Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 4cbfe42

Browse files
Build display lists from SkParagraph output using the ParagraphPainter interface (#37087)
SkPaint does not provide APIs for extracting the definitions of some attributes such as filters. The engine will instead use DlPaint to describe how text foregrounds and backgrounds will be painted. The DlPaint objects will be represented as PaintIDs in SkParagraph text styles. The ParagraphPainter will then map the PaintIDs back to the original DlPaint objects.
1 parent 645d4e3 commit 4cbfe42

15 files changed

+291
-103
lines changed

display_list/display_list_builder.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,13 @@ void DisplayListBuilder::drawTextBlob(const sk_sp<SkTextBlob> blob,
10711071
Push<DrawTextBlobOp>(0, 1, blob, x, y);
10721072
CheckLayerOpacityCompatibility();
10731073
}
1074+
void DisplayListBuilder::drawTextBlob(const sk_sp<SkTextBlob>& blob,
1075+
SkScalar x,
1076+
SkScalar y,
1077+
const DlPaint& paint) {
1078+
setAttributesFromDlPaint(paint, DisplayListOpFlags::kDrawTextBlobFlags);
1079+
drawTextBlob(blob, x, y);
1080+
}
10741081
void DisplayListBuilder::drawShadow(const SkPath& path,
10751082
const DlColor color,
10761083
const SkScalar elevation,

display_list/display_list_builder.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ class DisplayListBuilder final : public virtual Dispatcher,
334334
void drawTextBlob(const sk_sp<SkTextBlob> blob,
335335
SkScalar x,
336336
SkScalar y) override;
337+
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
338+
SkScalar x,
339+
SkScalar y,
340+
const DlPaint& paint);
337341
void drawShadow(const SkPath& path,
338342
const DlColor color,
339343
const SkScalar elevation,
@@ -503,7 +507,6 @@ class DisplayListBuilder final : public virtual Dispatcher,
503507
void onSetColorFilter(const DlColorFilter* filter);
504508
void onSetPathEffect(const DlPathEffect* effect);
505509
void onSetMaskFilter(const DlMaskFilter* filter);
506-
void onSetMaskBlurFilter(SkBlurStyle style, SkScalar sigma);
507510

508511
DlPaint current_;
509512
// If |current_blender_| is set then ignore |current_.getBlendMode()|

display_list/display_list_mask_filter.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ class DlMaskFilter
5858
// filter is then used to combine those colors.
5959
class DlBlurMaskFilter final : public DlMaskFilter {
6060
public:
61-
DlBlurMaskFilter(SkBlurStyle style, SkScalar sigma)
62-
: style_(style), sigma_(sigma) {}
61+
DlBlurMaskFilter(SkBlurStyle style, SkScalar sigma, bool respect_ctm = true)
62+
: style_(style), sigma_(sigma), respect_ctm_(respect_ctm) {}
6363
DlBlurMaskFilter(const DlBlurMaskFilter& filter)
64-
: DlBlurMaskFilter(filter.style_, filter.sigma_) {}
64+
: DlBlurMaskFilter(filter.style_, filter.sigma_, filter.respect_ctm_) {}
6565
DlBlurMaskFilter(const DlBlurMaskFilter* filter)
66-
: DlBlurMaskFilter(filter->style_, filter->sigma_) {}
66+
: DlBlurMaskFilter(filter->style_, filter->sigma_, filter->respect_ctm_) {
67+
}
6768

6869
DlMaskFilterType type() const override { return DlMaskFilterType::kBlur; }
6970
size_t size() const override { return sizeof(*this); }
@@ -73,24 +74,29 @@ class DlBlurMaskFilter final : public DlMaskFilter {
7374
}
7475

7576
sk_sp<SkMaskFilter> skia_object() const override {
76-
return SkMaskFilter::MakeBlur(style_, sigma_);
77+
return SkMaskFilter::MakeBlur(style_, sigma_, respect_ctm_);
7778
}
7879

7980
const DlBlurMaskFilter* asBlur() const override { return this; }
8081

8182
SkBlurStyle style() const { return style_; }
8283
SkScalar sigma() const { return sigma_; }
84+
bool respectCTM() const { return respect_ctm_; }
8385

8486
protected:
8587
bool equals_(DlMaskFilter const& other) const override {
8688
FML_DCHECK(other.type() == DlMaskFilterType::kBlur);
8789
auto that = static_cast<DlBlurMaskFilter const*>(&other);
88-
return style_ == that->style_ && sigma_ == that->sigma_;
90+
return style_ == that->style_ && sigma_ == that->sigma_ &&
91+
respect_ctm_ == that->respect_ctm_;
8992
}
9093

9194
private:
9295
SkBlurStyle style_;
9396
SkScalar sigma_;
97+
// Added for backward compatibility with Flutter text shadow rendering which
98+
// uses Skia blur filters with this flag set to false.
99+
bool respect_ctm_;
94100
};
95101

96102
// A wrapper class for a Skia MaskFilter of unknown type. The above 4 types

display_list/display_list_test_utils.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,15 +284,15 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
284284
}},
285285
{"SetMaskFilter",
286286
{
287-
{0, 24, 0, 0,
287+
{0, 32, 0, 0,
288288
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter1); }},
289-
{0, 24, 0, 0,
289+
{0, 32, 0, 0,
290290
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter2); }},
291-
{0, 24, 0, 0,
291+
{0, 32, 0, 0,
292292
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter3); }},
293-
{0, 24, 0, 0,
293+
{0, 32, 0, 0,
294294
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter4); }},
295-
{0, 24, 0, 0,
295+
{0, 32, 0, 0,
296296
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter5); }},
297297
{0, 0, 0, 0,
298298
[](DisplayListBuilder& b) { b.setMaskFilter(nullptr); }},

