From 32aa60630bbf800f8ebf0cecc0b240f9cbe25290 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 8 Oct 2024 12:55:21 -0700 Subject: [PATCH] [Impeller] remove heap allocation of most geometry objects. (flutter/engine#55677) Almost all geometry objects can now be stack allocated while rendering, instead of heap allocated - due to the removal of the EntityPass compositor. Clip geometries must still be heap allocated as the geometry objects are not yet stored in the display list, and the clips must be recorded for backdrop filter clip replay. The canvas stores unique_ptrs to these geometries in a vector that it clears at the end of the frame. The Geometry factory methods were adjusted to return unique ptrs, and the Geometry class given a virtual dtor since we no longer rely on the special property of std::shared_ptr for memorizing the right dtor. The ColorSourceContents and ClipContents class now hold onto a const ptr to the geometry object. At some point in the future, we can rework the geometry object to be stored inline in the display list which will further simplify this code. Part of https://github.com/flutter/flutter/issues/142054 --- .../flutter/impeller/display_list/canvas.cc | 321 +++++++++-------- .../flutter/impeller/display_list/canvas.h | 33 +- .../impeller/display_list/dl_dispatcher.cc | 37 +- .../flutter/impeller/display_list/paint.cc | 16 +- .../src/flutter/impeller/display_list/paint.h | 6 +- .../impeller/entity/contents/clip_contents.cc | 2 +- .../impeller/entity/contents/clip_contents.h | 8 +- .../contents/clip_contents_unittests.cc | 3 +- .../entity/contents/color_source_contents.cc | 6 +- .../entity/contents/color_source_contents.h | 29 +- .../contents/filters/blend_filter_contents.cc | 5 +- .../contents/filters/filter_contents.cc | 2 +- .../entity/contents/filters/filter_contents.h | 2 +- .../filters/gaussian_blur_filter_contents.cc | 6 +- .../filters/gaussian_blur_filter_contents.h | 13 +- .../contents/linear_gradient_contents.cc | 8 +- .../entity/contents/solid_color_contents.cc | 10 +- .../entity/contents/solid_color_contents.h | 6 - .../tiled_texture_contents_unittests.cc | 3 +- .../impeller/entity/entity_unittests.cc | 322 ++++++++++-------- .../entity/geometry/circle_geometry.cc | 2 + .../entity/geometry/circle_geometry.h | 2 +- .../impeller/entity/geometry/cover_geometry.h | 4 +- .../entity/geometry/ellipse_geometry.h | 2 +- .../entity/geometry/fill_path_geometry.cc | 2 + .../entity/geometry/fill_path_geometry.h | 2 +- .../impeller/entity/geometry/geometry.cc | 40 +-- .../impeller/entity/geometry/geometry.h | 22 +- .../impeller/entity/geometry/line_geometry.cc | 2 + .../impeller/entity/geometry/line_geometry.h | 5 +- .../entity/geometry/point_field_geometry.cc | 2 + .../entity/geometry/point_field_geometry.h | 2 +- .../impeller/entity/geometry/rect_geometry.cc | 2 + .../impeller/entity/geometry/rect_geometry.h | 8 +- .../entity/geometry/round_rect_geometry.cc | 2 + .../entity/geometry/round_rect_geometry.h | 2 +- .../entity/geometry/stroke_path_geometry.h | 2 +- .../entity/geometry/superellipse_geometry.cc | 2 + .../entity/geometry/superellipse_geometry.h | 2 +- 39 files changed, 482 insertions(+), 463 deletions(-) diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc index 9c45f8d6dce..d14db69dc0d 100644 --- a/engine/src/flutter/impeller/display_list/canvas.cc +++ b/engine/src/flutter/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); - } - - 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(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; - } - - return CreateContentsForGeometryWithFilters(paint, std::move(geometry)); -} - -static std::shared_ptr CreateCoverContentsWithFilters( +static bool UseColorSourceContents( + const std::shared_ptr& vertices, const Paint& paint) { - return CreateContentsForGeometryWithFilters(paint, Geometry::MakeCover()); + // 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(); } 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); + 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::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); -} - -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/engine/src/flutter/impeller/display_list/canvas.h b/engine/src/flutter/impeller/display_list/canvas.h index e1cc8e2afda..387cb5c81dc 100644 --- a/engine/src/flutter/impeller/display_list/canvas.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/display_list/dl_dispatcher.cc b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc index 6a06ce5ff5b..ffdd0c6eca9 100644 --- a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/display_list/paint.cc b/engine/src/flutter/impeller/display_list/paint.cc index 59105b462ce..13bd681fe30 100644 --- a/engine/src/flutter/impeller/display_list/paint.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/display_list/paint.h b/engine/src/flutter/impeller/display_list/paint.h index 620b5126a15..830b72673ba 100644 --- a/engine/src/flutter/impeller/display_list/paint.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/clip_contents.cc b/engine/src/flutter/impeller/entity/contents/clip_contents.cc index 1eb51b8ee29..ee4535ed708 100644 --- a/engine/src/flutter/impeller/entity/contents/clip_contents.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/clip_contents.h b/engine/src/flutter/impeller/entity/contents/clip_contents.h index eae784ab251..51e76644f4e 100644 --- a/engine/src/flutter/impeller/entity/contents/clip_contents.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/clip_contents_unittests.cc b/engine/src/flutter/impeller/entity/contents/clip_contents_unittests.cc index f9c23cb6db2..21070a0bc5b 100644 --- a/engine/src/flutter/impeller/entity/contents/clip_contents_unittests.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/color_source_contents.cc b/engine/src/flutter/impeller/entity/contents/color_source_contents.cc index 009f3146076..8d42add0a92 100644 --- a/engine/src/flutter/impeller/entity/contents/color_source_contents.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/color_source_contents.h b/engine/src/flutter/impeller/entity/contents/color_source_contents.h index 1bade2c369b..52985493f78 100644 --- a/engine/src/flutter/impeller/entity/contents/color_source_contents.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc b/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc index 49c7d6b14cd..08b7b0744f3 100644 --- a/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/filters/filter_contents.cc b/engine/src/flutter/impeller/entity/contents/filters/filter_contents.cc index 36af904dd14..85bcabadc19 100644 --- a/engine/src/flutter/impeller/entity/contents/filters/filter_contents.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/filters/filter_contents.h b/engine/src/flutter/impeller/entity/contents/filters/filter_contents.h index 6ffdf13e2a6..3c355bb2494 100644 --- a/engine/src/flutter/impeller/entity/contents/filters/filter_contents.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 4c7af0b485f..efdd24254f0 100644 --- a/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index b24c87f0205..1cc43cfaf5c 100644 --- a/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc b/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc index 28ea871b618..73d533f2d7d 100644 --- a/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc b/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc index efddb125f67..6fdd23fa69a 100644 --- a/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/solid_color_contents.h b/engine/src/flutter/impeller/entity/contents/solid_color_contents.h index af6d5048ec2..c6982206f21 100644 --- a/engine/src/flutter/impeller/entity/contents/solid_color_contents.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc index dd732e36212..ff306e531d7 100644 --- a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/entity_unittests.cc b/engine/src/flutter/impeller/entity/entity_unittests.cc index b3f9b9940b4..6804b1ed480 100644 --- a/engine/src/flutter/impeller/entity/entity_unittests.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc b/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc index b4075757780..ab265a6c104 100644 --- a/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/circle_geometry.h b/engine/src/flutter/impeller/entity/geometry/circle_geometry.h index 7d33fdd390a..cbbef0d119b 100644 --- a/engine/src/flutter/impeller/entity/geometry/circle_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/cover_geometry.h b/engine/src/flutter/impeller/entity/geometry/cover_geometry.h index 1d238fbc994..4be6359acf9 100644 --- a/engine/src/flutter/impeller/entity/geometry/cover_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/ellipse_geometry.h b/engine/src/flutter/impeller/entity/geometry/ellipse_geometry.h index 941f7a2b588..924727072d0 100644 --- a/engine/src/flutter/impeller/entity/geometry/ellipse_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/fill_path_geometry.cc b/engine/src/flutter/impeller/entity/geometry/fill_path_geometry.cc index 73161827490..347aa3ed426 100644 --- a/engine/src/flutter/impeller/entity/geometry/fill_path_geometry.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/fill_path_geometry.h b/engine/src/flutter/impeller/entity/geometry/fill_path_geometry.h index 104ba0a6811..7b930d0557f 100644 --- a/engine/src/flutter/impeller/entity/geometry/fill_path_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/geometry.cc b/engine/src/flutter/impeller/entity/geometry/geometry.cc index c92e02dad9a..40540dd649a 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/geometry.h b/engine/src/flutter/impeller/entity/geometry/geometry.h index 09d4384882a..8a249363663 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/line_geometry.cc b/engine/src/flutter/impeller/entity/geometry/line_geometry.cc index 72c20cd83e4..d5f5b640630 100644 --- a/engine/src/flutter/impeller/entity/geometry/line_geometry.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/line_geometry.h b/engine/src/flutter/impeller/entity/geometry/line_geometry.h index 861ae4a0d86..5f9a0306a1f 100644 --- a/engine/src/flutter/impeller/entity/geometry/line_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/point_field_geometry.cc b/engine/src/flutter/impeller/entity/geometry/point_field_geometry.cc index 9cf412e1e13..ff7cf8cf124 100644 --- a/engine/src/flutter/impeller/entity/geometry/point_field_geometry.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/point_field_geometry.h b/engine/src/flutter/impeller/entity/geometry/point_field_geometry.h index 14696a1652c..eb47345bf83 100644 --- a/engine/src/flutter/impeller/entity/geometry/point_field_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/rect_geometry.cc b/engine/src/flutter/impeller/entity/geometry/rect_geometry.cc index 6c880150792..19de79d7186 100644 --- a/engine/src/flutter/impeller/entity/geometry/rect_geometry.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/rect_geometry.h b/engine/src/flutter/impeller/entity/geometry/rect_geometry.h index d7b90d41424..40457939ad6 100644 --- a/engine/src/flutter/impeller/entity/geometry/rect_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.cc b/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.cc index fea43dbb382..1d673f53add 100644 --- a/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.h b/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.h index b3b7957aca2..1cf73b812bd 100644 --- a/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.h b/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.h index e5575f8147e..4265710e694 100644 --- a/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.h +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/superellipse_geometry.cc b/engine/src/flutter/impeller/entity/geometry/superellipse_geometry.cc index 578126b03c8..5fe5fd660af 100644 --- a/engine/src/flutter/impeller/entity/geometry/superellipse_geometry.cc +++ b/engine/src/flutter/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/engine/src/flutter/impeller/entity/geometry/superellipse_geometry.h b/engine/src/flutter/impeller/entity/geometry/superellipse_geometry.h index 19c049f2962..b01845bac57 100644 --- a/engine/src/flutter/impeller/entity/geometry/superellipse_geometry.h +++ b/engine/src/flutter/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;