Skip to content

Commit 8b881c6

Browse files
bderodnfield
authored andcommitted
Compute text coverage; use blend mode in savelayer; conservative pass collapse/elision behavior (flutter#129)
1 parent a4599bf commit 8b881c6

File tree

10 files changed

+70
-5
lines changed

10 files changed

+70
-5
lines changed

impeller/aiks/aiks_unittests.cc

+21
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,27 @@ TEST_F(AiksTest, CanRenderEmojiTextFrame) {
418418
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
419419
}
420420

421+
TEST_F(AiksTest, CanRenderTextInSaveLayer) {
422+
Canvas canvas;
423+
canvas.DrawPaint({.color = Color::White()});
424+
canvas.Translate({100, 100});
425+
canvas.Scale(Vector2{0.5, 0.5});
426+
427+
// Blend the layer with the parent pass using kClear to expose the coverage.
428+
canvas.SaveLayer({.blend_mode = Entity::BlendMode::kClear});
429+
ASSERT_TRUE(RenderTextInCanvas(
430+
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
431+
"Roboto-Regular.ttf"));
432+
canvas.Restore();
433+
434+
// Render the text again over the cleared coverage rect.
435+
ASSERT_TRUE(RenderTextInCanvas(
436+
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
437+
"Roboto-Regular.ttf"));
438+
439+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
440+
}
441+
421442
TEST_F(AiksTest, CanDrawPaint) {
422443
Paint paint;
423444
paint.color = Color::MediumTurquoise();

impeller/aiks/canvas.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,10 @@ void Canvas::DrawCircle(Point center, Scalar radius, Paint paint) {
141141

142142
void Canvas::SaveLayer(Paint paint, std::optional<Rect> bounds) {
143143
GetCurrentPass().SetDelegate(
144-
std::make_unique<PaintPassDelegate>(std::move(paint), bounds));
144+
std::make_unique<PaintPassDelegate>(paint, bounds));
145145

146146
Save(true);
147+
GetCurrentPass().SetBlendMode(paint.blend_mode);
147148

148149
if (bounds.has_value()) {
149150
// Render target switches due to a save layer can be elided. In such cases

impeller/aiks/paint_pass_delegate.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ std::optional<Rect> PaintPassDelegate::GetCoverageRect() {
2222

2323
// |EntityPassDelgate|
2424
bool PaintPassDelegate::CanElide() {
25-
return paint_.color.IsTransparent();
25+
return paint_.blend_mode == Entity::BlendMode::kDestination;
2626
}
2727

2828
// |EntityPassDelgate|
2929
bool PaintPassDelegate::CanCollapseIntoParentPass() {
30-
return paint_.color.IsOpaque();
30+
return false;
3131
}
3232

3333
// |EntityPassDelgate|

impeller/entity/contents/text_contents.cc

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "impeller/entity/contents/text_contents.h"
66

7+
#include <optional>
8+
79
#include "impeller/entity/contents/content_context.h"
810
#include "impeller/entity/entity.h"
911
#include "impeller/geometry/path_builder.h"
@@ -48,6 +50,14 @@ void TextContents::SetColor(Color color) {
4850
color_ = color;
4951
}
5052

53+
std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
54+
auto bounds = frame_.GetBounds();
55+
if (!bounds.has_value()) {
56+
return std::nullopt;
57+
}
58+
return bounds->TransformBounds(entity.GetTransformation());
59+
}
60+
5161
bool TextContents::Render(const ContentContext& renderer,
5262
const Entity& entity,
5363
RenderPass& pass) const {

impeller/entity/contents/text_contents.h

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class TextContents final : public Contents {
3434

3535
void SetColor(Color color);
3636

37+
// |Contents|
38+
std::optional<Rect> GetCoverage(const Entity& entity) const override;
39+
3740
// |Contents|
3841
bool Render(const ContentContext& renderer,
3942
const Entity& entity,

impeller/entity/entity_pass.cc

+5
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ bool EntityPass::Render(ContentContext& renderer,
210210
.TakePath());
211211
entity.SetContents(std::move(offscreen_texture_contents));
212212
entity.SetStencilDepth(stencil_depth_);
213+
entity.SetBlendMode(subpass->blend_mode_);
213214
// Once we have filters being applied for SaveLayer, some special sauce
214215
// may be needed here (or in PaintPassDelegate) to ensure the filter
215216
// parameters are transformed by the `xformation_` matrix, while continuing
@@ -257,4 +258,8 @@ void EntityPass::SetStencilDepth(size_t stencil_depth) {
257258
stencil_depth_ = stencil_depth;
258259
}
259260

261+
void EntityPass::SetBlendMode(Entity::BlendMode blend_mode) {
262+
blend_mode_ = blend_mode;
263+
}
264+
260265
} // namespace impeller

impeller/entity/entity_pass.h

+3
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,15 @@ class EntityPass {
5858

5959
void SetStencilDepth(size_t stencil_depth);
6060

61+
void SetBlendMode(Entity::BlendMode blend_mode);
62+
6163
private:
6264
Entities entities_;
6365
Subpasses subpasses_;
6466
EntityPass* superpass_ = nullptr;
6567
Matrix xformation_;
6668
size_t stencil_depth_ = 0u;
69+
Entity::BlendMode blend_mode_ = Entity::BlendMode::kSourceOver;
6770
std::unique_ptr<EntityPassDelegate> delegate_ =
6871
EntityPassDelegate::MakeDefault();
6972
std::shared_ptr<LazyGlyphAtlas> lazy_glyph_atlas_ =

impeller/typographer/backends/skia/text_frame_skia.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ static Font ToFont(const SkFont& font, Scalar scale) {
2929
return Font{std::move(typeface), std::move(metrics)};
3030
}
3131

32-
TextFrame TextFrameFromTextBlob(sk_sp<SkTextBlob> blob,
33-
Scalar scale) {
32+
TextFrame TextFrameFromTextBlob(sk_sp<SkTextBlob> blob, Scalar scale) {
3433
if (!blob) {
3534
return {};
3635
}

impeller/typographer/text_frame.cc

+15
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ TextFrame::TextFrame() = default;
1010

1111
TextFrame::~TextFrame() = default;
1212

13+
std::optional<Rect> TextFrame::GetBounds() const {
14+
std::optional<Rect> result;
15+
16+
for (const auto& run : runs_) {
17+
const auto glyph_bounds = run.GetFont().GetMetrics().GetBoundingBox();
18+
for (const auto& glyph_position : run.GetGlyphPositions()) {
19+
Vector2 position = glyph_position.position * Vector2();
20+
Rect glyph_rect = Rect(position + glyph_bounds.origin, glyph_bounds.size);
21+
result = result.has_value() ? result->Union(glyph_rect) : glyph_rect;
22+
}
23+
}
24+
25+
return result;
26+
}
27+
1328
bool TextFrame::AddTextRun(TextRun run) {
1429
if (!run.IsValid()) {
1530
return false;

impeller/typographer/text_frame.h

+8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ class TextFrame {
2121

2222
~TextFrame();
2323

24+
//----------------------------------------------------------------------------
25+
/// @brief The conservative bounding box for this text frame.
26+
///
27+
/// @return The bounds rectangle. If there are no glyphs in this text
28+
/// frame, std::nullopt is returned.
29+
///
30+
std::optional<Rect> GetBounds() const;
31+
2432
//----------------------------------------------------------------------------
2533
/// @brief The number of runs in this text frame.
2634
///

0 commit comments

Comments
 (0)