[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
This commit is contained in:
Jonah Williams 2024-10-08 12:55:21 -07:00 committed by GitHub
parent 96134c85e4
commit 32aa60630b
39 changed files with 482 additions and 463 deletions

View File

@ -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<Contents> CreateContentsForGeometryWithFilters(
const Paint& paint,
std::shared_ptr<Geometry> geometry) {
std::shared_ptr<ColorSourceContents> 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> 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<FilterContents> 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<Contents> CreatePathContentsWithFilters(
const Paint& paint,
const Path& path) {
std::shared_ptr<Geometry> 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<Contents> CreateCoverContentsWithFilters(
static bool UseColorSourceContents(
const std::shared_ptr<VerticesGeometry>& 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<Rect> 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>& geometry,
void Canvas::ClipGeometry(std::unique_ptr<Geometry> geometry,
Entity::ClipOperation clip_op) {
clip_geometry_.push_back(std::move(geometry));
auto contents = std::make_shared<ClipContents>();
contents->SetGeometry(geometry);
contents->SetGeometry(clip_geometry_.back().get());
contents->SetClipOperation(clip_op);
Entity entity;
@ -764,12 +689,10 @@ void Canvas::DrawPoints(std::vector<Point> 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<Texture>& image,
@ -811,16 +734,20 @@ void Canvas::DrawImageRect(const std::shared_ptr<Texture>& image,
texture_contents->SetOpacity(paint.color.alpha);
texture_contents->SetDeferApplyingOpacity(paint.HasColorFilter());
std::shared_ptr<Contents> 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<VerticesGeometry>& 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<VerticesGeometry>& vertices,
BlendMode blend_mode,
const Paint& paint) {
@ -861,8 +772,7 @@ void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& 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<VerticesGeometry>& vertices,
std::shared_ptr<ColorSourceContents> 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<VerticesGeometry>& 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<VerticesSimpleBlendContents>();
contents->SetBlendMode(blend_mode);
@ -1430,6 +1342,84 @@ void Canvas::DrawTextFrame(const std::shared_ptr<TextFrame>& text_frame,
AddRenderEntityToCurrentPass(entity, false);
}
void Canvas::AddRenderEntityWithFiltersToCurrentPass(Entity& entity,
const Geometry* geometry,
const Paint& paint,
bool reuse_depth) {
std::shared_ptr<ColorSourceContents> 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> 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<FilterContents> 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_);

View File

@ -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<TextFrame>& text_frame,
Point position,
const Paint& paint);
@ -225,6 +208,9 @@ class Canvas {
void DrawAtlas(const std::shared_ptr<AtlasContents>& atlas_contents,
const Paint& paint);
void ClipGeometry(std::unique_ptr<Geometry> geometry,
Entity::ClipOperation clip_op);
void EndReplay();
uint64_t GetOpDepth() const { return current_depth_; }
@ -247,6 +233,11 @@ class Canvas {
std::vector<LazyRenderingConfig> render_passes_;
std::vector<SaveLayerState> 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<std::unique_ptr<Geometry>> 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>& geometry,
Entity::ClipOperation clip_op);
void RestoreClip();
bool AttemptDrawBlurredRRect(const Rect& rect,

View File

@ -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);
}
}
}

View File

@ -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<Contents> Paint::WithColorFilter(
}
std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
std::shared_ptr<TextureContents> texture_contents) const {
std::shared_ptr<TextureContents> 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<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
auto mask = std::make_shared<SolidColorContents>();
mask->SetColor(Color::White());
std::optional<Rect> coverage = texture_contents->GetCoverage({});
std::shared_ptr<Geometry> 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<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
std::shared_ptr<ColorSourceContents> 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<FilterContents> 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<Contents> color_contents = color_source_contents;
/// 4. Apply the user set color filter on the GPU, if applicable.

View File

@ -58,10 +58,12 @@ struct Paint {
std::shared_ptr<FilterContents> CreateMaskBlur(
std::shared_ptr<ColorSourceContents> color_source_contents,
const flutter::DlColorFilter* color_filter,
bool invert_colors) const;
bool invert_colors,
RectGeometry* rect_geom) const;
std::shared_ptr<FilterContents> CreateMaskBlur(
std::shared_ptr<TextureContents> texture_contents) const;
std::shared_ptr<TextureContents> texture_contents,
RectGeometry* rect_geom) const;
std::shared_ptr<FilterContents> CreateMaskBlur(
const FilterInput::Ref& input,

View File

@ -32,7 +32,7 @@ ClipContents::ClipContents() = default;
ClipContents::~ClipContents() = default;
void ClipContents::SetGeometry(const std::shared_ptr<Geometry>& geometry) {
void ClipContents::SetGeometry(const Geometry* geometry) {
geometry_ = geometry;
}

View File

@ -5,10 +5,6 @@
#ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_CLIP_CONTENTS_H_
#define FLUTTER_IMPELLER_ENTITY_CONTENTS_CLIP_CONTENTS_H_
#include <functional>
#include <memory>
#include <vector>
#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>& 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> geometry_;
const Geometry* geometry_ = nullptr;
Entity::ClipOperation clip_op_ = Entity::ClipOperation::kIntersect;
ClipContents(const ClipContents&) = delete;

View File

@ -37,7 +37,8 @@ TEST_P(EntityTest, ClipContentsOptimizesFullScreenIntersectClips) {
auto contents = std::make_shared<ClipContents>();
contents->SetClipOperation(Entity::ClipOperation::kIntersect);
contents->SetGeometry(Geometry::MakeCover());
auto geom = Geometry::MakeCover();
contents->SetGeometry(geom.get());
Entity entity;
entity.SetContents(std::move(contents));

View File

@ -13,11 +13,11 @@ ColorSourceContents::ColorSourceContents() = default;
ColorSourceContents::~ColorSourceContents() = default;
void ColorSourceContents::SetGeometry(std::shared_ptr<Geometry> geometry) {
geometry_ = std::move(geometry);
void ColorSourceContents::SetGeometry(const Geometry* geometry) {
geometry_ = geometry;
}
const std::shared_ptr<Geometry>& ColorSourceContents::GetGeometry() const {
const Geometry* ColorSourceContents::GetGeometry() const {
return geometry_;
}

View File

@ -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> geometry);
void SetGeometry(const Geometry* geometry);
//----------------------------------------------------------------------------
/// @brief Get the geometry that this contents will use to render.
///
const std::shared_ptr<Geometry>& 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<GeometryResult(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const Geometry& geom)>;
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> geometry_;
const Geometry* geometry_ = nullptr;
Matrix inverse_matrix_;
Scalar opacity_ = 1.0;
Scalar inherited_opacity_ = 1.0;

View File

@ -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<Entity> PipelineBlend(
if (foreground_color.has_value()) {
auto contents = std::make_shared<SolidColorContents>();
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;

View File

@ -39,7 +39,7 @@ std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
Sigma sigma_y,
Entity::TileMode tile_mode,
FilterContents::BlurStyle mask_blur_style,
const std::shared_ptr<Geometry>& mask_geometry) {
const Geometry* mask_geometry) {
auto blur = std::make_shared<GaussianBlurFilterContents>(
sigma_x.sigma, sigma_y.sigma, tile_mode, mask_blur_style, mask_geometry);
blur->SetInputs({input});

View File

@ -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<Geometry>& mask_geometry = nullptr);
const Geometry* mask_geometry = nullptr);
static std::shared_ptr<FilterContents> MakeBorderMaskBlur(
FilterInput::Ref input,

View File

@ -505,7 +505,7 @@ Entity ApplyClippedBlurStyle(Entity::ClipOperation clip_operation,
const std::shared_ptr<FilterInput>& input,
const Snapshot& input_snapshot,
Entity blur_entity,
const std::shared_ptr<Geometry>& geometry) {
const Geometry* geometry) {
auto clip_contents = std::make_shared<ClipContents>();
clip_contents->SetClipOperation(clip_operation);
clip_contents->SetGeometry(geometry);
@ -544,7 +544,7 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style,
const std::shared_ptr<FilterInput>& input,
const Snapshot& input_snapshot,
Entity blur_entity,
const std::shared_ptr<Geometry>& 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<Geometry>& mask_geometry)
const Geometry* mask_geometry)
: sigma_(sigma_x, sigma_y),
tile_mode_(tile_mode),
mask_blur_style_(mask_blur_style),

View File

@ -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<Geometry>& 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<Geometry> mask_geometry_;
const Geometry* mask_geometry_ = nullptr;
};
} // namespace impeller

View File

@ -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<Rect> maybe_rect = geometry.GetCoverage(Matrix());
std::optional<Rect> maybe_rect = geometry->GetCoverage(Matrix());
if (!maybe_rect.has_value()) {
return {};
}

View File

@ -38,7 +38,7 @@ std::optional<Rect> SolidColorContents::GetCoverage(
return std::nullopt;
}
const std::shared_ptr<Geometry>& 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> SolidColorContents::Make(const Path& path,
Color color) {
auto contents = std::make_unique<SolidColorContents>();
contents->SetGeometry(Geometry::MakeFillPath(path));
contents->SetColor(color);
return contents;
}
std::optional<Color> SolidColorContents::AsBackgroundColor(
const Entity& entity,
ISize target_size) const {

View File

@ -5,12 +5,9 @@
#ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_SOLID_COLOR_CONTENTS_H_
#define FLUTTER_IMPELLER_ENTITY_CONTENTS_SOLID_COLOR_CONTENTS_H_
#include <memory>
#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<SolidColorContents> Make(const Path& path,
Color color);
void SetColor(Color color);
Color GetColor() const;

View File

@ -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();

View File

@ -95,34 +95,6 @@ TEST_P(EntityTest, FilterCoverageRespectsCropRect) {
}
}
TEST_P(EntityTest, CanDrawRect) {
auto contents = std::make_shared<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
contents->SetGeometry(Geometry::MakeStrokePath(path, 5.0));
static std::unique_ptr<Geometry> 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<TiledTextureContents>();
contents->SetGeometry(Geometry::MakeStrokePath(path, 100.0));
static std::unique_ptr<Geometry> 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<SolidColorContents>();
contents->SetGeometry(Geometry::MakeStrokePath(path, 20.0));
static std::unique_ptr<Geometry> 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<SolidColorContents>();
contents->SetGeometry(
Geometry::MakeStrokePath(path, width, miter_limit, cap, join));
static std::unique_ptr<Geometry> 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<SolidColorContents>();
bounds_contents->SetGeometry(Geometry::MakeFillPath(
PathBuilder{}.AddRect(entity.GetCoverage().value()).TakePath()));
static std::unique_ptr<Geometry> 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<Geometry> geom = Geometry::MakeFillPath(path);
auto contents = std::make_shared<SolidColorContents>();
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<Geometry> geom = Geometry::MakeFillPath(path);
auto contents = std::make_shared<SolidColorContents>();
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<Geometry> geom = Geometry::MakeFillPath(path);
auto contents = std::make_shared<SolidColorContents>();
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<StrokePathGeometry*>(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<StrokePathGeometry*>(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<Geometry> geom = Geometry::MakeFillPath(path);
auto contents = std::make_shared<SolidColorContents>();
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<float*>(&cover_color));
ImGui::ColorEdit4("Bounds color",
ImGui::ColorEdit4("Bounds color ",
reinterpret_cast<float*>(&bounds_color));
ImGui::SliderFloat2("Translation", offset, 0,
pass.GetRenderTargetSize().width);
@ -986,8 +997,10 @@ TEST_P(EntityTest, GaussianBlurFilter) {
} else {
auto fill = std::make_shared<SolidColorContents>();
fill->SetColor(input_color);
fill->SetGeometry(
Geometry::MakeFillPath(PathBuilder{}.AddRect(input_rect).TakePath()));
static std::unique_ptr<Geometry> 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<Geometry> geom =
Geometry::MakeFillPath(PathBuilder{}.AddRect(input_rect).TakePath());
auto contents = std::make_shared<SolidColorContents>();
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<Rect> target_contents_coverage =
target_contents->GetCoverage(entity);
if (target_contents_coverage.has_value()) {
bounds_entity.SetContents(SolidColorContents::Make(
static std::unique_ptr<Geometry> geom = Geometry::MakeFillPath(
PathBuilder{}
.AddRect(target_contents->GetCoverage(entity).value())
.TakePath(),
bounds_color));
bounds_entity.SetTransform(Matrix());
.TakePath());
auto contents = std::make_shared<SolidColorContents>();
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<float*>(&cover_color));
ImGui::ColorEdit4("Bounds color",
ImGui::ColorEdit4("Bounds color ",
reinterpret_cast<float*>(&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<Geometry> geom =
Geometry::MakeFillPath(PathBuilder{}.AddRect(input_rect).TakePath());
auto cover_contents = std::make_shared<SolidColorContents>();
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<Geometry> bounds_geom = Geometry::MakeFillPath(
PathBuilder{}
.AddRect(contents->GetCoverage(entity).value())
.TakePath());
auto bounds_contents = std::make_shared<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<ClipContents>();
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<ClipContents>();
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<ClipContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<PipelineDescriptor>* first_pipeline;
static std::unique_ptr<Geometry> geom = Geometry::MakeCover();
auto callback = [&](ContentContext& context, RenderPass& pass) -> bool {
EXPECT_EQ(runtime_stage->IsDirty(), expect_dirty);
auto contents = std::make_shared<RuntimeEffectContents>();
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<RuntimeEffectContents>();
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<RuntimeEffectContents>();
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<TextureContents>();
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<SolidColorContents>();
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<TiledTextureContents>();
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<SolidColorContents>();
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<SolidColorContents>();
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<SolidColorContents>();
contents->SetGeometry(Geometry::MakeFillPath(path));
static std::unique_ptr<Geometry> 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<SolidColorContents>();
static std::unique_ptr<SuperellipseGeometry> geom =
std::make_unique<SuperellipseGeometry>(Point{400, 400}, radius, degree,
alpha, beta);
contents->SetColor(color);
contents->SetGeometry(std::make_shared<SuperellipseGeometry>(
Point{400, 400}, radius, degree, alpha, beta));
contents->SetGeometry(geom.get());
Entity entity;
entity.SetContents(contents);

View File

@ -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)

View File

@ -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;

View File

@ -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<CoverGeometry>::value);
} // namespace impeller
#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_COVER_GEOMETRY_H_

View File

@ -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;

View File

@ -16,6 +16,8 @@ FillPathGeometry::FillPathGeometry(const Path& path,
std::optional<Rect> inner_rect)
: path_(path), inner_rect_(inner_rect) {}
FillPathGeometry::~FillPathGeometry() {}
GeometryResult FillPathGeometry::GetPositionBuffer(
const ContentContext& renderer,
const Entity& entity,

View File

@ -18,7 +18,7 @@ class FillPathGeometry final : public Geometry {
explicit FillPathGeometry(const Path& path,
std::optional<Rect> inner_rect = std::nullopt);
~FillPathGeometry() = default;
~FillPathGeometry() override;
// |Geometry|
bool CoversArea(const Matrix& transform, const Rect& rect) const override;

View File

@ -57,19 +57,19 @@ GeometryResult::Mode Geometry::GetResultMode() const {
return GeometryResult::Mode::kNormal;
}
std::shared_ptr<Geometry> Geometry::MakeFillPath(
std::unique_ptr<Geometry> Geometry::MakeFillPath(
const Path& path,
std::optional<Rect> inner_rect) {
return std::make_shared<FillPathGeometry>(path, inner_rect);
return std::make_unique<FillPathGeometry>(path, inner_rect);
}
std::shared_ptr<Geometry> Geometry::MakePointField(std::vector<Point> points,
std::unique_ptr<Geometry> Geometry::MakePointField(std::vector<Point> points,
Scalar radius,
bool round) {
return std::make_shared<PointFieldGeometry>(std::move(points), radius, round);
return std::make_unique<PointFieldGeometry>(std::move(points), radius, round);
}
std::shared_ptr<Geometry> Geometry::MakeStrokePath(const Path& path,
std::unique_ptr<Geometry> Geometry::MakeStrokePath(const Path& path,
Scalar stroke_width,
Scalar miter_limit,
Cap stroke_cap,
@ -78,43 +78,43 @@ std::shared_ptr<Geometry> Geometry::MakeStrokePath(const Path& path,
if (miter_limit < 0) {
miter_limit = 4.0;
}
return std::make_shared<StrokePathGeometry>(path, stroke_width, miter_limit,
return std::make_unique<StrokePathGeometry>(path, stroke_width, miter_limit,
stroke_cap, stroke_join);
}
std::shared_ptr<Geometry> Geometry::MakeCover() {
return std::make_shared<CoverGeometry>();
std::unique_ptr<Geometry> Geometry::MakeCover() {
return std::make_unique<CoverGeometry>();
}
std::shared_ptr<Geometry> Geometry::MakeRect(const Rect& rect) {
return std::make_shared<RectGeometry>(rect);
std::unique_ptr<Geometry> Geometry::MakeRect(const Rect& rect) {
return std::make_unique<RectGeometry>(rect);
}
std::shared_ptr<Geometry> Geometry::MakeOval(const Rect& rect) {
return std::make_shared<EllipseGeometry>(rect);
std::unique_ptr<Geometry> Geometry::MakeOval(const Rect& rect) {
return std::make_unique<EllipseGeometry>(rect);
}
std::shared_ptr<Geometry> Geometry::MakeLine(const Point& p0,
std::unique_ptr<Geometry> Geometry::MakeLine(const Point& p0,
const Point& p1,
Scalar width,
Cap cap) {
return std::make_shared<LineGeometry>(p0, p1, width, cap);
return std::make_unique<LineGeometry>(p0, p1, width, cap);
}
std::shared_ptr<Geometry> Geometry::MakeCircle(const Point& center,
std::unique_ptr<Geometry> Geometry::MakeCircle(const Point& center,
Scalar radius) {
return std::make_shared<CircleGeometry>(center, radius);
return std::make_unique<CircleGeometry>(center, radius);
}
std::shared_ptr<Geometry> Geometry::MakeStrokedCircle(const Point& center,
std::unique_ptr<Geometry> Geometry::MakeStrokedCircle(const Point& center,
Scalar radius,
Scalar stroke_width) {
return std::make_shared<CircleGeometry>(center, radius, stroke_width);
return std::make_unique<CircleGeometry>(center, radius, stroke_width);
}
std::shared_ptr<Geometry> Geometry::MakeRoundRect(const Rect& rect,
std::unique_ptr<Geometry> Geometry::MakeRoundRect(const Rect& rect,
const Size& radii) {
return std::make_shared<RoundRectGeometry>(rect, radii);
return std::make_unique<RoundRectGeometry>(rect, radii);
}
bool Geometry::CoversArea(const Matrix& transform, const Rect& rect) const {

View File

@ -54,39 +54,41 @@ static const GeometryResult kEmptyResult = {
class Geometry {
public:
static std::shared_ptr<Geometry> MakeFillPath(
virtual ~Geometry() {}
static std::unique_ptr<Geometry> MakeFillPath(
const Path& path,
std::optional<Rect> inner_rect = std::nullopt);
static std::shared_ptr<Geometry> MakeStrokePath(
static std::unique_ptr<Geometry> 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<Geometry> MakeCover();
static std::unique_ptr<Geometry> MakeCover();
static std::shared_ptr<Geometry> MakeRect(const Rect& rect);
static std::unique_ptr<Geometry> MakeRect(const Rect& rect);
static std::shared_ptr<Geometry> MakeOval(const Rect& rect);
static std::unique_ptr<Geometry> MakeOval(const Rect& rect);
static std::shared_ptr<Geometry> MakeLine(const Point& p0,
static std::unique_ptr<Geometry> MakeLine(const Point& p0,
const Point& p1,
Scalar width,
Cap cap);
static std::shared_ptr<Geometry> MakeCircle(const Point& center,
static std::unique_ptr<Geometry> MakeCircle(const Point& center,
Scalar radius);
static std::shared_ptr<Geometry> MakeStrokedCircle(const Point& center,
static std::unique_ptr<Geometry> MakeStrokedCircle(const Point& center,
Scalar radius,
Scalar stroke_width);
static std::shared_ptr<Geometry> MakeRoundRect(const Rect& rect,
static std::unique_ptr<Geometry> MakeRoundRect(const Rect& rect,
const Size& radii);
static std::shared_ptr<Geometry> MakePointField(std::vector<Point> points,
static std::unique_ptr<Geometry> MakePointField(std::vector<Point> points,
Scalar radius,
bool round);

View File

@ -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) {

View File

@ -5,7 +5,6 @@
#ifndef FLUTTER_IMPELLER_ENTITY_GEOMETRY_LINE_GEOMETRY_H_
#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_LINE_GEOMETRY_H_
#include <type_traits>
#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<LineGeometry>::value);
} // namespace impeller
#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_LINE_GEOMETRY_H_

View File

@ -15,6 +15,8 @@ PointFieldGeometry::PointFieldGeometry(std::vector<Point> points,
bool round)
: points_(std::move(points)), radius_(radius), round_(round) {}
PointFieldGeometry::~PointFieldGeometry() = default;
GeometryResult PointFieldGeometry::GetPositionBuffer(
const ContentContext& renderer,
const Entity& entity,

View File

@ -13,7 +13,7 @@ class PointFieldGeometry final : public Geometry {
public:
PointFieldGeometry(std::vector<Point> points, Scalar radius, bool round);
~PointFieldGeometry() = default;
~PointFieldGeometry() override;
private:
// |Geometry|

View File

@ -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 {

View File

@ -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<RectGeometry>::value);
} // namespace impeller
#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_RECT_GEOMETRY_H_

View File

@ -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,

View File

@ -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;

View File

@ -19,7 +19,7 @@ class StrokePathGeometry final : public Geometry {
Cap stroke_cap,
Join stroke_join);
~StrokePathGeometry();
~StrokePathGeometry() override;
Scalar GetStrokeWidth() const;

View File

@ -21,6 +21,8 @@ SuperellipseGeometry::SuperellipseGeometry(const Point& center,
alpha_(alpha),
beta_(beta) {}
SuperellipseGeometry::~SuperellipseGeometry() {}
GeometryResult SuperellipseGeometry::GetPositionBuffer(
const ContentContext& renderer,
const Entity& entity,

View File

@ -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;