diff --git a/impeller/display_list/canvas.cc b/impeller/display_list/canvas.cc index 9c45f8d6dce84..d14db69dc0d69 100644 --- a/impeller/display_list/canvas.cc +++ b/impeller/display_list/canvas.cc @@ -25,7 +25,16 @@ #include "impeller/entity/contents/text_contents.h" #include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/contents/vertices_contents.h" +#include "impeller/entity/geometry/circle_geometry.h" +#include "impeller/entity/geometry/cover_geometry.h" +#include "impeller/entity/geometry/ellipse_geometry.h" +#include "impeller/entity/geometry/fill_path_geometry.h" #include "impeller/entity/geometry/geometry.h" +#include "impeller/entity/geometry/line_geometry.h" +#include "impeller/entity/geometry/point_field_geometry.h" +#include "impeller/entity/geometry/rect_geometry.h" +#include "impeller/entity/geometry/round_rect_geometry.h" +#include "impeller/entity/geometry/stroke_path_geometry.h" #include "impeller/entity/save_layer_utils.h" #include "impeller/geometry/color.h" #include "impeller/geometry/constants.h" @@ -35,90 +44,20 @@ namespace impeller { namespace { -static std::shared_ptr CreateContentsForGeometryWithFilters( - const Paint& paint, - std::shared_ptr geometry) { - std::shared_ptr contents = paint.CreateContents(); - - // Attempt to apply the color filter on the CPU first. - // Note: This is not just an optimization; some color sources rely on - // CPU-applied color filters to behave properly. - bool needs_color_filter = paint.color_filter || paint.invert_colors; - if (needs_color_filter && - contents->ApplyColorFilter([&](Color color) -> Color { - if (paint.color_filter) { - color = GetCPUColorFilterProc(paint.color_filter)(color); - } - if (paint.invert_colors) { - color = color.ApplyColorMatrix(kColorInversion); - } - return color; - })) { - needs_color_filter = false; - } - - bool can_apply_mask_filter = geometry->CanApplyMaskFilter(); - contents->SetGeometry(std::move(geometry)); - - if (can_apply_mask_filter && paint.mask_blur_descriptor.has_value()) { - // If there's a mask blur and we need to apply the color filter on the GPU, - // we need to be careful to only apply the color filter to the source - // colors. CreateMaskBlur is able to handle this case. - return paint.mask_blur_descriptor->CreateMaskBlur( - contents, needs_color_filter ? paint.color_filter : nullptr, - needs_color_filter ? paint.invert_colors : false); +static bool UseColorSourceContents( + const std::shared_ptr& vertices, + const Paint& paint) { + // If there are no vertex color or texture coordinates. Or if there + // are vertex coordinates but its just a color. + if (vertices->HasVertexColors()) { + return false; } - - std::shared_ptr contents_copy = std::move(contents); - - // Image input types will directly set their color filter, - // if any. See `TiledTextureContents.SetColorFilter`. - if (needs_color_filter && + if (vertices->HasTextureCoordinates() && (!paint.color_source || - paint.color_source->type() != flutter::DlColorSourceType::kImage)) { - if (paint.color_filter) { - contents_copy = WrapWithGPUColorFilter( - paint.color_filter, FilterInput::Make(std::move(contents_copy)), - ColorFilterContents::AbsorbOpacity::kYes); - } - if (paint.invert_colors) { - contents_copy = - WrapWithInvertColors(FilterInput::Make(contents_copy), - ColorFilterContents::AbsorbOpacity::kYes); - } - } - - if (paint.image_filter) { - std::shared_ptr filter = WrapInput( - paint.image_filter, FilterInput::Make(std::move(contents_copy))); - filter->SetRenderingMode(Entity::RenderingMode::kDirect); - return filter; - } - - return contents_copy; -} - -static std::shared_ptr CreatePathContentsWithFilters( - const Paint& paint, - const Path& path) { - std::shared_ptr geometry; - switch (paint.style) { - case Paint::Style::kFill: - geometry = Geometry::MakeFillPath(path); - break; - case Paint::Style::kStroke: - geometry = - Geometry::MakeStrokePath(path, paint.stroke_width, paint.stroke_miter, - paint.stroke_cap, paint.stroke_join); - break; + paint.color_source->type() == flutter::DlColorSourceType::kColor)) { + return true; } - - return CreateContentsForGeometryWithFilters(paint, std::move(geometry)); -} - -static std::shared_ptr CreateCoverContentsWithFilters( - const Paint& paint) { - return CreateContentsForGeometryWithFilters(paint, Geometry::MakeCover()); + return !vertices->HasTextureCoordinates(); } static void SetClipScissor(std::optional clip_coverage, @@ -448,18 +387,24 @@ void Canvas::DrawPath(const Path& path, const Paint& paint) { Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - entity.SetContents(CreatePathContentsWithFilters(paint, path)); - AddRenderEntityToCurrentPass(entity); + if (paint.style == Paint::Style::kFill) { + FillPathGeometry geom(path); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); + } else { + StrokePathGeometry geom(path, paint.stroke_width, paint.stroke_miter, + paint.stroke_cap, paint.stroke_join); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); + } } void Canvas::DrawPaint(const Paint& paint) { Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - entity.SetContents(CreateCoverContentsWithFilters(paint)); - AddRenderEntityToCurrentPass(entity); + CoverGeometry geom; + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); } bool Canvas::AttemptDrawBlurredRRect(const Rect& rect, @@ -573,18 +518,21 @@ bool Canvas::AttemptDrawBlurredRRect(const Rect& rect, Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(rrect_paint.blend_mode); - entity.SetContents(CreateContentsForGeometryWithFilters( - rrect_paint, Geometry::MakeRoundRect(rect, corner_radii))); - AddRenderEntityToCurrentPass(entity, true); + + RoundRectGeometry geom(rect, corner_radii); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, rrect_paint, + /*reuse_depth=*/true); break; } case FilterContents::BlurStyle::kOuter: { - ClipRRect(rect, corner_radii, Entity::ClipOperation::kDifference); + ClipGeometry(Geometry::MakeRoundRect(rect, corner_radii), + Entity::ClipOperation::kDifference); draw_blurred_rrect(); break; } case FilterContents::BlurStyle::kInner: { - ClipRRect(rect, corner_radii, Entity::ClipOperation::kIntersect); + ClipGeometry(Geometry::MakeRoundRect(rect, corner_radii), + Entity::ClipOperation::kIntersect); draw_blurred_rrect(); break; } @@ -599,10 +547,9 @@ void Canvas::DrawLine(const Point& p0, const Point& p1, const Paint& paint) { Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - entity.SetContents(CreateContentsForGeometryWithFilters( - paint, Geometry::MakeLine(p0, p1, paint.stroke_width, paint.stroke_cap))); - AddRenderEntityToCurrentPass(entity); + LineGeometry geom(p0, p1, paint.stroke_width, paint.stroke_cap); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); } void Canvas::DrawRect(const Rect& rect, const Paint& paint) { @@ -618,10 +565,9 @@ void Canvas::DrawRect(const Rect& rect, const Paint& paint) { Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - entity.SetContents( - CreateContentsForGeometryWithFilters(paint, Geometry::MakeRect(rect))); - AddRenderEntityToCurrentPass(entity); + RectGeometry geom(rect); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); } void Canvas::DrawOval(const Rect& rect, const Paint& paint) { @@ -649,10 +595,9 @@ void Canvas::DrawOval(const Rect& rect, const Paint& paint) { Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - entity.SetContents( - CreateContentsForGeometryWithFilters(paint, Geometry::MakeOval(rect))); - AddRenderEntityToCurrentPass(entity); + EllipseGeometry geom(rect); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); } void Canvas::DrawRRect(const Rect& rect, @@ -666,10 +611,9 @@ void Canvas::DrawRRect(const Rect& rect, Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - entity.SetContents(CreateContentsForGeometryWithFilters( - paint, Geometry::MakeRoundRect(rect, corner_radii))); - AddRenderEntityToCurrentPass(entity); + RoundRectGeometry geom(rect, corner_radii); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); return; } @@ -694,41 +638,22 @@ void Canvas::DrawCircle(const Point& center, Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - auto geometry = - paint.style == Paint::Style::kStroke - ? Geometry::MakeStrokedCircle(center, radius, paint.stroke_width) - : Geometry::MakeCircle(center, radius); - entity.SetContents( - CreateContentsForGeometryWithFilters(paint, std::move(geometry))); - - AddRenderEntityToCurrentPass(entity); -} - -void Canvas::ClipPath(const Path& path, Entity::ClipOperation clip_op) { - ClipGeometry(Geometry::MakeFillPath(path), clip_op); -} -void Canvas::ClipRect(const Rect& rect, Entity::ClipOperation clip_op) { - auto geometry = Geometry::MakeRect(rect); - ClipGeometry(geometry, clip_op); -} - -void Canvas::ClipOval(const Rect& bounds, Entity::ClipOperation clip_op) { - auto geometry = Geometry::MakeOval(bounds); - ClipGeometry(geometry, clip_op); -} - -void Canvas::ClipRRect(const Rect& rect, - const Size& corner_radii, - Entity::ClipOperation clip_op) { - auto geometry = Geometry::MakeRoundRect(rect, corner_radii); - ClipGeometry(geometry, clip_op); + if (paint.style == Paint::Style::kStroke) { + CircleGeometry geom(center, radius, paint.stroke_width); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); + } else { + CircleGeometry geom(center, radius); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); + } } -void Canvas::ClipGeometry(const std::shared_ptr& geometry, +void Canvas::ClipGeometry(std::unique_ptr geometry, Entity::ClipOperation clip_op) { + clip_geometry_.push_back(std::move(geometry)); + auto contents = std::make_shared(); - contents->SetGeometry(geometry); + contents->SetGeometry(clip_geometry_.back().get()); contents->SetClipOperation(clip_op); Entity entity; @@ -764,12 +689,10 @@ void Canvas::DrawPoints(std::vector points, Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - entity.SetContents(CreateContentsForGeometryWithFilters( - paint, - Geometry::MakePointField(std::move(points), radius, - /*round=*/point_style == PointStyle::kRound))); - AddRenderEntityToCurrentPass(entity); + PointFieldGeometry geom(std::move(points), radius, + /*round=*/point_style == PointStyle::kRound); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); } void Canvas::DrawImage(const std::shared_ptr& image, @@ -811,16 +734,20 @@ void Canvas::DrawImageRect(const std::shared_ptr& image, texture_contents->SetOpacity(paint.color.alpha); texture_contents->SetDeferApplyingOpacity(paint.HasColorFilter()); - std::shared_ptr contents = texture_contents; - if (paint.mask_blur_descriptor.has_value()) { - contents = paint.mask_blur_descriptor->CreateMaskBlur(texture_contents); - } - Entity entity; entity.SetBlendMode(paint.blend_mode); - entity.SetContents(paint.WithFilters(contents)); entity.SetTransform(GetCurrentTransform()); + if (!paint.mask_blur_descriptor.has_value()) { + entity.SetContents(paint.WithFilters(std::move(texture_contents))); + AddRenderEntityToCurrentPass(entity); + return; + } + + RectGeometry out_rect(Rect{}); + + entity.SetContents(paint.WithFilters( + paint.mask_blur_descriptor->CreateMaskBlur(texture_contents, &out_rect))); AddRenderEntityToCurrentPass(entity); } @@ -828,22 +755,6 @@ size_t Canvas::GetClipHeight() const { return transform_stack_.back().clip_height; } -static bool UseColorSourceContents( - const std::shared_ptr& vertices, - const Paint& paint) { - // If there are no vertex color or texture coordinates. Or if there - // are vertex coordinates but its just a color. - if (vertices->HasVertexColors()) { - return false; - } - if (vertices->HasTextureCoordinates() && - (!paint.color_source || - paint.color_source->type() == flutter::DlColorSourceType::kColor)) { - return true; - } - return !vertices->HasTextureCoordinates(); -} - void Canvas::DrawVertices(const std::shared_ptr& vertices, BlendMode blend_mode, const Paint& paint) { @@ -861,8 +772,7 @@ void Canvas::DrawVertices(const std::shared_ptr& vertices, // If there are no vertex colors. if (UseColorSourceContents(vertices, paint)) { - entity.SetContents(CreateContentsForGeometryWithFilters(paint, vertices)); - AddRenderEntityToCurrentPass(entity); + AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint); return; } @@ -913,7 +823,7 @@ void Canvas::DrawVertices(const std::shared_ptr& vertices, std::shared_ptr src_contents = src_paint.CreateContents(); - src_contents->SetGeometry(vertices); + src_contents->SetGeometry(vertices.get()); // If the color source has an intrinsic size, then we use that to // create the src contents as a simplification. Otherwise we use @@ -933,7 +843,9 @@ void Canvas::DrawVertices(const std::shared_ptr& vertices, vertices->GetTextureCoordinateCoverge().value_or(cvg.value()); } src_contents = src_paint.CreateContents(); - src_contents->SetGeometry(Geometry::MakeRect(Rect::Round(src_coverage))); + + clip_geometry_.push_back(Geometry::MakeRect(Rect::Round(src_coverage))); + src_contents->SetGeometry(clip_geometry_.back().get()); auto contents = std::make_shared(); contents->SetBlendMode(blend_mode); @@ -1430,6 +1342,84 @@ void Canvas::DrawTextFrame(const std::shared_ptr& text_frame, AddRenderEntityToCurrentPass(entity, false); } +void Canvas::AddRenderEntityWithFiltersToCurrentPass(Entity& entity, + const Geometry* geometry, + const Paint& paint, + bool reuse_depth) { + std::shared_ptr contents = paint.CreateContents(); + if (!paint.color_filter && !paint.invert_colors && !paint.image_filter && + !paint.mask_blur_descriptor.has_value()) { + contents->SetGeometry(geometry); + entity.SetContents(std::move(contents)); + AddRenderEntityToCurrentPass(entity, reuse_depth); + return; + } + + // Attempt to apply the color filter on the CPU first. + // Note: This is not just an optimization; some color sources rely on + // CPU-applied color filters to behave properly. + bool needs_color_filter = paint.color_filter || paint.invert_colors; + if (needs_color_filter && + contents->ApplyColorFilter([&](Color color) -> Color { + if (paint.color_filter) { + color = GetCPUColorFilterProc(paint.color_filter)(color); + } + if (paint.invert_colors) { + color = color.ApplyColorMatrix(kColorInversion); + } + return color; + })) { + needs_color_filter = false; + } + + bool can_apply_mask_filter = geometry->CanApplyMaskFilter(); + contents->SetGeometry(geometry); + + if (can_apply_mask_filter && paint.mask_blur_descriptor.has_value()) { + // If there's a mask blur and we need to apply the color filter on the GPU, + // we need to be careful to only apply the color filter to the source + // colors. CreateMaskBlur is able to handle this case. + RectGeometry out_rect(Rect{}); + auto filter_contents = paint.mask_blur_descriptor->CreateMaskBlur( + contents, needs_color_filter ? paint.color_filter : nullptr, + needs_color_filter ? paint.invert_colors : false, &out_rect); + entity.SetContents(std::move(filter_contents)); + AddRenderEntityToCurrentPass(entity, reuse_depth); + return; + } + + std::shared_ptr contents_copy = std::move(contents); + + // Image input types will directly set their color filter, + // if any. See `TiledTextureContents.SetColorFilter`. + if (needs_color_filter && + (!paint.color_source || + paint.color_source->type() != flutter::DlColorSourceType::kImage)) { + if (paint.color_filter) { + contents_copy = WrapWithGPUColorFilter( + paint.color_filter, FilterInput::Make(std::move(contents_copy)), + ColorFilterContents::AbsorbOpacity::kYes); + } + if (paint.invert_colors) { + contents_copy = + WrapWithInvertColors(FilterInput::Make(std::move(contents_copy)), + ColorFilterContents::AbsorbOpacity::kYes); + } + } + + if (paint.image_filter) { + std::shared_ptr filter = WrapInput( + paint.image_filter, FilterInput::Make(std::move(contents_copy))); + filter->SetRenderingMode(Entity::RenderingMode::kDirect); + entity.SetContents(filter); + AddRenderEntityToCurrentPass(entity, reuse_depth); + return; + } + + entity.SetContents(std::move(contents_copy)); + AddRenderEntityToCurrentPass(entity, reuse_depth); +} + void Canvas::AddRenderEntityToCurrentPass(Entity& entity, bool reuse_depth) { if (IsSkipping()) { return; @@ -1660,6 +1650,7 @@ void Canvas::EndReplay() { render_passes_.clear(); renderer_.GetRenderTargetCache()->End(); + clip_geometry_.clear(); Reset(); Initialize(initial_cull_rect_); diff --git a/impeller/display_list/canvas.h b/impeller/display_list/canvas.h index e1cc8e2afda4c..387cb5c81dc33 100644 --- a/impeller/display_list/canvas.h +++ b/impeller/display_list/canvas.h @@ -197,23 +197,6 @@ class Canvas { SamplerDescriptor sampler = {}, SourceRectConstraint src_rect_constraint = SourceRectConstraint::kFast); - void ClipPath( - const Path& path, - Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect); - - void ClipRect( - const Rect& rect, - Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect); - - void ClipOval( - const Rect& bounds, - Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect); - - void ClipRRect( - const Rect& rect, - const Size& corner_radii, - Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect); - void DrawTextFrame(const std::shared_ptr& text_frame, Point position, const Paint& paint); @@ -225,6 +208,9 @@ class Canvas { void DrawAtlas(const std::shared_ptr& atlas_contents, const Paint& paint); + void ClipGeometry(std::unique_ptr geometry, + Entity::ClipOperation clip_op); + void EndReplay(); uint64_t GetOpDepth() const { return current_depth_; } @@ -247,6 +233,11 @@ class Canvas { std::vector render_passes_; std::vector save_layer_state_; + // All geometry objects created for regular draws can be stack allocated, + // but clip geometries must be cached for record/replay for backdrop filters + // and so must be kept alive longer. + std::vector> clip_geometry_; + uint64_t current_depth_ = 0u; Point GetGlobalPassPosition() const; @@ -271,13 +262,15 @@ class Canvas { void Reset(); + void AddRenderEntityWithFiltersToCurrentPass(Entity& entity, + const Geometry* geometry, + const Paint& paint, + bool reuse_depth = false); + void AddRenderEntityToCurrentPass(Entity& entity, bool reuse_depth = false); void AddClipEntityToCurrentPass(Entity& entity); - void ClipGeometry(const std::shared_ptr& geometry, - Entity::ClipOperation clip_op); - void RestoreClip(); bool AttemptDrawBlurredRRect(const Rect& rect, diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 6a06ce5ff5b34..ffdd0c6eca9f8 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -25,6 +25,7 @@ #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/entity/entity.h" +#include "impeller/entity/geometry/geometry.h" #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" #include "impeller/geometry/path_builder.h" @@ -430,7 +431,7 @@ void DlDispatcherBase::clipRect(const DlRect& rect, bool is_aa) { AUTO_DEPTH_WATCHER(0u); - GetCanvas().ClipRect(rect, ToClipOperation(clip_op)); + GetCanvas().ClipGeometry(Geometry::MakeRect(rect), ToClipOperation(clip_op)); } // |flutter::DlOpReceiver| @@ -439,7 +440,8 @@ void DlDispatcherBase::clipOval(const DlRect& bounds, bool is_aa) { AUTO_DEPTH_WATCHER(0u); - GetCanvas().ClipOval(bounds, ToClipOperation(clip_op)); + GetCanvas().ClipGeometry(Geometry::MakeOval(bounds), + ToClipOperation(clip_op)); } // |flutter::DlOpReceiver| @@ -450,15 +452,20 @@ void DlDispatcherBase::clipRRect(const SkRRect& rrect, auto clip_op = ToClipOperation(sk_op); if (rrect.isRect()) { - GetCanvas().ClipRect(skia_conversions::ToRect(rrect.rect()), clip_op); + GetCanvas().ClipGeometry( + Geometry::MakeRect(skia_conversions::ToRect(rrect.rect())), clip_op); } else if (rrect.isOval()) { - GetCanvas().ClipOval(skia_conversions::ToRect(rrect.rect()), clip_op); + GetCanvas().ClipGeometry( + Geometry::MakeOval(skia_conversions::ToRect(rrect.rect())), clip_op); } else if (rrect.isSimple()) { - GetCanvas().ClipRRect(skia_conversions::ToRect(rrect.rect()), - skia_conversions::ToSize(rrect.getSimpleRadii()), - clip_op); + GetCanvas().ClipGeometry( + Geometry::MakeRoundRect( + skia_conversions::ToRect(rrect.rect()), + skia_conversions::ToSize(rrect.getSimpleRadii())), + clip_op); } else { - GetCanvas().ClipPath(skia_conversions::ToPath(rrect), clip_op); + GetCanvas().ClipGeometry( + Geometry::MakeFillPath(skia_conversions::ToPath(rrect)), clip_op); } } @@ -470,17 +477,19 @@ void DlDispatcherBase::clipPath(const DlPath& path, ClipOp sk_op, bool is_aa) { DlRect rect; if (path.IsRect(&rect)) { - GetCanvas().ClipRect(rect, clip_op); + GetCanvas().ClipGeometry(Geometry::MakeRect(rect), clip_op); } else if (path.IsOval(&rect)) { - GetCanvas().ClipOval(rect, clip_op); + GetCanvas().ClipGeometry(Geometry::MakeOval(rect), clip_op); } else { SkRRect rrect; if (path.IsSkRRect(&rrect) && rrect.isSimple()) { - GetCanvas().ClipRRect(skia_conversions::ToRect(rrect.rect()), - skia_conversions::ToSize(rrect.getSimpleRadii()), - clip_op); + GetCanvas().ClipGeometry( + Geometry::MakeRoundRect( + skia_conversions::ToRect(rrect.rect()), + skia_conversions::ToSize(rrect.getSimpleRadii())), + clip_op); } else { - GetCanvas().ClipPath(path.GetPath(), clip_op); + GetCanvas().ClipGeometry(Geometry::MakeFillPath(path.GetPath()), clip_op); } } } diff --git a/impeller/display_list/paint.cc b/impeller/display_list/paint.cc index 59105b462ce2d..13bd681fe30fb 100644 --- a/impeller/display_list/paint.cc +++ b/impeller/display_list/paint.cc @@ -24,6 +24,7 @@ #include "impeller/entity/contents/sweep_gradient_contents.h" #include "impeller/entity/contents/tiled_texture_contents.h" #include "impeller/entity/geometry/geometry.h" +#include "impeller/entity/geometry/rect_geometry.h" namespace impeller { @@ -340,7 +341,8 @@ std::shared_ptr Paint::WithColorFilter( } std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( - std::shared_ptr texture_contents) const { + std::shared_ptr texture_contents, + RectGeometry* rect_geom) const { Scalar expand_amount = GaussianBlurFilterContents::CalculateBlurRadius( GaussianBlurFilterContents::ScaleSigma(sigma.sigma)); texture_contents->SetSourceRect( @@ -348,11 +350,12 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( auto mask = std::make_shared(); mask->SetColor(Color::White()); std::optional coverage = texture_contents->GetCoverage({}); - std::shared_ptr geometry; + Geometry* geometry = nullptr; if (coverage) { texture_contents->SetDestinationRect( coverage.value().Expand(expand_amount, expand_amount)); - geometry = Geometry::MakeRect(coverage.value()); + *rect_geom = RectGeometry(coverage.value()); + geometry = rect_geom; } mask->SetGeometry(geometry); auto descriptor = texture_contents->GetSamplerDescriptor(); @@ -370,7 +373,8 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( std::shared_ptr color_source_contents, const flutter::DlColorFilter* color_filter, - bool invert_colors) const { + bool invert_colors, + RectGeometry* rect_geom) const { // If it's a solid color then we can just get away with doing one Gaussian // blur. The color filter will always be applied on the CPU. if (color_source_contents->IsSolidColor()) { @@ -399,8 +403,8 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( if (!expanded_local_bounds.has_value()) { expanded_local_bounds = Rect(); } - color_source_contents->SetGeometry( - Geometry::MakeRect(*expanded_local_bounds)); + *rect_geom = RectGeometry(expanded_local_bounds.value()); + color_source_contents->SetGeometry(rect_geom); std::shared_ptr color_contents = color_source_contents; /// 4. Apply the user set color filter on the GPU, if applicable. diff --git a/impeller/display_list/paint.h b/impeller/display_list/paint.h index 620b5126a15f8..830b72673bac7 100644 --- a/impeller/display_list/paint.h +++ b/impeller/display_list/paint.h @@ -58,10 +58,12 @@ struct Paint { std::shared_ptr CreateMaskBlur( std::shared_ptr color_source_contents, const flutter::DlColorFilter* color_filter, - bool invert_colors) const; + bool invert_colors, + RectGeometry* rect_geom) const; std::shared_ptr CreateMaskBlur( - std::shared_ptr texture_contents) const; + std::shared_ptr texture_contents, + RectGeometry* rect_geom) const; std::shared_ptr CreateMaskBlur( const FilterInput::Ref& input, diff --git a/impeller/entity/contents/clip_contents.cc b/impeller/entity/contents/clip_contents.cc index 1eb51b8ee299c..ee4535ed7084e 100644 --- a/impeller/entity/contents/clip_contents.cc +++ b/impeller/entity/contents/clip_contents.cc @@ -32,7 +32,7 @@ ClipContents::ClipContents() = default; ClipContents::~ClipContents() = default; -void ClipContents::SetGeometry(const std::shared_ptr& geometry) { +void ClipContents::SetGeometry(const Geometry* geometry) { geometry_ = geometry; } diff --git a/impeller/entity/contents/clip_contents.h b/impeller/entity/contents/clip_contents.h index eae784ab251c5..51e76644f4ec9 100644 --- a/impeller/entity/contents/clip_contents.h +++ b/impeller/entity/contents/clip_contents.h @@ -5,10 +5,6 @@ #ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_CLIP_CONTENTS_H_ #define FLUTTER_IMPELLER_ENTITY_CONTENTS_CLIP_CONTENTS_H_ -#include -#include -#include - #include "impeller/entity/contents/contents.h" #include "impeller/entity/entity.h" #include "impeller/entity/geometry/geometry.h" @@ -21,7 +17,7 @@ class ClipContents final : public Contents { ~ClipContents(); - void SetGeometry(const std::shared_ptr& geometry); + void SetGeometry(const Geometry* geometry); void SetClipOperation(Entity::ClipOperation clip_op); @@ -42,7 +38,7 @@ class ClipContents final : public Contents { void SetInheritedOpacity(Scalar opacity) override; private: - std::shared_ptr geometry_; + const Geometry* geometry_ = nullptr; Entity::ClipOperation clip_op_ = Entity::ClipOperation::kIntersect; ClipContents(const ClipContents&) = delete; diff --git a/impeller/entity/contents/clip_contents_unittests.cc b/impeller/entity/contents/clip_contents_unittests.cc index f9c23cb6db26c..21070a0bc5bb5 100644 --- a/impeller/entity/contents/clip_contents_unittests.cc +++ b/impeller/entity/contents/clip_contents_unittests.cc @@ -37,7 +37,8 @@ TEST_P(EntityTest, ClipContentsOptimizesFullScreenIntersectClips) { auto contents = std::make_shared(); contents->SetClipOperation(Entity::ClipOperation::kIntersect); - contents->SetGeometry(Geometry::MakeCover()); + auto geom = Geometry::MakeCover(); + contents->SetGeometry(geom.get()); Entity entity; entity.SetContents(std::move(contents)); diff --git a/impeller/entity/contents/color_source_contents.cc b/impeller/entity/contents/color_source_contents.cc index 009f3146076be..8d42add0a9206 100644 --- a/impeller/entity/contents/color_source_contents.cc +++ b/impeller/entity/contents/color_source_contents.cc @@ -13,11 +13,11 @@ ColorSourceContents::ColorSourceContents() = default; ColorSourceContents::~ColorSourceContents() = default; -void ColorSourceContents::SetGeometry(std::shared_ptr geometry) { - geometry_ = std::move(geometry); +void ColorSourceContents::SetGeometry(const Geometry* geometry) { + geometry_ = geometry; } -const std::shared_ptr& ColorSourceContents::GetGeometry() const { +const Geometry* ColorSourceContents::GetGeometry() const { return geometry_; } diff --git a/impeller/entity/contents/color_source_contents.h b/impeller/entity/contents/color_source_contents.h index 1bade2c369b48..52985493f78aa 100644 --- a/impeller/entity/contents/color_source_contents.h +++ b/impeller/entity/contents/color_source_contents.h @@ -43,12 +43,12 @@ class ColorSourceContents : public Contents { //---------------------------------------------------------------------------- /// @brief Set the geometry that this contents will use to render. /// - void SetGeometry(std::shared_ptr geometry); + void SetGeometry(const Geometry* geometry); //---------------------------------------------------------------------------- /// @brief Get the geometry that this contents will use to render. /// - const std::shared_ptr& GetGeometry() const; + const Geometry* GetGeometry() const; //---------------------------------------------------------------------------- /// @brief Set the effect transform for this color source. @@ -110,14 +110,14 @@ class ColorSourceContents : public Contents { std::function; + const Geometry* geom)>; static GeometryResult DefaultCreateGeometryCallback( const ContentContext& renderer, const Entity& entity, RenderPass& pass, - const Geometry& geom) { - return geom.GetPositionBuffer(renderer, entity, pass); + const Geometry* geom) { + return geom->GetPositionBuffer(renderer, entity, pass); } /// @brief Whether the entity should be treated as non-opaque due to stroke @@ -137,7 +137,8 @@ class ColorSourceContents : public Contents { auto options = OptionsFromPassAndEntity(pass, entity); GeometryResult::Mode geometry_mode = GetGeometry()->GetResultMode(); - Geometry& geometry = *GetGeometry(); + bool do_cover_draw = false; + Rect cover_area = {}; bool is_stencil_then_cover = geometry_mode == GeometryResult::Mode::kNonZero || @@ -200,11 +201,19 @@ class ColorSourceContents : public Contents { if (!maybe_cover_area.has_value()) { return true; } - geometry = RectGeometry(maybe_cover_area.value()); + do_cover_draw = true; + cover_area = maybe_cover_area.value(); + } + + GeometryResult geometry_result; + if (do_cover_draw) { + RectGeometry geom(cover_area); + geometry_result = create_geom_callback(renderer, entity, pass, &geom); + } else { + geometry_result = + create_geom_callback(renderer, entity, pass, GetGeometry()); } - GeometryResult geometry_result = - create_geom_callback(renderer, entity, pass, geometry); if (geometry_result.vertex_buffer.vertex_count == 0u) { return true; } @@ -260,7 +269,7 @@ class ColorSourceContents : public Contents { } private: - std::shared_ptr geometry_; + const Geometry* geometry_ = nullptr; Matrix inverse_matrix_; Scalar opacity_ = 1.0; Scalar inherited_opacity_ = 1.0; diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 49c7d6b14cd24..08b7b0744f35d 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -21,6 +21,7 @@ #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/entity/contents/solid_color_contents.h" #include "impeller/entity/entity.h" +#include "impeller/entity/geometry/rect_geometry.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" #include "impeller/geometry/color.h" @@ -626,8 +627,8 @@ static std::optional PipelineBlend( if (foreground_color.has_value()) { auto contents = std::make_shared(); - contents->SetGeometry( - Geometry::MakeRect(Rect::MakeSize(pass.GetRenderTargetSize()))); + RectGeometry geom(Rect::MakeSize(pass.GetRenderTargetSize())); + contents->SetGeometry(&geom); contents->SetColor(foreground_color.value()); Entity foreground_entity; diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 36af904dd14b9..85bcabadc199c 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -39,7 +39,7 @@ std::shared_ptr FilterContents::MakeGaussianBlur( Sigma sigma_y, Entity::TileMode tile_mode, FilterContents::BlurStyle mask_blur_style, - const std::shared_ptr& mask_geometry) { + const Geometry* mask_geometry) { auto blur = std::make_shared( sigma_x.sigma, sigma_y.sigma, tile_mode, mask_blur_style, mask_geometry); blur->SetInputs({input}); diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 6ffdf13e2a661..3c355bb2494b4 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -44,7 +44,7 @@ class FilterContents : public Contents { Sigma sigma_y, Entity::TileMode tile_mode = Entity::TileMode::kDecal, BlurStyle mask_blur_style = BlurStyle::kNormal, - const std::shared_ptr& mask_geometry = nullptr); + const Geometry* mask_geometry = nullptr); static std::shared_ptr MakeBorderMaskBlur( FilterInput::Ref input, diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 4c7af0b485f59..efdd24254f07e 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -505,7 +505,7 @@ Entity ApplyClippedBlurStyle(Entity::ClipOperation clip_operation, const std::shared_ptr& input, const Snapshot& input_snapshot, Entity blur_entity, - const std::shared_ptr& geometry) { + const Geometry* geometry) { auto clip_contents = std::make_shared(); clip_contents->SetClipOperation(clip_operation); clip_contents->SetGeometry(geometry); @@ -544,7 +544,7 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style, const std::shared_ptr& input, const Snapshot& input_snapshot, Entity blur_entity, - const std::shared_ptr& geometry, + const Geometry* geometry, Vector2 source_space_scalar) { switch (blur_style) { case FilterContents::BlurStyle::kNormal: @@ -599,7 +599,7 @@ GaussianBlurFilterContents::GaussianBlurFilterContents( Scalar sigma_y, Entity::TileMode tile_mode, BlurStyle mask_blur_style, - const std::shared_ptr& mask_geometry) + const Geometry* mask_geometry) : sigma_(sigma_x, sigma_y), tile_mode_(tile_mode), mask_blur_style_(mask_blur_style), diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index b24c87f0205d6..1cc43cfaf5c5a 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -55,12 +55,11 @@ GaussianBlurPipeline::FragmentShader::KernelSamples LerpHackKernelSamples( /// Note: This will replace `DirectionalGaussianBlurFilterContents`. class GaussianBlurFilterContents final : public FilterContents { public: - explicit GaussianBlurFilterContents( - Scalar sigma_x, - Scalar sigma_y, - Entity::TileMode tile_mode, - BlurStyle mask_blur_style, - const std::shared_ptr& mask_geometry); + explicit GaussianBlurFilterContents(Scalar sigma_x, + Scalar sigma_y, + Entity::TileMode tile_mode, + BlurStyle mask_blur_style, + const Geometry* mask_geometry = nullptr); Scalar GetSigmaX() const { return sigma_.x; } Scalar GetSigmaY() const { return sigma_.y; } @@ -117,7 +116,7 @@ class GaussianBlurFilterContents final : public FilterContents { const Vector2 sigma_ = Vector2(0.0, 0.0); const Entity::TileMode tile_mode_; const BlurStyle mask_blur_style_; - std::shared_ptr mask_geometry_; + const Geometry* mask_geometry_ = nullptr; }; } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 28ea871b61830..73d533f2d7dbf 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -107,17 +107,17 @@ bool LinearGradientContents::FastLinearGradient(const ContentContext& renderer, using VS = FastGradientPipeline::VertexShader; using FS = FastGradientPipeline::FragmentShader; - Geometry& geometry = *GetGeometry(); - bool force_stencil = !geometry.IsAxisAlignedRect(); + const Geometry* geometry = GetGeometry(); + bool force_stencil = !geometry->IsAxisAlignedRect(); auto geom_callback = [&](const ContentContext& renderer, const Entity& entity, RenderPass& pass, - const Geometry& geometry) -> GeometryResult { + const Geometry* geometry) -> GeometryResult { // We already know this is an axis aligned rectangle, so the coverage will // be approximately the same as the geometry. For non axis-algined // rectangles, we can force stencil then cover (not done here). We give an // identity transform to avoid double transforming the gradient. - std::optional maybe_rect = geometry.GetCoverage(Matrix()); + std::optional maybe_rect = geometry->GetCoverage(Matrix()); if (!maybe_rect.has_value()) { return {}; } diff --git a/impeller/entity/contents/solid_color_contents.cc b/impeller/entity/contents/solid_color_contents.cc index efddb125f6701..6fdd23fa69a88 100644 --- a/impeller/entity/contents/solid_color_contents.cc +++ b/impeller/entity/contents/solid_color_contents.cc @@ -38,7 +38,7 @@ std::optional SolidColorContents::GetCoverage( return std::nullopt; } - const std::shared_ptr& geometry = GetGeometry(); + const Geometry* geometry = GetGeometry(); if (geometry == nullptr) { return std::nullopt; } @@ -70,14 +70,6 @@ bool SolidColorContents::Render(const ContentContext& renderer, }); } -std::unique_ptr SolidColorContents::Make(const Path& path, - Color color) { - auto contents = std::make_unique(); - contents->SetGeometry(Geometry::MakeFillPath(path)); - contents->SetColor(color); - return contents; -} - std::optional SolidColorContents::AsBackgroundColor( const Entity& entity, ISize target_size) const { diff --git a/impeller/entity/contents/solid_color_contents.h b/impeller/entity/contents/solid_color_contents.h index af6d5048ec22e..c6982206f21a9 100644 --- a/impeller/entity/contents/solid_color_contents.h +++ b/impeller/entity/contents/solid_color_contents.h @@ -5,12 +5,9 @@ #ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_SOLID_COLOR_CONTENTS_H_ #define FLUTTER_IMPELLER_ENTITY_CONTENTS_SOLID_COLOR_CONTENTS_H_ -#include - #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/contents/contents.h" #include "impeller/geometry/color.h" -#include "impeller/geometry/path.h" namespace impeller { @@ -20,9 +17,6 @@ class SolidColorContents final : public ColorSourceContents { ~SolidColorContents() override; - static std::unique_ptr Make(const Path& path, - Color color); - void SetColor(Color color); Color GetColor() const; diff --git a/impeller/entity/contents/tiled_texture_contents_unittests.cc b/impeller/entity/contents/tiled_texture_contents_unittests.cc index dd732e36212a0..ff306e531d784 100644 --- a/impeller/entity/contents/tiled_texture_contents_unittests.cc +++ b/impeller/entity/contents/tiled_texture_contents_unittests.cc @@ -27,9 +27,10 @@ TEST_P(EntityTest, TiledTextureContentsRendersWithCorrectPipeline) { auto texture = GetContext()->GetResourceAllocator()->CreateTexture(texture_desc); + auto geom = Geometry::MakeCover(); TiledTextureContents contents; contents.SetTexture(texture); - contents.SetGeometry(Geometry::MakeCover()); + contents.SetGeometry(geom.get()); auto content_context = GetContentContext(); auto buffer = content_context->GetContext()->CreateCommandBuffer(); diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index b3f9b9940b4f8..6804b1ed4804b 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -95,34 +95,6 @@ TEST_P(EntityTest, FilterCoverageRespectsCropRect) { } } -TEST_P(EntityTest, CanDrawRect) { - auto contents = std::make_shared(); - contents->SetGeometry(Geometry::MakeRect(Rect::MakeXYWH(100, 100, 100, 100))); - contents->SetColor(Color::Red()); - - Entity entity; - entity.SetTransform(Matrix::MakeScale(GetContentScale())); - entity.SetContents(contents); - - ASSERT_TRUE(OpenPlaygroundHere(std::move(entity))); -} - -TEST_P(EntityTest, CanDrawRRect) { - auto contents = std::make_shared(); - auto path = PathBuilder{} - .SetConvexity(Convexity::kConvex) - .AddRoundedRect(Rect::MakeXYWH(100, 100, 100, 100), 10.0) - .TakePath(); - contents->SetGeometry(Geometry::MakeFillPath(path)); - contents->SetColor(Color::Red()); - - Entity entity; - entity.SetTransform(Matrix::MakeScale(GetContentScale())); - entity.SetContents(contents); - - ASSERT_TRUE(OpenPlaygroundHere(std::move(entity))); -} - TEST_P(EntityTest, GeometryBoundsAreTransformed) { auto geometry = Geometry::MakeRect(Rect::MakeXYWH(100, 100, 100, 100)); auto transform = Matrix::MakeScale({2.0, 2.0, 2.0}); @@ -144,7 +116,9 @@ TEST_P(EntityTest, ThreeStrokesInOnePath) { Entity entity; entity.SetTransform(Matrix::MakeScale(GetContentScale())); auto contents = std::make_unique(); - contents->SetGeometry(Geometry::MakeStrokePath(path, 5.0)); + + static std::unique_ptr geom = Geometry::MakeStrokePath(path, 5.0); + contents->SetGeometry(geom.get()); contents->SetColor(Color::Red()); entity.SetContents(std::move(contents)); ASSERT_TRUE(OpenPlaygroundHere(std::move(entity))); @@ -164,7 +138,8 @@ TEST_P(EntityTest, StrokeWithTextureContents) { Entity entity; entity.SetTransform(Matrix::MakeScale(GetContentScale())); auto contents = std::make_unique(); - contents->SetGeometry(Geometry::MakeStrokePath(path, 100.0)); + static std::unique_ptr geom = Geometry::MakeStrokePath(path, 100.0); + contents->SetGeometry(geom.get()); contents->SetTexture(bridge); contents->SetTileModes(Entity::TileMode::kClamp, Entity::TileMode::kClamp); entity.SetContents(std::move(contents)); @@ -205,7 +180,9 @@ TEST_P(EntityTest, TriangleInsideASquare) { Entity entity; entity.SetTransform(Matrix::MakeScale(GetContentScale())); auto contents = std::make_unique(); - contents->SetGeometry(Geometry::MakeStrokePath(path, 20.0)); + static std::unique_ptr geom = + Geometry::MakeStrokePath(path, 20.0); + contents->SetGeometry(geom.get()); contents->SetColor(Color::Red()); entity.SetContents(std::move(contents)); @@ -240,8 +217,9 @@ TEST_P(EntityTest, StrokeCapAndJoinTest) { auto render_path = [width = width, &context, &pass, &world_matrix]( const Path& path, Cap cap, Join join) { auto contents = std::make_unique(); - contents->SetGeometry( - Geometry::MakeStrokePath(path, width, miter_limit, cap, join)); + static std::unique_ptr geom = + Geometry::MakeStrokePath(path, width, miter_limit, cap, join); + contents->SetGeometry(geom.get()); contents->SetColor(Color::Red()); Entity entity; @@ -251,8 +229,11 @@ TEST_P(EntityTest, StrokeCapAndJoinTest) { auto coverage = entity.GetCoverage(); if (coverage.has_value()) { auto bounds_contents = std::make_unique(); - bounds_contents->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(entity.GetCoverage().value()).TakePath())); + + static std::unique_ptr geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(entity.GetCoverage().value()).TakePath()); + + bounds_contents->SetGeometry(geom.get()); bounds_contents->SetColor(Color::Green().WithAlpha(0.5)); Entity bounds_entity; bounds_entity.SetContents(std::move(bounds_contents)); @@ -372,7 +353,14 @@ TEST_P(EntityTest, CubicCurveTest) { .TakePath(); Entity entity; entity.SetTransform(Matrix::MakeScale(GetContentScale())); - entity.SetContents(SolidColorContents::Make(path, Color::Red())); + + static std::unique_ptr geom = Geometry::MakeFillPath(path); + + auto contents = std::make_shared(); + contents->SetColor(Color::Red()); + contents->SetGeometry(geom.get()); + + entity.SetContents(contents); ASSERT_TRUE(OpenPlaygroundHere(std::move(entity))); } @@ -416,7 +404,14 @@ TEST_P(EntityTest, CanDrawCorrectlyWithRotatedTransform) { Entity entity; entity.SetTransform(result_transform); - entity.SetContents(SolidColorContents::Make(path, Color::Red())); + + static std::unique_ptr geom = Geometry::MakeFillPath(path); + + auto contents = std::make_shared(); + contents->SetColor(Color::Red()); + contents->SetGeometry(geom.get()); + + entity.SetContents(contents); return entity.Render(context, pass); }; ASSERT_TRUE(OpenPlaygroundHere(callback)); @@ -646,7 +641,14 @@ TEST_P(EntityTest, CubicCurveAndOverlapTest) { .TakePath(); Entity entity; entity.SetTransform(Matrix::MakeScale(GetContentScale())); - entity.SetContents(SolidColorContents::Make(path, Color::Red())); + + static std::unique_ptr geom = Geometry::MakeFillPath(path); + + auto contents = std::make_shared(); + contents->SetColor(Color::Red()); + contents->SetGeometry(geom.get()); + + entity.SetContents(contents); ASSERT_TRUE(OpenPlaygroundHere(std::move(entity))); } @@ -680,13 +682,15 @@ TEST_P(EntityTest, SolidColorContentsStrokeSetMiterLimit) { } { - auto geometry = Geometry::MakeStrokePath(Path{}, 1.0, /*miter_limit=*/8.0); + auto geometry = Geometry::MakeStrokePath(Path{}, 1.0, + /*miter_limit=*/8.0); auto path_geometry = static_cast(geometry.get()); ASSERT_FLOAT_EQ(path_geometry->GetMiterLimit(), 8); } { - auto geometry = Geometry::MakeStrokePath(Path{}, 1.0, /*miter_limit=*/-1.0); + auto geometry = Geometry::MakeStrokePath(Path{}, 1.0, + /*miter_limit=*/-1.0); auto path_geometry = static_cast(geometry.get()); ASSERT_FLOAT_EQ(path_geometry->GetMiterLimit(), 4); } @@ -851,7 +855,14 @@ TEST_P(EntityTest, BezierCircleScaled) { .TakePath(); entity.SetTransform( Matrix::MakeScale({scale, scale, 1.0}).Translate({-90, -20, 0})); - entity.SetContents(SolidColorContents::Make(path, Color::Red())); + + static std::unique_ptr geom = Geometry::MakeFillPath(path); + + auto contents = std::make_shared(); + contents->SetColor(Color::Red()); + contents->SetGeometry(geom.get()); + + entity.SetContents(contents); return entity.Render(context, pass); }; ASSERT_TRUE(OpenPlaygroundHere(callback)); @@ -955,7 +966,7 @@ TEST_P(EntityTest, GaussianBlurFilter) { ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, sizeof(tile_mode_names) / sizeof(char*)); ImGui::ColorEdit4("Cover color", reinterpret_cast(&cover_color)); - ImGui::ColorEdit4("Bounds color", + ImGui::ColorEdit4("Bounds color ", reinterpret_cast(&bounds_color)); ImGui::SliderFloat2("Translation", offset, 0, pass.GetRenderTargetSize().width); @@ -986,8 +997,10 @@ TEST_P(EntityTest, GaussianBlurFilter) { } else { auto fill = std::make_shared(); fill->SetColor(input_color); - fill->SetGeometry( - Geometry::MakeFillPath(PathBuilder{}.AddRect(input_rect).TakePath())); + static std::unique_ptr geom = + Geometry::MakeFillPath(PathBuilder{}.AddRect(input_rect).TakePath()); + + fill->SetGeometry(geom.get()); input = fill; input_size = input_rect.GetSize(); @@ -1032,10 +1045,13 @@ TEST_P(EntityTest, GaussianBlurFilter) { // Renders a red "cover" rectangle that shows the original position of the // unfiltered input. Entity cover_entity; - cover_entity.SetContents(SolidColorContents::Make( - PathBuilder{}.AddRect(input_rect).TakePath(), cover_color)); + static std::unique_ptr geom = + Geometry::MakeFillPath(PathBuilder{}.AddRect(input_rect).TakePath()); + auto contents = std::make_shared(); + contents->SetColor(cover_color); + contents->SetGeometry(geom.get()); + cover_entity.SetContents(std::move(contents)); cover_entity.SetTransform(ctm); - cover_entity.Render(context, pass); // Renders a green bounding rect of the target filter. @@ -1043,13 +1059,16 @@ TEST_P(EntityTest, GaussianBlurFilter) { std::optional target_contents_coverage = target_contents->GetCoverage(entity); if (target_contents_coverage.has_value()) { - bounds_entity.SetContents(SolidColorContents::Make( + static std::unique_ptr geom = Geometry::MakeFillPath( PathBuilder{} .AddRect(target_contents->GetCoverage(entity).value()) - .TakePath(), - bounds_color)); - bounds_entity.SetTransform(Matrix()); + .TakePath()); + auto contents = std::make_shared(); + contents->SetColor(bounds_color); + contents->SetGeometry(geom.get()); + bounds_entity.SetContents(contents); + bounds_entity.SetTransform(Matrix()); bounds_entity.Render(context, pass); } @@ -1089,7 +1108,7 @@ TEST_P(EntityTest, MorphologyFilter) { ImGui::SliderFloat2("Radius", radius, 0, 200); ImGui::SliderFloat("Input opacity", &input_color.alpha, 0, 1); ImGui::ColorEdit4("Cover color", reinterpret_cast(&cover_color)); - ImGui::ColorEdit4("Bounds color", + ImGui::ColorEdit4("Bounds color ", reinterpret_cast(&bounds_color)); ImGui::SliderFloat2("Translation", offset, 0, pass.GetRenderTargetSize().width); @@ -1135,20 +1154,28 @@ TEST_P(EntityTest, MorphologyFilter) { entity.Render(context, pass); - // Renders a red "cover" rectangle that shows the original position of the + // Renders a red "cover" rectangle that shows the original position of the // unfiltered input. Entity cover_entity; - cover_entity.SetContents(SolidColorContents::Make( - PathBuilder{}.AddRect(input_rect).TakePath(), cover_color)); + static std::unique_ptr geom = + Geometry::MakeFillPath(PathBuilder{}.AddRect(input_rect).TakePath()); + auto cover_contents = std::make_shared(); + cover_contents->SetColor(cover_color); + cover_contents->SetGeometry(geom.get()); + cover_entity.SetContents(cover_contents); cover_entity.SetTransform(ctm); - cover_entity.Render(context, pass); // Renders a green bounding rect of the target filter. Entity bounds_entity; - bounds_entity.SetContents(SolidColorContents::Make( - PathBuilder{}.AddRect(contents->GetCoverage(entity).value()).TakePath(), - bounds_color)); + static std::unique_ptr bounds_geom = Geometry::MakeFillPath( + PathBuilder{} + .AddRect(contents->GetCoverage(entity).value()) + .TakePath()); + auto bounds_contents = std::make_shared(); + bounds_contents->SetColor(bounds_color); + bounds_contents->SetGeometry(bounds_geom.get()); + bounds_entity.SetContents(std::move(bounds_contents)); bounds_entity.SetTransform(Matrix()); bounds_entity.Render(context, pass); @@ -1179,11 +1206,12 @@ TEST_P(EntityTest, SolidStrokeCoverageIsCorrect) { Entity entity; auto contents = std::make_unique(); - contents->SetGeometry(std::move(geometry)); + contents->SetGeometry(geometry.get()); contents->SetColor(Color::Black()); entity.SetContents(std::move(contents)); auto actual = entity.GetCoverage(); auto expected = Rect::MakeLTRB(-2, -2, 12, 12); + ASSERT_TRUE(actual.has_value()); ASSERT_RECT_NEAR(actual.value(), expected); } @@ -1196,12 +1224,13 @@ TEST_P(EntityTest, SolidStrokeCoverageIsCorrect) { Entity entity; auto contents = std::make_unique(); - contents->SetGeometry(std::move(geometry)); + contents->SetGeometry(geometry.get()); contents->SetColor(Color::Black()); entity.SetContents(std::move(contents)); auto actual = entity.GetCoverage(); auto expected = Rect::MakeLTRB(-sqrt(8), -sqrt(8), 10 + sqrt(8), 10 + sqrt(8)); + ASSERT_TRUE(actual.has_value()); ASSERT_RECT_NEAR(actual.value(), expected); } @@ -1214,11 +1243,12 @@ TEST_P(EntityTest, SolidStrokeCoverageIsCorrect) { Entity entity; auto contents = std::make_unique(); - contents->SetGeometry(std::move(geometry)); + contents->SetGeometry(geometry.get()); contents->SetColor(Color::Black()); entity.SetContents(std::move(contents)); auto actual = entity.GetCoverage(); auto expected = Rect::MakeLTRB(-4, -4, 14, 14); + ASSERT_TRUE(actual.has_value()); ASSERT_RECT_NEAR(actual.value(), expected); } @@ -1226,8 +1256,9 @@ TEST_P(EntityTest, SolidStrokeCoverageIsCorrect) { TEST_P(EntityTest, BorderMaskBlurCoverageIsCorrect) { auto fill = std::make_shared(); - fill->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath())); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath()); + fill->SetGeometry(geom.get()); fill->SetColor(Color::CornflowerBlue()); auto border_mask_blur = FilterContents::MakeBorderMaskBlur( FilterInput::Make(fill), Radius{3}, Radius{4}); @@ -1257,8 +1288,9 @@ TEST_P(EntityTest, SolidFillCoverageIsCorrect) { auto fill = std::make_shared(); fill->SetColor(Color::CornflowerBlue()); auto expected = Rect::MakeLTRB(100, 110, 200, 220); - fill->SetGeometry( - Geometry::MakeFillPath(PathBuilder{}.AddRect(expected).TakePath())); + auto geom = + Geometry::MakeFillPath(PathBuilder{}.AddRect(expected).TakePath()); + fill->SetGeometry(geom.get()); auto coverage = fill->GetCoverage({}); ASSERT_TRUE(coverage.has_value()); @@ -1268,9 +1300,10 @@ TEST_P(EntityTest, SolidFillCoverageIsCorrect) { // Entity transform { auto fill = std::make_shared(); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeLTRB(100, 110, 200, 220)).TakePath()); fill->SetColor(Color::CornflowerBlue()); - fill->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeLTRB(100, 110, 200, 220)).TakePath())); + fill->SetGeometry(geom.get()); Entity entity; entity.SetTransform(Matrix::MakeTranslation(Vector2(4, 5))); @@ -1285,9 +1318,10 @@ TEST_P(EntityTest, SolidFillCoverageIsCorrect) { // No coverage for fully transparent colors { auto fill = std::make_shared(); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeLTRB(100, 110, 200, 220)).TakePath()); fill->SetColor(Color::WhiteTransparent()); - fill->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeLTRB(100, 110, 200, 220)).TakePath())); + fill->SetGeometry(geom.get()); auto coverage = fill->GetCoverage({}); ASSERT_FALSE(coverage.has_value()); @@ -1307,9 +1341,10 @@ TEST_P(EntityTest, ClipContentsGetClipCoverageIsCorrect) { // Intersection: No stencil coverage, with geometry. { auto clip = std::make_shared(); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 100, 100)).TakePath()); clip->SetClipOperation(Entity::ClipOperation::kIntersect); - clip->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 100, 100)).TakePath())); + clip->SetGeometry(geom.get()); auto result = clip->GetClipCoverage(Entity{}, Rect{}); ASSERT_FALSE(result.coverage.has_value()); @@ -1328,9 +1363,10 @@ TEST_P(EntityTest, ClipContentsGetClipCoverageIsCorrect) { // Intersection: With stencil coverage, with geometry. { auto clip = std::make_shared(); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 50, 50)).TakePath()); clip->SetClipOperation(Entity::ClipOperation::kIntersect); - clip->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 50, 50)).TakePath())); + clip->SetGeometry(geom.get()); auto result = clip->GetClipCoverage(Entity{}, Rect::MakeLTRB(0, 0, 100, 100)); @@ -1342,9 +1378,10 @@ TEST_P(EntityTest, ClipContentsGetClipCoverageIsCorrect) { // Difference: With stencil coverage, with geometry. { auto clip = std::make_shared(); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 50, 50)).TakePath()); clip->SetClipOperation(Entity::ClipOperation::kDifference); - clip->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 50, 50)).TakePath())); + clip->SetGeometry(geom.get()); auto result = clip->GetClipCoverage(Entity{}, Rect::MakeLTRB(0, 0, 100, 100)); @@ -1394,8 +1431,9 @@ TEST_P(EntityTest, RRectShadowTest) { auto coverage = entity.GetCoverage(); if (show_coverage && coverage.has_value()) { auto bounds_contents = std::make_unique(); - bounds_contents->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(entity.GetCoverage().value()).TakePath())); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(entity.GetCoverage().value()).TakePath()); + bounds_contents->SetGeometry(geom.get()); bounds_contents->SetColor(coverage_color.Premultiply()); Entity bounds_entity; bounds_entity.SetContents(std::move(bounds_contents)); @@ -1410,8 +1448,9 @@ TEST_P(EntityTest, RRectShadowTest) { TEST_P(EntityTest, ColorMatrixFilterCoverageIsCorrect) { // Set up a simple color background. auto fill = std::make_shared(); - fill->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath())); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath()); + fill->SetGeometry(geom.get()); fill->SetColor(Color::Coral()); // Set the color matrix filter. @@ -1496,9 +1535,10 @@ TEST_P(EntityTest, ColorMatrixFilterEditable) { TEST_P(EntityTest, LinearToSrgbFilterCoverageIsCorrect) { // Set up a simple color background. + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath()); auto fill = std::make_shared(); - fill->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath())); + fill->SetGeometry(geom.get()); fill->SetColor(Color::MintCream()); auto filter = @@ -1549,8 +1589,9 @@ TEST_P(EntityTest, LinearToSrgbFilter) { TEST_P(EntityTest, SrgbToLinearFilterCoverageIsCorrect) { // Set up a simple color background. auto fill = std::make_shared(); - fill->SetGeometry(Geometry::MakeFillPath( - PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath())); + auto geom = Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath()); + fill->SetGeometry(geom.get()); fill->SetColor(Color::DeepPink()); auto filter = @@ -1720,11 +1761,13 @@ TEST_P(EntityTest, RuntimeEffect) { bool expect_dirty = true; Pipeline* first_pipeline; + static std::unique_ptr geom = Geometry::MakeCover(); + auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { EXPECT_EQ(runtime_stage->IsDirty(), expect_dirty); auto contents = std::make_shared(); - contents->SetGeometry(Geometry::MakeCover()); + contents->SetGeometry(geom.get()); contents->SetRuntimeStage(runtime_stage); struct FragUniforms { @@ -1786,8 +1829,8 @@ TEST_P(EntityTest, RuntimeEffectCanSuccessfullyRender) { ASSERT_TRUE(runtime_stage->IsDirty()); auto contents = std::make_shared(); - contents->SetGeometry(Geometry::MakeCover()); - + auto geom = Geometry::MakeCover(); + contents->SetGeometry(geom.get()); contents->SetRuntimeStage(runtime_stage); struct FragUniforms { @@ -1851,7 +1894,8 @@ TEST_P(EntityTest, RuntimeEffectSetsRightSizeWhenUniformIsStruct) { ASSERT_TRUE(runtime_stage->IsDirty()); auto contents = std::make_shared(); - contents->SetGeometry(Geometry::MakeCover()); + auto geom = Geometry::MakeCover(); + contents->SetGeometry(geom.get()); contents->SetRuntimeStage(runtime_stage); struct FragUniforms { @@ -1886,43 +1930,6 @@ TEST_P(EntityTest, RuntimeEffectSetsRightSizeWhenUniformIsStruct) { 16u); } -TEST_P(EntityTest, InheritOpacityTest) { - Entity entity; - - // Texture contents can always accept opacity. - auto texture_contents = std::make_shared(); - texture_contents->SetOpacity(0.5); - - texture_contents->SetInheritedOpacity(0.5); - ASSERT_EQ(texture_contents->GetOpacity(), 0.25); - texture_contents->SetInheritedOpacity(0.5); - ASSERT_EQ(texture_contents->GetOpacity(), 0.25); - - // Solid color contents can accept opacity if their geometry - // doesn't overlap. - auto solid_color = std::make_shared(); - solid_color->SetGeometry( - Geometry::MakeRect(Rect::MakeLTRB(100, 100, 200, 200))); - solid_color->SetColor(Color::Blue().WithAlpha(0.5)); - - solid_color->SetInheritedOpacity(0.5); - ASSERT_EQ(solid_color->GetColor().alpha, 0.25); - solid_color->SetInheritedOpacity(0.5); - ASSERT_EQ(solid_color->GetColor().alpha, 0.25); - - // Color source contents can accept opacity if their geometry - // doesn't overlap. - auto tiled_texture = std::make_shared(); - tiled_texture->SetGeometry( - Geometry::MakeRect(Rect::MakeLTRB(100, 100, 200, 200))); - tiled_texture->SetOpacityFactor(0.5); - - tiled_texture->SetInheritedOpacity(0.5); - ASSERT_EQ(tiled_texture->GetOpacityFactor(), 0.25); - tiled_texture->SetInheritedOpacity(0.5); - ASSERT_EQ(tiled_texture->GetOpacityFactor(), 0.25); -} - TEST_P(EntityTest, ColorFilterWithForegroundColorAdvancedBlend) { auto image = CreateTextureForFixture("boston.jpg"); auto filter = ColorFilterContents::MakeBlend( @@ -2026,7 +2033,8 @@ TEST_P(EntityTest, CoverageForStrokePathWithNegativeValuesInTransform) { TEST_P(EntityTest, SolidColorContentsIsOpaque) { Matrix matrix; SolidColorContents contents; - contents.SetGeometry(Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10))); + auto geom = Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10)); + contents.SetGeometry(geom.get()); contents.SetColor(Color::CornflowerBlue()); EXPECT_TRUE(contents.IsOpaque(matrix)); @@ -2034,9 +2042,10 @@ TEST_P(EntityTest, SolidColorContentsIsOpaque) { EXPECT_FALSE(contents.IsOpaque(matrix)); // Create stroked path that required alpha coverage. - contents.SetGeometry(Geometry::MakeStrokePath( + geom = Geometry::MakeStrokePath( PathBuilder{}.AddLine({0, 0}, {100, 100}).TakePath(), - /*stroke_width=*/0.05)); + /*stroke_width=*/0.05); + contents.SetGeometry(geom.get()); contents.SetColor(Color::CornflowerBlue()); EXPECT_FALSE(contents.IsOpaque(matrix)); @@ -2045,7 +2054,8 @@ TEST_P(EntityTest, SolidColorContentsIsOpaque) { TEST_P(EntityTest, ConicalGradientContentsIsOpaque) { Matrix matrix; ConicalGradientContents contents; - contents.SetGeometry(Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10))); + auto geom = Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10)); + contents.SetGeometry(geom.get()); contents.SetColors({Color::CornflowerBlue()}); EXPECT_FALSE(contents.IsOpaque(matrix)); @@ -2053,9 +2063,10 @@ TEST_P(EntityTest, ConicalGradientContentsIsOpaque) { EXPECT_FALSE(contents.IsOpaque(matrix)); // Create stroked path that required alpha coverage. - contents.SetGeometry(Geometry::MakeStrokePath( + geom = Geometry::MakeStrokePath( PathBuilder{}.AddLine({0, 0}, {100, 100}).TakePath(), - /*stroke_width=*/0.05)); + /*stroke_width=*/0.05); + contents.SetGeometry(geom.get()); contents.SetColors({Color::CornflowerBlue()}); EXPECT_FALSE(contents.IsOpaque(matrix)); @@ -2064,7 +2075,8 @@ TEST_P(EntityTest, ConicalGradientContentsIsOpaque) { TEST_P(EntityTest, LinearGradientContentsIsOpaque) { Matrix matrix; LinearGradientContents contents; - contents.SetGeometry(Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10))); + auto geom = Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10)); + contents.SetGeometry(geom.get()); contents.SetColors({Color::CornflowerBlue()}); EXPECT_TRUE(contents.IsOpaque(matrix)); @@ -2075,9 +2087,10 @@ TEST_P(EntityTest, LinearGradientContentsIsOpaque) { EXPECT_FALSE(contents.IsOpaque(matrix)); // Create stroked path that required alpha coverage. - contents.SetGeometry(Geometry::MakeStrokePath( + geom = Geometry::MakeStrokePath( PathBuilder{}.AddLine({0, 0}, {100, 100}).TakePath(), - /*stroke_width=*/0.05)); + /*stroke_width=*/0.05); + contents.SetGeometry(geom.get()); contents.SetColors({Color::CornflowerBlue()}); EXPECT_FALSE(contents.IsOpaque(matrix)); @@ -2086,7 +2099,8 @@ TEST_P(EntityTest, LinearGradientContentsIsOpaque) { TEST_P(EntityTest, RadialGradientContentsIsOpaque) { Matrix matrix; RadialGradientContents contents; - contents.SetGeometry(Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10))); + auto geom = Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10)); + contents.SetGeometry(geom.get()); contents.SetColors({Color::CornflowerBlue()}); EXPECT_TRUE(contents.IsOpaque(matrix)); @@ -2097,9 +2111,10 @@ TEST_P(EntityTest, RadialGradientContentsIsOpaque) { EXPECT_FALSE(contents.IsOpaque(matrix)); // Create stroked path that required alpha coverage. - contents.SetGeometry(Geometry::MakeStrokePath( + geom = Geometry::MakeStrokePath( PathBuilder{}.AddLine({0, 0}, {100, 100}).TakePath(), - /*stroke_width=*/0.05)); + /*stroke_width=*/0.05); + contents.SetGeometry(geom.get()); contents.SetColors({Color::CornflowerBlue()}); EXPECT_FALSE(contents.IsOpaque(matrix)); @@ -2108,7 +2123,8 @@ TEST_P(EntityTest, RadialGradientContentsIsOpaque) { TEST_P(EntityTest, SweepGradientContentsIsOpaque) { Matrix matrix; RadialGradientContents contents; - contents.SetGeometry(Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10))); + auto geom = Geometry::MakeRect(Rect::MakeLTRB(0, 0, 10, 10)); + contents.SetGeometry(geom.get()); contents.SetColors({Color::CornflowerBlue()}); EXPECT_TRUE(contents.IsOpaque(matrix)); @@ -2119,9 +2135,10 @@ TEST_P(EntityTest, SweepGradientContentsIsOpaque) { EXPECT_FALSE(contents.IsOpaque(matrix)); // Create stroked path that required alpha coverage. - contents.SetGeometry(Geometry::MakeStrokePath( + geom = Geometry::MakeStrokePath( PathBuilder{}.AddLine({0, 0}, {100, 100}).TakePath(), - /*stroke_width=*/0.05)); + /*stroke_width=*/0.05); + contents.SetGeometry(geom.get()); contents.SetColors({Color::CornflowerBlue()}); EXPECT_FALSE(contents.IsOpaque(matrix)); @@ -2150,13 +2167,13 @@ TEST_P(EntityTest, ColorFilterContentsWithLargeGeometry) { Entity entity; entity.SetTransform(Matrix::MakeScale(GetContentScale())); auto src_contents = std::make_shared(); - src_contents->SetGeometry( - Geometry::MakeRect(Rect::MakeLTRB(-300, -500, 30000, 50000))); + auto src_geom = Geometry::MakeRect(Rect::MakeLTRB(-300, -500, 30000, 50000)); + src_contents->SetGeometry(src_geom.get()); src_contents->SetColor(Color::Red()); auto dst_contents = std::make_shared(); - dst_contents->SetGeometry( - Geometry::MakeRect(Rect::MakeLTRB(300, 500, 20000, 30000))); + auto dst_geom = Geometry::MakeRect(Rect::MakeLTRB(300, 500, 20000, 30000)); + dst_contents->SetGeometry(dst_geom.get()); dst_contents->SetColor(Color::Blue()); auto contents = ColorFilterContents::MakeBlend( @@ -2234,13 +2251,15 @@ TEST_P(EntityTest, ContentContextOptionsHasReasonableHashFunctions) { #ifdef FML_OS_LINUX TEST_P(EntityTest, FramebufferFetchVulkanBindingOffsetIsTheSame) { // Using framebuffer fetch on Vulkan requires that we maintain a subpass input - // binding that we don't have a good route for configuring with the current - // metadata approach. This test verifies that the binding value doesn't change + // binding that we don't have a good route for configuring with the + // current metadata approach. This test verifies that the binding value + // doesn't change // from the expected constant. // See also: // * impeller/renderer/backend/vulkan/binding_helpers_vk.cc // * impeller/entity/shaders/blending/framebuffer_blend.frag - // This test only works on Linux because macOS hosts incorrectly populate the + // This test only works on Linux because macOS hosts incorrectly + // populate the // Vulkan descriptor sets based on the MSL compiler settings. bool expected_layout = false; @@ -2333,7 +2352,8 @@ TEST_P(EntityTest, CanRenderEmptyPathsWithoutCrashing) { EXPECT_TRUE(path.GetBoundingBox()->IsEmpty()); auto contents = std::make_shared(); - contents->SetGeometry(Geometry::MakeFillPath(path)); + static std::unique_ptr geom = Geometry::MakeFillPath(path); + contents->SetGeometry(geom.get()); contents->SetColor(Color::Red()); Entity entity; @@ -2361,9 +2381,11 @@ TEST_P(EntityTest, DrawSuperEllipse) { ImGui::End(); auto contents = std::make_shared(); + static std::unique_ptr geom = + std::make_unique(Point{400, 400}, radius, degree, + alpha, beta); contents->SetColor(color); - contents->SetGeometry(std::make_shared( - Point{400, 400}, radius, degree, alpha, beta)); + contents->SetGeometry(geom.get()); Entity entity; entity.SetContents(contents); diff --git a/impeller/entity/geometry/circle_geometry.cc b/impeller/entity/geometry/circle_geometry.cc index b4075757780a3..ab265a6c10462 100644 --- a/impeller/entity/geometry/circle_geometry.cc +++ b/impeller/entity/geometry/circle_geometry.cc @@ -17,6 +17,8 @@ CircleGeometry::CircleGeometry(const Point& center, Scalar radius) FML_DCHECK(radius >= 0); } +CircleGeometry::~CircleGeometry() = default; + CircleGeometry::CircleGeometry(const Point& center, Scalar radius, Scalar stroke_width) diff --git a/impeller/entity/geometry/circle_geometry.h b/impeller/entity/geometry/circle_geometry.h index 7d33fdd390a92..cbbef0d119ba6 100644 --- a/impeller/entity/geometry/circle_geometry.h +++ b/impeller/entity/geometry/circle_geometry.h @@ -19,7 +19,7 @@ class CircleGeometry final : public Geometry { Scalar radius, Scalar stroke_width); - ~CircleGeometry() = default; + ~CircleGeometry() override; // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override; diff --git a/impeller/entity/geometry/cover_geometry.h b/impeller/entity/geometry/cover_geometry.h index 1d238fbc9949b..4be6359acf946 100644 --- a/impeller/entity/geometry/cover_geometry.h +++ b/impeller/entity/geometry/cover_geometry.h @@ -15,7 +15,7 @@ class CoverGeometry final : public Geometry { public: CoverGeometry(); - ~CoverGeometry() = default; + ~CoverGeometry() override = default; // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override; @@ -36,8 +36,6 @@ class CoverGeometry final : public Geometry { CoverGeometry& operator=(const CoverGeometry&) = delete; }; -static_assert(std::is_trivially_destructible::value); - } // namespace impeller #endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_COVER_GEOMETRY_H_ diff --git a/impeller/entity/geometry/ellipse_geometry.h b/impeller/entity/geometry/ellipse_geometry.h index 941f7a2b58882..924727072d048 100644 --- a/impeller/entity/geometry/ellipse_geometry.h +++ b/impeller/entity/geometry/ellipse_geometry.h @@ -17,7 +17,7 @@ class EllipseGeometry final : public Geometry { public: explicit EllipseGeometry(Rect bounds); - ~EllipseGeometry() = default; + ~EllipseGeometry() override = default; // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override; diff --git a/impeller/entity/geometry/fill_path_geometry.cc b/impeller/entity/geometry/fill_path_geometry.cc index 731618274907a..347aa3ed42607 100644 --- a/impeller/entity/geometry/fill_path_geometry.cc +++ b/impeller/entity/geometry/fill_path_geometry.cc @@ -16,6 +16,8 @@ FillPathGeometry::FillPathGeometry(const Path& path, std::optional inner_rect) : path_(path), inner_rect_(inner_rect) {} +FillPathGeometry::~FillPathGeometry() {} + GeometryResult FillPathGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, diff --git a/impeller/entity/geometry/fill_path_geometry.h b/impeller/entity/geometry/fill_path_geometry.h index 104ba0a6811e6..7b930d0557f3c 100644 --- a/impeller/entity/geometry/fill_path_geometry.h +++ b/impeller/entity/geometry/fill_path_geometry.h @@ -18,7 +18,7 @@ class FillPathGeometry final : public Geometry { explicit FillPathGeometry(const Path& path, std::optional inner_rect = std::nullopt); - ~FillPathGeometry() = default; + ~FillPathGeometry() override; // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override; diff --git a/impeller/entity/geometry/geometry.cc b/impeller/entity/geometry/geometry.cc index c92e02dad9aec..40540dd649a7f 100644 --- a/impeller/entity/geometry/geometry.cc +++ b/impeller/entity/geometry/geometry.cc @@ -57,19 +57,19 @@ GeometryResult::Mode Geometry::GetResultMode() const { return GeometryResult::Mode::kNormal; } -std::shared_ptr Geometry::MakeFillPath( +std::unique_ptr Geometry::MakeFillPath( const Path& path, std::optional inner_rect) { - return std::make_shared(path, inner_rect); + return std::make_unique(path, inner_rect); } -std::shared_ptr Geometry::MakePointField(std::vector points, +std::unique_ptr Geometry::MakePointField(std::vector points, Scalar radius, bool round) { - return std::make_shared(std::move(points), radius, round); + return std::make_unique(std::move(points), radius, round); } -std::shared_ptr Geometry::MakeStrokePath(const Path& path, +std::unique_ptr Geometry::MakeStrokePath(const Path& path, Scalar stroke_width, Scalar miter_limit, Cap stroke_cap, @@ -78,43 +78,43 @@ std::shared_ptr Geometry::MakeStrokePath(const Path& path, if (miter_limit < 0) { miter_limit = 4.0; } - return std::make_shared(path, stroke_width, miter_limit, + return std::make_unique(path, stroke_width, miter_limit, stroke_cap, stroke_join); } -std::shared_ptr Geometry::MakeCover() { - return std::make_shared(); +std::unique_ptr Geometry::MakeCover() { + return std::make_unique(); } -std::shared_ptr Geometry::MakeRect(const Rect& rect) { - return std::make_shared(rect); +std::unique_ptr Geometry::MakeRect(const Rect& rect) { + return std::make_unique(rect); } -std::shared_ptr Geometry::MakeOval(const Rect& rect) { - return std::make_shared(rect); +std::unique_ptr Geometry::MakeOval(const Rect& rect) { + return std::make_unique(rect); } -std::shared_ptr Geometry::MakeLine(const Point& p0, +std::unique_ptr Geometry::MakeLine(const Point& p0, const Point& p1, Scalar width, Cap cap) { - return std::make_shared(p0, p1, width, cap); + return std::make_unique(p0, p1, width, cap); } -std::shared_ptr Geometry::MakeCircle(const Point& center, +std::unique_ptr Geometry::MakeCircle(const Point& center, Scalar radius) { - return std::make_shared(center, radius); + return std::make_unique(center, radius); } -std::shared_ptr Geometry::MakeStrokedCircle(const Point& center, +std::unique_ptr Geometry::MakeStrokedCircle(const Point& center, Scalar radius, Scalar stroke_width) { - return std::make_shared(center, radius, stroke_width); + return std::make_unique(center, radius, stroke_width); } -std::shared_ptr Geometry::MakeRoundRect(const Rect& rect, +std::unique_ptr Geometry::MakeRoundRect(const Rect& rect, const Size& radii) { - return std::make_shared(rect, radii); + return std::make_unique(rect, radii); } bool Geometry::CoversArea(const Matrix& transform, const Rect& rect) const { diff --git a/impeller/entity/geometry/geometry.h b/impeller/entity/geometry/geometry.h index 09d4384882a1b..8a24936366377 100644 --- a/impeller/entity/geometry/geometry.h +++ b/impeller/entity/geometry/geometry.h @@ -54,39 +54,41 @@ static const GeometryResult kEmptyResult = { class Geometry { public: - static std::shared_ptr MakeFillPath( + virtual ~Geometry() {} + + static std::unique_ptr MakeFillPath( const Path& path, std::optional inner_rect = std::nullopt); - static std::shared_ptr MakeStrokePath( + static std::unique_ptr MakeStrokePath( const Path& path, Scalar stroke_width = 0.0, Scalar miter_limit = 4.0, Cap stroke_cap = Cap::kButt, Join stroke_join = Join::kMiter); - static std::shared_ptr MakeCover(); + static std::unique_ptr MakeCover(); - static std::shared_ptr MakeRect(const Rect& rect); + static std::unique_ptr MakeRect(const Rect& rect); - static std::shared_ptr MakeOval(const Rect& rect); + static std::unique_ptr MakeOval(const Rect& rect); - static std::shared_ptr MakeLine(const Point& p0, + static std::unique_ptr MakeLine(const Point& p0, const Point& p1, Scalar width, Cap cap); - static std::shared_ptr MakeCircle(const Point& center, + static std::unique_ptr MakeCircle(const Point& center, Scalar radius); - static std::shared_ptr MakeStrokedCircle(const Point& center, + static std::unique_ptr MakeStrokedCircle(const Point& center, Scalar radius, Scalar stroke_width); - static std::shared_ptr MakeRoundRect(const Rect& rect, + static std::unique_ptr MakeRoundRect(const Rect& rect, const Size& radii); - static std::shared_ptr MakePointField(std::vector points, + static std::unique_ptr MakePointField(std::vector points, Scalar radius, bool round); diff --git a/impeller/entity/geometry/line_geometry.cc b/impeller/entity/geometry/line_geometry.cc index 72c20cd83e436..d5f5b640630b1 100644 --- a/impeller/entity/geometry/line_geometry.cc +++ b/impeller/entity/geometry/line_geometry.cc @@ -12,6 +12,8 @@ LineGeometry::LineGeometry(Point p0, Point p1, Scalar width, Cap cap) FML_DCHECK(width >= 0); } +LineGeometry::~LineGeometry() = default; + Scalar LineGeometry::ComputePixelHalfWidth(const Matrix& transform, Scalar width, bool msaa) { diff --git a/impeller/entity/geometry/line_geometry.h b/impeller/entity/geometry/line_geometry.h index 861ae4a0d8624..5f9a0306a1f22 100644 --- a/impeller/entity/geometry/line_geometry.h +++ b/impeller/entity/geometry/line_geometry.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_IMPELLER_ENTITY_GEOMETRY_LINE_GEOMETRY_H_ #define FLUTTER_IMPELLER_ENTITY_GEOMETRY_LINE_GEOMETRY_H_ -#include #include "impeller/entity/geometry/geometry.h" namespace impeller { @@ -14,7 +13,7 @@ class LineGeometry final : public Geometry { public: explicit LineGeometry(Point p0, Point p1, Scalar width, Cap cap); - ~LineGeometry() = default; + ~LineGeometry() override; static Scalar ComputePixelHalfWidth(const Matrix& transform, Scalar width, @@ -70,8 +69,6 @@ class LineGeometry final : public Geometry { LineGeometry& operator=(const LineGeometry&) = delete; }; -static_assert(std::is_trivially_destructible::value); - } // namespace impeller #endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_LINE_GEOMETRY_H_ diff --git a/impeller/entity/geometry/point_field_geometry.cc b/impeller/entity/geometry/point_field_geometry.cc index 9cf412e1e1340..ff7cf8cf124f2 100644 --- a/impeller/entity/geometry/point_field_geometry.cc +++ b/impeller/entity/geometry/point_field_geometry.cc @@ -15,6 +15,8 @@ PointFieldGeometry::PointFieldGeometry(std::vector points, bool round) : points_(std::move(points)), radius_(radius), round_(round) {} +PointFieldGeometry::~PointFieldGeometry() = default; + GeometryResult PointFieldGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, diff --git a/impeller/entity/geometry/point_field_geometry.h b/impeller/entity/geometry/point_field_geometry.h index 14696a1652c9f..eb47345bf8306 100644 --- a/impeller/entity/geometry/point_field_geometry.h +++ b/impeller/entity/geometry/point_field_geometry.h @@ -13,7 +13,7 @@ class PointFieldGeometry final : public Geometry { public: PointFieldGeometry(std::vector points, Scalar radius, bool round); - ~PointFieldGeometry() = default; + ~PointFieldGeometry() override; private: // |Geometry| diff --git a/impeller/entity/geometry/rect_geometry.cc b/impeller/entity/geometry/rect_geometry.cc index 6c88015079294..19de79d718610 100644 --- a/impeller/entity/geometry/rect_geometry.cc +++ b/impeller/entity/geometry/rect_geometry.cc @@ -8,6 +8,8 @@ namespace impeller { RectGeometry::RectGeometry(Rect rect) : rect_(rect) {} +RectGeometry::~RectGeometry() = default; + GeometryResult RectGeometry::GetPositionBuffer(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { diff --git a/impeller/entity/geometry/rect_geometry.h b/impeller/entity/geometry/rect_geometry.h index d7b90d41424a1..40457939ad63f 100644 --- a/impeller/entity/geometry/rect_geometry.h +++ b/impeller/entity/geometry/rect_geometry.h @@ -13,7 +13,7 @@ class RectGeometry final : public Geometry { public: explicit RectGeometry(Rect rect); - ~RectGeometry() = default; + ~RectGeometry() override; // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override; @@ -31,14 +31,8 @@ class RectGeometry final : public Geometry { private: Rect rect_; - - RectGeometry(const RectGeometry&) = delete; - - RectGeometry& operator=(const RectGeometry&) = delete; }; -static_assert(std::is_trivially_destructible::value); - } // namespace impeller #endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_RECT_GEOMETRY_H_ diff --git a/impeller/entity/geometry/round_rect_geometry.cc b/impeller/entity/geometry/round_rect_geometry.cc index fea43dbb38200..1d673f53add31 100644 --- a/impeller/entity/geometry/round_rect_geometry.cc +++ b/impeller/entity/geometry/round_rect_geometry.cc @@ -9,6 +9,8 @@ namespace impeller { RoundRectGeometry::RoundRectGeometry(const Rect& bounds, const Size& radii) : bounds_(bounds), radii_(radii) {} +RoundRectGeometry::~RoundRectGeometry() = default; + GeometryResult RoundRectGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, diff --git a/impeller/entity/geometry/round_rect_geometry.h b/impeller/entity/geometry/round_rect_geometry.h index b3b7957aca2e3..1cf73b812bd5c 100644 --- a/impeller/entity/geometry/round_rect_geometry.h +++ b/impeller/entity/geometry/round_rect_geometry.h @@ -17,7 +17,7 @@ class RoundRectGeometry final : public Geometry { public: explicit RoundRectGeometry(const Rect& bounds, const Size& radii); - ~RoundRectGeometry() = default; + ~RoundRectGeometry() override; // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override; diff --git a/impeller/entity/geometry/stroke_path_geometry.h b/impeller/entity/geometry/stroke_path_geometry.h index e5575f8147ed6..4265710e6941a 100644 --- a/impeller/entity/geometry/stroke_path_geometry.h +++ b/impeller/entity/geometry/stroke_path_geometry.h @@ -19,7 +19,7 @@ class StrokePathGeometry final : public Geometry { Cap stroke_cap, Join stroke_join); - ~StrokePathGeometry(); + ~StrokePathGeometry() override; Scalar GetStrokeWidth() const; diff --git a/impeller/entity/geometry/superellipse_geometry.cc b/impeller/entity/geometry/superellipse_geometry.cc index 578126b03c89d..5fe5fd660afe9 100644 --- a/impeller/entity/geometry/superellipse_geometry.cc +++ b/impeller/entity/geometry/superellipse_geometry.cc @@ -21,6 +21,8 @@ SuperellipseGeometry::SuperellipseGeometry(const Point& center, alpha_(alpha), beta_(beta) {} +SuperellipseGeometry::~SuperellipseGeometry() {} + GeometryResult SuperellipseGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, diff --git a/impeller/entity/geometry/superellipse_geometry.h b/impeller/entity/geometry/superellipse_geometry.h index 19c049f2962ff..b01845bac57b1 100644 --- a/impeller/entity/geometry/superellipse_geometry.h +++ b/impeller/entity/geometry/superellipse_geometry.h @@ -28,7 +28,7 @@ class SuperellipseGeometry final : public Geometry { Scalar alpha, Scalar beta); - ~SuperellipseGeometry() = default; + ~SuperellipseGeometry() override; // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override;