lib/ui/painting/canvas.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ class Canvas : public RefCountedDartWrappable<Canvas>, DisplayListOpFlags {
190190
SkCanvas* canvas() const { return canvas_; }
191191
void Invalidate();
192192

193+
DisplayListBuilder* builder() {
194+
return display_list_recorder_ ? display_list_recorder_->builder().get()
195+
: nullptr;
196+
}
197+
193198
private:
194199
explicit Canvas(SkCanvas* canvas);
195200

@@ -205,9 +210,6 @@ class Canvas : public RefCountedDartWrappable<Canvas>, DisplayListOpFlags {
205210
// paint attributes from an SkPaint and an operation type as well as access
206211
// to the raw DisplayListBuilder for emitting custom rendering operations.
207212
sk_sp<DisplayListCanvasRecorder> display_list_recorder_;
208-
DisplayListBuilder* builder() {
209-
return display_list_recorder_->builder().get();
210-
}
211213
};
212214

213215
} // namespace flutter

lib/ui/text/paragraph.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,15 @@ void Paragraph::paint(Canvas* canvas, double x, double y) {
6464
return;
6565
}
6666

67-
SkCanvas* sk_canvas = canvas->canvas();
68-
if (!sk_canvas) {
67+
DisplayListBuilder* builder = canvas->builder();
68+
if (builder && m_paragraph->Paint(builder, x, y)) {
6969
return;
7070
}
71-
m_paragraph->Paint(sk_canvas, x, y);
71+
// Fall back to SkCanvas if painting to DisplayListBuilder is not supported.
72+
SkCanvas* sk_canvas = canvas->canvas();
73+
if (sk_canvas) {
74+
m_paragraph->Paint(sk_canvas, x, y);
75+
}
7276
}
7377

7478
static tonic::Float32List EncodeTextBoxes(

lib/ui/text/paragraph_builder.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ void ParagraphBuilder::pushStyle(const tonic::Int32List& encoded,
472472
SkPaint sk_paint;
473473
style.has_background = true;
474474
style.background = *background.paint(sk_paint);
475+
DlPaint dl_paint;
476+
background.toDlPaint(dl_paint);
477+
style.background_dl = dl_paint;
475478
}
476479
}
477480

@@ -481,6 +484,9 @@ void ParagraphBuilder::pushStyle(const tonic::Int32List& encoded,
481484
SkPaint sk_paint;
482485
style.has_foreground = true;
483486
style.foreground = *foreground.paint(sk_paint);
487+
DlPaint dl_paint;
488+
foreground.toDlPaint(dl_paint);
489+
style.foreground_dl = dl_paint;
484490
}
485491
}
486492

