mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Implement mask blur in display list dispatcher (flutter/engine#142)
This commit is contained in:
parent
bbe5ef72cb
commit
a6134bf6ba
@ -114,7 +114,7 @@ void Canvas::DrawPath(Path path, Paint paint) {
|
||||
entity.SetPath(std::move(path));
|
||||
entity.SetStencilDepth(GetStencilDepth());
|
||||
entity.SetBlendMode(paint.blend_mode);
|
||||
entity.SetContents(paint.CreateContentsForEntity());
|
||||
entity.SetContents(paint.WithFilters(paint.CreateContentsForEntity()));
|
||||
|
||||
GetCurrentPass().AddEntity(std::move(entity));
|
||||
}
|
||||
@ -242,7 +242,7 @@ void Canvas::DrawImageRect(std::shared_ptr<Image> image,
|
||||
entity.SetPath(PathBuilder{}.AddRect(dest).TakePath());
|
||||
entity.SetBlendMode(paint.blend_mode);
|
||||
entity.SetStencilDepth(GetStencilDepth());
|
||||
entity.SetContents(contents);
|
||||
entity.SetContents(paint.WithFilters(contents, false));
|
||||
entity.SetTransformation(GetCurrentTransformation());
|
||||
|
||||
GetCurrentPass().AddEntity(std::move(entity));
|
||||
@ -296,7 +296,7 @@ void Canvas::DrawTextFrame(TextFrame text_frame, Point position, Paint paint) {
|
||||
entity.SetPath({});
|
||||
entity.SetStencilDepth(GetStencilDepth());
|
||||
entity.SetBlendMode(paint.blend_mode);
|
||||
entity.SetContents(std::move(text_contents));
|
||||
entity.SetContents(paint.WithFilters(std::move(text_contents), true));
|
||||
|
||||
GetCurrentPass().AddEntity(std::move(entity));
|
||||
}
|
||||
|
||||
@ -33,4 +33,24 @@ std::shared_ptr<Contents> Paint::CreateContentsForEntity() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Contents> Paint::WithFilters(
|
||||
std::shared_ptr<Contents> input,
|
||||
std::optional<bool> is_solid_color) const {
|
||||
bool is_solid_color_val = is_solid_color.value_or(!contents);
|
||||
|
||||
if (mask_blur.has_value()) {
|
||||
if (is_solid_color_val) {
|
||||
input = FilterContents::MakeGaussianBlur(
|
||||
FilterInput::Make(input), mask_blur->sigma, mask_blur->sigma,
|
||||
mask_blur->blur_style);
|
||||
} else {
|
||||
input = FilterContents::MakeBorderMaskBlur(
|
||||
FilterInput::Make(input), mask_blur->sigma, mask_blur->sigma,
|
||||
mask_blur->blur_style);
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -8,12 +8,18 @@
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/entity/contents/contents.h"
|
||||
#include "impeller/entity/contents/filters/filter_contents.h"
|
||||
#include "impeller/entity/contents/solid_stroke_contents.h"
|
||||
#include "impeller/entity/entity.h"
|
||||
#include "impeller/geometry/color.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
struct MaskBlur {
|
||||
FilterContents::BlurStyle blur_style;
|
||||
FilterContents::Sigma sigma;
|
||||
};
|
||||
|
||||
struct Paint {
|
||||
enum class Style {
|
||||
kFill,
|
||||
@ -27,9 +33,25 @@ struct Paint {
|
||||
Scalar stroke_miter = 4.0;
|
||||
Style style = Style::kFill;
|
||||
Entity::BlendMode blend_mode = Entity::BlendMode::kSourceOver;
|
||||
std::optional<MaskBlur> mask_blur;
|
||||
std::shared_ptr<Contents> contents;
|
||||
|
||||
std::shared_ptr<Contents> CreateContentsForEntity() const;
|
||||
|
||||
/// @brief Wrap this paint's configured filters to the given contents.
|
||||
/// @param[in] input The contents to wrap with paint's filters.
|
||||
/// @param[in] is_solid_color Affects mask blurring behavior. If false, use
|
||||
/// the image border for mask blurring. If true,
|
||||
/// do a Gaussian blur to achieve the mask
|
||||
/// blurring effect for arbitrary paths. If unset,
|
||||
/// use the current paint configuration to infer
|
||||
/// the result.
|
||||
/// @return The filter-wrapped contents. If there are no filters that need
|
||||
/// to be wrapped for the current paint configuration, the
|
||||
/// original contents is returned.
|
||||
std::shared_ptr<Contents> WithFilters(
|
||||
std::shared_ptr<Contents> input,
|
||||
std::optional<bool> is_solid_color = std::nullopt) const;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <optional>
|
||||
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "impeller/entity/contents/filters/filter_contents.h"
|
||||
#include "impeller/entity/contents/linear_gradient_contents.h"
|
||||
#include "impeller/entity/contents/solid_stroke_contents.h"
|
||||
#include "impeller/entity/entity.h"
|
||||
@ -253,15 +254,33 @@ void DisplayListDispatcher::setPathEffect(sk_sp<SkPathEffect> effect) {
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
static FilterContents::BlurStyle ToBlurStyle(SkBlurStyle blur_style) {
|
||||
switch (blur_style) {
|
||||
case kNormal_SkBlurStyle:
|
||||
return FilterContents::BlurStyle::kNormal;
|
||||
case kSolid_SkBlurStyle:
|
||||
return FilterContents::BlurStyle::kSolid;
|
||||
case kOuter_SkBlurStyle:
|
||||
return FilterContents::BlurStyle::kOuter;
|
||||
case kInner_SkBlurStyle:
|
||||
return FilterContents::BlurStyle::kInner;
|
||||
}
|
||||
}
|
||||
|
||||
// |flutter::Dispatcher|
|
||||
void DisplayListDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) {
|
||||
// Needs https://github.com/flutter/flutter/issues/95434
|
||||
if (filter == nullptr) {
|
||||
// Reset everything
|
||||
paint_.mask_blur = std::nullopt;
|
||||
return;
|
||||
}
|
||||
switch (filter->type()) {
|
||||
case flutter::DlMaskFilterType::kBlur:
|
||||
case flutter::DlMaskFilterType::kBlur: {
|
||||
auto blur = filter->asBlur();
|
||||
paint_.mask_blur = {.blur_style = ToBlurStyle(blur->style()),
|
||||
.sigma = FilterContents::Sigma(blur->sigma())};
|
||||
break;
|
||||
}
|
||||
case flutter::DlMaskFilterType::kUnknown:
|
||||
UNIMPLEMENTED;
|
||||
break;
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include "third_party/skia/include/core/SkPathBuilder.h"
|
||||
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/display_list_mask_filter.h"
|
||||
#include "flutter/display_list/types.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "impeller/display_list/display_list_image_impeller.h"
|
||||
#include "impeller/display_list/display_list_playground.h"
|
||||
@ -174,5 +176,36 @@ TEST_P(DisplayListTest, StrokedPathsDrawCorrectly) {
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, CanDrawWithMaskBlur) {
|
||||
auto texture = CreateTextureForFixture("embarcadero.jpg");
|
||||
flutter::DisplayListBuilder builder;
|
||||
|
||||
// Mask blurred image.
|
||||
{
|
||||
auto filter = flutter::DlBlurMaskFilter(kNormal_SkBlurStyle, 10.0f);
|
||||
builder.setMaskFilter(&filter);
|
||||
builder.drawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
|
||||
SkSamplingOptions{}, true);
|
||||
}
|
||||
|
||||
// Mask blurred filled path.
|
||||
{
|
||||
builder.setColor(SK_ColorYELLOW);
|
||||
auto filter = flutter::DlBlurMaskFilter(kOuter_SkBlurStyle, 10.0f);
|
||||
builder.setMaskFilter(&filter);
|
||||
builder.drawArc(SkRect::MakeXYWH(410, 110, 100, 100), 45, 270, true);
|
||||
}
|
||||
|
||||
// Mask blurred text.
|
||||
{
|
||||
auto filter = flutter::DlBlurMaskFilter(kSolid_SkBlurStyle, 10.0f);
|
||||
builder.setMaskFilter(&filter);
|
||||
builder.drawTextBlob(
|
||||
SkTextBlob::MakeFromString("Testing", CreateTestFont()), 220, 170);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
|
||||
@ -47,7 +47,7 @@ std::optional<Snapshot> Contents::RenderToSnapshot(
|
||||
RenderPass& pass) -> bool {
|
||||
Entity sub_entity;
|
||||
sub_entity.SetPath(entity.GetPath());
|
||||
sub_entity.SetBlendMode(Entity::BlendMode::kSource);
|
||||
sub_entity.SetBlendMode(Entity::BlendMode::kSourceOver);
|
||||
sub_entity.SetTransformation(
|
||||
Matrix::MakeTranslation(Vector3(-bounds->origin)) *
|
||||
entity.GetTransformation());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user