Skip to content

Commit 3ac895e

Browse files
[Impeller] support for foreground shaders on text (flutter#40193)
[Impeller] support for foreground shaders on text
1 parent bb1ca8f commit 3ac895e

11 files changed

+215
-10
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,8 @@ ORIGIN: ../../../flutter/impeller/entity/contents/clip_contents.cc + ../../../fl
11211121
ORIGIN: ../../../flutter/impeller/entity/contents/clip_contents.h + ../../../flutter/LICENSE
11221122
ORIGIN: ../../../flutter/impeller/entity/contents/color_source_contents.cc + ../../../flutter/LICENSE
11231123
ORIGIN: ../../../flutter/impeller/entity/contents/color_source_contents.h + ../../../flutter/LICENSE
1124+
ORIGIN: ../../../flutter/impeller/entity/contents/color_source_text_contents.cc + ../../../flutter/LICENSE
1125+
ORIGIN: ../../../flutter/impeller/entity/contents/color_source_text_contents.h + ../../../flutter/LICENSE
11241126
ORIGIN: ../../../flutter/impeller/entity/contents/content_context.cc + ../../../flutter/LICENSE
11251127
ORIGIN: ../../../flutter/impeller/entity/contents/content_context.h + ../../../flutter/LICENSE
11261128
ORIGIN: ../../../flutter/impeller/entity/contents/contents.cc + ../../../flutter/LICENSE
@@ -3655,6 +3657,8 @@ FILE: ../../../flutter/impeller/entity/contents/clip_contents.cc
36553657
FILE: ../../../flutter/impeller/entity/contents/clip_contents.h
36563658
FILE: ../../../flutter/impeller/entity/contents/color_source_contents.cc
36573659
FILE: ../../../flutter/impeller/entity/contents/color_source_contents.h
3660+
FILE: ../../../flutter/impeller/entity/contents/color_source_text_contents.cc
3661+
FILE: ../../../flutter/impeller/entity/contents/color_source_text_contents.h
36583662
FILE: ../../../flutter/impeller/entity/contents/content_context.cc
36593663
FILE: ../../../flutter/impeller/entity/contents/content_context.h
36603664
FILE: ../../../flutter/impeller/entity/contents/contents.cc

impeller/aiks/canvas.cc

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "impeller/aiks/paint_pass_delegate.h"
1313
#include "impeller/entity/contents/atlas_contents.h"
1414
#include "impeller/entity/contents/clip_contents.h"
15+
#include "impeller/entity/contents/color_source_text_contents.h"
1516
#include "impeller/entity/contents/rrect_shadow_contents.h"
1617
#include "impeller/entity/contents/text_contents.h"
1718
#include "impeller/entity/contents/texture_contents.h"
@@ -380,16 +381,40 @@ void Canvas::DrawTextFrame(const TextFrame& text_frame,
380381
const Paint& paint) {
381382
lazy_glyph_atlas_->AddTextFrame(text_frame);
382383

384+
Entity entity;
385+
entity.SetStencilDepth(GetStencilDepth());
386+
entity.SetBlendMode(paint.blend_mode);
387+
383388
auto text_contents = std::make_shared<TextContents>();
384389
text_contents->SetTextFrame(text_frame);
385390
text_contents->SetGlyphAtlas(lazy_glyph_atlas_);
391+
392+
if (paint.color_source.has_value()) {
393+
auto& source = paint.color_source.value();
394+
auto color_text_contents = std::make_shared<ColorSourceTextContents>();
395+
entity.SetTransformation(GetCurrentTransformation());
396+
397+
Entity test;
398+
auto cvg = text_contents->GetCoverage(test).value();
399+
color_text_contents->SetTextPosition(cvg.origin + position);
400+
401+
text_contents->SetInverseMatrix(
402+
Matrix::MakeTranslation(Vector3(-cvg.origin.x, -cvg.origin.y, 0)));
403+
color_text_contents->SetTextContents(std::move(text_contents));
404+
color_text_contents->SetColorSourceContents(source());
405+
406+
entity.SetContents(
407+
paint.WithFilters(std::move(color_text_contents), false));
408+
409+
GetCurrentPass().AddEntity(entity);
410+
return;
411+
}
412+
386413
text_contents->SetColor(paint.color);
387414

388-
Entity entity;
389415
entity.SetTransformation(GetCurrentTransformation() *
390416
Matrix::MakeTranslation(position));
391-
entity.SetStencilDepth(GetStencilDepth());
392-
entity.SetBlendMode(paint.blend_mode);
417+
393418
entity.SetContents(paint.WithFilters(std::move(text_contents), true));
394419

395420
GetCurrentPass().AddEntity(entity);

impeller/display_list/display_list_unittests.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,25 @@ TEST_P(DisplayListTest, CanDrawTextBlob) {
5757
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
5858
}
5959

60+
TEST_P(DisplayListTest, CanDrawTextBlobWithGradient) {
61+
flutter::DisplayListBuilder builder;
62+
63+
std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
64+
flutter::DlColor::kRed()};
65+
const float stops[2] = {0.0, 1.0};
66+
67+
auto linear = flutter::DlColorSource::MakeLinear({0.0, 0.0}, {300.0, 300.0},
68+
2, colors.data(), stops,
69+
flutter::DlTileMode::kClamp);
70+
flutter::DlPaint paint;
71+
paint.setColorSource(linear);
72+
73+
builder.DrawTextBlob(
74+
SkTextBlob::MakeFromString("Hello World", CreateTestFont()), 100, 100,
75+
paint);
76+
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
77+
}
78+
6079
TEST_P(DisplayListTest, CanDrawTextWithSaveLayer) {
6180
flutter::DisplayListBuilder builder;
6281
builder.setColor(SK_ColorRED);

impeller/entity/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ impeller_component("entity") {
120120
"contents/clip_contents.h",
121121
"contents/color_source_contents.cc",
122122
"contents/color_source_contents.h",
123+
"contents/color_source_text_contents.cc",
124+
"contents/color_source_text_contents.h",
123125
"contents/content_context.cc",
124126
"contents/content_context.h",
125127
"contents/contents.cc",

impeller/entity/contents/color_source_contents.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class ColorSourceContents : public Contents {
2222

2323
void SetEffectTransform(Matrix matrix);
2424

25+
const Matrix& GetInverseMatrix() const;
26+
2527
void SetAlpha(Scalar alpha);
2628

2729
// |Contents|
@@ -34,8 +36,6 @@ class ColorSourceContents : public Contents {
3436
protected:
3537
const std::shared_ptr<Geometry>& GetGeometry() const;
3638

37-
const Matrix& GetInverseMatrix() const;
38-
3939
Scalar GetAlpha() const;
4040

4141
private:
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "impeller/entity/contents/color_source_text_contents.h"
6+
7+
#include "impeller/entity/contents/content_context.h"
8+
#include "impeller/entity/contents/texture_contents.h"
9+
#include "impeller/renderer/render_pass.h"
10+
11+
namespace impeller {
12+
13+
ColorSourceTextContents::ColorSourceTextContents() = default;
14+
15+
ColorSourceTextContents::~ColorSourceTextContents() = default;
16+
17+
void ColorSourceTextContents::SetTextContents(
18+
std::shared_ptr<TextContents> text_contents) {
19+
text_contents_ = std::move(text_contents);
20+
}
21+
22+
void ColorSourceTextContents::SetColorSourceContents(
23+
std::shared_ptr<ColorSourceContents> color_source_contents) {
24+
color_source_contents_ = std::move(color_source_contents);
25+
}
26+
27+
std::optional<Rect> ColorSourceTextContents::GetCoverage(
28+
const Entity& entity) const {
29+
return text_contents_->GetCoverage(entity);
30+
}
31+
32+
void ColorSourceTextContents::SetTextPosition(Point position) {
33+
position_ = position;
34+
}
35+
36+
bool ColorSourceTextContents::Render(const ContentContext& renderer,
37+
const Entity& entity,
38+
RenderPass& pass) const {
39+
auto coverage = text_contents_->GetCoverage(entity);
40+
if (!coverage.has_value()) {
41+
return true;
42+
}
43+
auto transform = entity.GetTransformation();
44+
45+
text_contents_->SetColor(Color::Black());
46+
color_source_contents_->SetGeometry(
47+
Geometry::MakeRect(Rect::MakeSize(coverage->size)));
48+
49+
// offset the color source so it behaves as if it were drawn in the original
50+
// position.
51+
auto effect_transform =
52+
color_source_contents_->GetInverseMatrix().Invert().Translate(-position_);
53+
color_source_contents_->SetEffectTransform(effect_transform);
54+
55+
auto new_texture = renderer.MakeSubpass(
56+
"Text Color Blending", ISize::Ceil(coverage.value().size),
57+
[&](const ContentContext& context, RenderPass& pass) {
58+
Entity sub_entity;
59+
sub_entity.SetTransformation(transform);
60+
sub_entity.SetContents(text_contents_);
61+
sub_entity.SetBlendMode(BlendMode::kSource);
62+
if (!sub_entity.Render(context, pass)) {
63+
return false;
64+
}
65+
66+
sub_entity.SetContents(color_source_contents_);
67+
sub_entity.SetBlendMode(BlendMode::kSourceIn);
68+
return sub_entity.Render(context, pass);
69+
});
70+
if (!new_texture) {
71+
return false;
72+
}
73+
74+
auto dest_rect = Rect::MakeSize(new_texture->GetSize())
75+
.TransformBounds(transform.Invert())
76+
.Shift(position_);
77+
78+
auto texture_contents = TextureContents::MakeRect(dest_rect);
79+
texture_contents->SetTexture(new_texture);
80+
texture_contents->SetSourceRect(Rect::MakeSize(new_texture->GetSize()));
81+
return texture_contents->Render(renderer, entity, pass);
82+
}
83+
84+
} // namespace impeller
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include <functional>
8+
#include <memory>
9+
#include <variant>
10+
#include <vector>
11+
12+
#include "flutter/fml/macros.h"
13+
#include "impeller/entity/contents/color_source_contents.h"
14+
#include "impeller/entity/contents/contents.h"
15+
#include "impeller/entity/contents/text_contents.h"
16+
17+
namespace impeller {
18+
19+
class ColorSourceTextContents final : public Contents {
20+
public:
21+
ColorSourceTextContents();
22+
23+
~ColorSourceTextContents();
24+
25+
void SetTextContents(std::shared_ptr<TextContents> text_contents);
26+
27+
void SetColorSourceContents(
28+
std::shared_ptr<ColorSourceContents> color_source_contents);
29+
30+
void SetTextPosition(Point position);
31+
32+
// |Contents|
33+
std::optional<Rect> GetCoverage(const Entity& entity) const override;
34+
35+
// |Contents|
36+
bool Render(const ContentContext& renderer,
37+
const Entity& entity,
38+
RenderPass& pass) const override;
39+
40+
private:
41+
Point position_;
42+
std::shared_ptr<TextContents> text_contents_;
43+
std::shared_ptr<ColorSourceContents> color_source_contents_;
44+
45+
FML_DISALLOW_COPY_AND_ASSIGN(ColorSourceTextContents);
46+
};
47+
48+
} // namespace impeller

impeller/entity/contents/text_contents.cc

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ void TextContents::SetColor(Color color) {
5050
color_ = color;
5151
}
5252

53+
void TextContents::SetInverseMatrix(Matrix matrix) {
54+
inverse_matrix_ = matrix;
55+
}
56+
5357
std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
5458
auto bounds = frame_.GetBounds();
5559
if (!bounds.has_value()) {
@@ -71,6 +75,7 @@ static bool CommonRender(
7175
RenderPass& pass,
7276
const Color& color,
7377
const TextFrame& frame,
78+
const Matrix& inverse_matrix,
7479
std::shared_ptr<GlyphAtlas>
7580
atlas, // NOLINT(performance-unnecessary-value-param)
7681
Command& cmd) {
@@ -159,8 +164,10 @@ static bool CommonRender(
159164

160165
auto uv_scaler_a = atlas_glyph_pos->size / atlas_size;
161166
auto uv_scaler_b = (Point::Round(atlas_glyph_pos->origin) / atlas_size);
162-
auto translation = Matrix::MakeTranslation(
163-
Vector3(offset_glyph_position.x, offset_glyph_position.y, 0));
167+
auto translation =
168+
Matrix::MakeTranslation(
169+
Vector3(offset_glyph_position.x, offset_glyph_position.y, 0)) *
170+
inverse_matrix;
164171

165172
for (const auto& point : unit_points) {
166173
typename VS::PerVertexData vtx;
@@ -209,8 +216,8 @@ bool TextContents::RenderSdf(const ContentContext& renderer,
209216
cmd.pipeline = renderer.GetGlyphAtlasSdfPipeline(opts);
210217
cmd.stencil_reference = entity.GetStencilDepth();
211218

212-
return CommonRender<GlyphAtlasSdfPipeline>(renderer, entity, pass, color_,
213-
frame_, atlas, cmd);
219+
return CommonRender<GlyphAtlasSdfPipeline>(
220+
renderer, entity, pass, color_, frame_, inverse_matrix_, atlas, cmd);
214221
}
215222

216223
bool TextContents::Render(const ContentContext& renderer,
@@ -245,7 +252,7 @@ bool TextContents::Render(const ContentContext& renderer,
245252
cmd.stencil_reference = entity.GetStencilDepth();
246253

247254
return CommonRender<GlyphAtlasPipeline>(renderer, entity, pass, color_,
248-
frame_, atlas, cmd);
255+
frame_, inverse_matrix_, atlas, cmd);
249256
}
250257

251258
} // namespace impeller

impeller/entity/contents/text_contents.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class TextContents final : public Contents {
3232

3333
void SetColor(Color color);
3434

35+
void SetInverseMatrix(Matrix matrix);
36+
3537
// |Contents|
3638
std::optional<Rect> GetCoverage(const Entity& entity) const override;
3739

@@ -49,6 +51,7 @@ class TextContents final : public Contents {
4951
TextFrame frame_;
5052
Color color_;
5153
mutable std::shared_ptr<LazyGlyphAtlas> lazy_atlas_;
54+
Matrix inverse_matrix_;
5255

5356
std::shared_ptr<GlyphAtlas> ResolveAtlas(
5457
GlyphAtlas::Type type,

impeller/geometry/geometry_unittests.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,6 +1646,13 @@ TEST(GeometryTest, RectGetPoints) {
16461646
ASSERT_POINT_NEAR(points[3], Point(400, 600));
16471647
}
16481648

1649+
TEST(GeometryTest, RectShift) {
1650+
auto r = Rect::MakeLTRB(0, 0, 100, 100);
1651+
1652+
ASSERT_EQ(r.Shift(Point(10, 5)), Rect::MakeLTRB(10, 5, 110, 105));
1653+
ASSERT_EQ(r.Shift(Point(-10, -5)), Rect::MakeLTRB(-10, -5, 90, 95));
1654+
}
1655+
16491656
TEST(GeometryTest, RectGetTransformedPoints) {
16501657
Rect r(100, 200, 300, 400);
16511658
auto points = r.GetTransformedPoints(Matrix::MakeTranslation({10, 20}));

impeller/geometry/rect.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,12 @@ struct TRect {
238238

239239
return *this;
240240
}
241+
242+
/// @brief Returns a new rectangle translated by the given offset.
243+
constexpr TRect<T> Shift(TPoint<T> offset) const {
244+
return TRect(origin.x + offset.x, origin.y + offset.y, size.width,
245+
size.height);
246+
}
241247
};
242248

243249
using Rect = TRect<Scalar>;

0 commit comments

Comments
 (0)