third_party/txt/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ source_set("txt") {
143143
configs += [ ":define_skshaper" ]
144144

145145
public_deps = [
146+
"//flutter/display_list",
146147
"//flutter/fml",
147148
"//third_party/harfbuzz",
148149
"//third_party/icu",

third_party/txt/src/skia/paragraph_builder_skia.cc

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,68 @@ SkFontStyle MakeSkFontStyle(txt::FontWeight font_weight,
4242
: SkFontStyle::Slant::kItalic_Slant);
4343
}
4444

45-
skt::ParagraphStyle TxtToSkia(const ParagraphStyle& txt) {
45+
} // anonymous namespace
46+
47+
ParagraphBuilderSkia::ParagraphBuilderSkia(
48+
const ParagraphStyle& style,
49+
std::shared_ptr<FontCollection> font_collection)
50+
: base_style_(style.GetTextStyle()) {
51+
builder_ = skt::ParagraphBuilder::make(
52+
TxtToSkia(style), font_collection->CreateSktFontCollection());
53+
}
54+
55+
ParagraphBuilderSkia::~ParagraphBuilderSkia() = default;
56+
57+
void ParagraphBuilderSkia::PushStyle(const TextStyle& style) {
58+
builder_->pushStyle(TxtToSkia(style));
59+
txt_style_stack_.push(style);
60+
}
61+
62+
void ParagraphBuilderSkia::Pop() {
63+
builder_->pop();
64+
txt_style_stack_.pop();
65+
}
66+
67+
const TextStyle& ParagraphBuilderSkia::PeekStyle() {
68+
return txt_style_stack_.empty() ? base_style_ : txt_style_stack_.top();
69+
}
70+
71+
void ParagraphBuilderSkia::AddText(const std::u16string& text) {
72+
builder_->addText(text);
73+
}
74+
75+
void ParagraphBuilderSkia::AddPlaceholder(PlaceholderRun& span) {
76+
skt::PlaceholderStyle placeholder_style;
77+
placeholder_style.fHeight = span.height;
78+
placeholder_style.fWidth = span.width;
79+
placeholder_style.fBaseline = static_cast<skt::TextBaseline>(span.baseline);
80+
placeholder_style.fBaselineOffset = span.baseline_offset;
81+
placeholder_style.fAlignment =
82+
static_cast<skt::PlaceholderAlignment>(span.alignment);
83+
84+
builder_->addPlaceholder(placeholder_style);
85+
}
86+
87+
std::unique_ptr<Paragraph> ParagraphBuilderSkia::Build() {
88+
return std::make_unique<ParagraphSkia>(builder_->Build(),
89+
std::move(dl_paints_));
90+
}
91+
92+
skt::ParagraphPainter::PaintID ParagraphBuilderSkia::CreatePaintID(
93+
const flutter::DlPaint& dl_paint) {
94+
dl_paints_.push_back(dl_paint);
95+
return dl_paints_.size() - 1;
96+
}
97+
98+
skt::ParagraphStyle ParagraphBuilderSkia::TxtToSkia(const ParagraphStyle& txt) {
4699
skt::ParagraphStyle skia;
47100
skt::TextStyle text_style;
48101

102+
// Convert the default color of an SkParagraph text style into a DlPaint.
103+
flutter::DlPaint dl_paint;
104+
dl_paint.setColor(text_style.getColor());
105+
text_style.setForegroundPaintID(CreatePaintID(dl_paint));
106+
49107
text_style.setFontStyle(MakeSkFontStyle(txt.font_weight, txt.font_style));
50108
text_style.setFontSize(SkDoubleToScalar(txt.font_size));
51109
text_style.setHeight(SkDoubleToScalar(txt.height));
@@ -84,7 +142,7 @@ skt::ParagraphStyle TxtToSkia(const ParagraphStyle& txt) {
84142
return skia;
85143
}
86144

87-
skt::TextStyle TxtToSkia(const TextStyle& txt) {
145+
skt::TextStyle ParagraphBuilderSkia::TxtToSkia(const TextStyle& txt) {
88146
skt::TextStyle skia;
89147

90148
skia.setColor(txt.color);
@@ -112,10 +170,14 @@ skt::TextStyle TxtToSkia(const TextStyle& txt) {
112170

113171
skia.setLocale(SkString(txt.locale.c_str()));
114172
if (txt.has_background) {
115-
skia.setBackgroundColor(txt.background);
173+
skia.setBackgroundPaintID(CreatePaintID(txt.background_dl));
116174
}
117175
if (txt.has_foreground) {
118-
skia.setForegroundColor(txt.foreground);
176+
skia.setForegroundPaintID(CreatePaintID(txt.foreground_dl));
177+
} else {
178+
flutter::DlPaint dl_paint;
179+
dl_paint.setColor(txt.color);
180+
skia.setForegroundPaintID(CreatePaintID(dl_paint));
119181
}
120182

121183
skia.resetFontFeatures();
@@ -153,50 +215,4 @@ skt::TextStyle TxtToSkia(const TextStyle& txt) {
153215
return skia;
154216
}
155217

156-
} // anonymous namespace
157-
158-
ParagraphBuilderSkia::ParagraphBuilderSkia(
159-
const ParagraphStyle& style,
160-
std::shared_ptr<FontCollection> font_collection)
161-
: builder_(skt::ParagraphBuilder::make(
162-
TxtToSkia(style),
163-
font_collection->CreateSktFontCollection())),
164-
base_style_(style.GetTextStyle()) {}
165-
166-
ParagraphBuilderSkia::~ParagraphBuilderSkia() = default;
167-
168-
void ParagraphBuilderSkia::PushStyle(const TextStyle& style) {
169-
builder_->pushStyle(TxtToSkia(style));
170-
txt_style_stack_.push(style);
171-
}
172-
173-
void ParagraphBuilderSkia::Pop() {
174-
builder_->pop();
175-
txt_style_stack_.pop();
176-
}
177-
178-
const TextStyle& ParagraphBuilderSkia::PeekStyle() {
179-
return txt_style_stack_.empty() ? base_style_ : txt_style_stack_.top();
180-
}
181-
182-
void ParagraphBuilderSkia::AddText(const std::u16string& text) {
183-
builder_->addText(text);
184-
}
185-
186-
void ParagraphBuilderSkia::AddPlaceholder(PlaceholderRun& span) {
187-
skt::PlaceholderStyle placeholder_style;
188-
placeholder_style.fHeight = span.height;
189-
placeholder_style.fWidth = span.width;
190-
placeholder_style.fBaseline = static_cast<skt::TextBaseline>(span.baseline);
191-
placeholder_style.fBaselineOffset = span.baseline_offset;
192-
placeholder_style.fAlignment =
193-
static_cast<skt::PlaceholderAlignment>(span.alignment);
194-
195-
builder_->addPlaceholder(placeholder_style);
196-
}
197-
198-
std::unique_ptr<Paragraph> ParagraphBuilderSkia::Build() {
199-
return std::make_unique<ParagraphSkia>(builder_->Build());
200-
}
201-
202218
} // namespace txt

third_party/txt/src/skia/paragraph_builder_skia.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "txt/paragraph_builder.h"
2121

22+
#include "flutter/display_list/display_list_paint.h"
2223
#include "third_party/skia/modules/skparagraph/include/ParagraphBuilder.h"
2324

2425
namespace txt {
@@ -39,9 +40,15 @@ class ParagraphBuilderSkia : public ParagraphBuilder {
3940
virtual std::unique_ptr<Paragraph> Build() override;
4041

4142
private:
43+
skia::textlayout::ParagraphPainter::PaintID CreatePaintID(
44+
const flutter::DlPaint& dl_paint);
45+
skia::textlayout::ParagraphStyle TxtToSkia(const ParagraphStyle& txt);
46+
skia::textlayout::TextStyle TxtToSkia(const TextStyle& txt);
47+
4248
std::shared_ptr<skia::textlayout::ParagraphBuilder> builder_;
4349
TextStyle base_style_;
4450
std::stack<TextStyle> txt_style_stack_;
51+
std::vector<flutter::DlPaint> dl_paints_;
4552
};
4653

4754
} // namespace txt

0 commit comments

Comments
 (0)