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

Build display lists from SkParagraph output using the ParagraphPainter interface #37087

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions display_list/display_list_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,13 @@ void DisplayListBuilder::drawTextBlob(const sk_sp<SkTextBlob> blob,
Push<DrawTextBlobOp>(0, 1, blob, x, y);
CheckLayerOpacityCompatibility();
}
void DisplayListBuilder::drawTextBlob(const sk_sp<SkTextBlob>& blob,
SkScalar x,
SkScalar y,
const DlPaint& paint) {
setAttributesFromDlPaint(paint, DisplayListOpFlags::kDrawTextBlobFlags);
drawTextBlob(blob, x, y);
}
void DisplayListBuilder::drawShadow(const SkPath& path,
const DlColor color,
const SkScalar elevation,
Expand Down
5 changes: 4 additions & 1 deletion display_list/display_list_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ class DisplayListBuilder final : public virtual Dispatcher,
void drawTextBlob(const sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y) override;
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
SkScalar x,
SkScalar y,
const DlPaint& paint);
void drawShadow(const SkPath& path,
const DlColor color,
const SkScalar elevation,
Expand Down Expand Up @@ -503,7 +507,6 @@ class DisplayListBuilder final : public virtual Dispatcher,
void onSetColorFilter(const DlColorFilter* filter);
void onSetPathEffect(const DlPathEffect* effect);
void onSetMaskFilter(const DlMaskFilter* filter);
void onSetMaskBlurFilter(SkBlurStyle style, SkScalar sigma);

DlPaint current_;
// If |current_blender_| is set then ignore |current_.getBlendMode()|
Expand Down
18 changes: 12 additions & 6 deletions display_list/display_list_mask_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ class DlMaskFilter
// filter is then used to combine those colors.
class DlBlurMaskFilter final : public DlMaskFilter {
public:
DlBlurMaskFilter(SkBlurStyle style, SkScalar sigma)
: style_(style), sigma_(sigma) {}
DlBlurMaskFilter(SkBlurStyle style, SkScalar sigma, bool respect_ctm = true)
: style_(style), sigma_(sigma), respect_ctm_(respect_ctm) {}
DlBlurMaskFilter(const DlBlurMaskFilter& filter)
: DlBlurMaskFilter(filter.style_, filter.sigma_) {}
: DlBlurMaskFilter(filter.style_, filter.sigma_, filter.respect_ctm_) {}
DlBlurMaskFilter(const DlBlurMaskFilter* filter)
: DlBlurMaskFilter(filter->style_, filter->sigma_) {}
: DlBlurMaskFilter(filter->style_, filter->sigma_, filter->respect_ctm_) {
}

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

sk_sp<SkMaskFilter> skia_object() const override {
return SkMaskFilter::MakeBlur(style_, sigma_);
return SkMaskFilter::MakeBlur(style_, sigma_, respect_ctm_);
}

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

SkBlurStyle style() const { return style_; }
SkScalar sigma() const { return sigma_; }
bool respectCTM() const { return respect_ctm_; }

protected:
bool equals_(DlMaskFilter const& other) const override {
FML_DCHECK(other.type() == DlMaskFilterType::kBlur);
auto that = static_cast<DlBlurMaskFilter const*>(&other);
return style_ == that->style_ && sigma_ == that->sigma_;
return style_ == that->style_ && sigma_ == that->sigma_ &&
respect_ctm_ == that->respect_ctm_;
}

private:
SkBlurStyle style_;
SkScalar sigma_;
// Added for backward compatibility with Flutter text shadow rendering which
// uses Skia blur filters with this flag set to false.
bool respect_ctm_;
};

// A wrapper class for a Skia MaskFilter of unknown type. The above 4 types
Expand Down
10 changes: 5 additions & 5 deletions display_list/display_list_test_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,15 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
}},
{"SetMaskFilter",
{
{0, 24, 0, 0,
{0, 32, 0, 0,
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter1); }},
{0, 24, 0, 0,
{0, 32, 0, 0,
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter2); }},
{0, 24, 0, 0,
{0, 32, 0, 0,
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter3); }},
{0, 24, 0, 0,
{0, 32, 0, 0,
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter4); }},
{0, 24, 0, 0,
{0, 32, 0, 0,
[](DisplayListBuilder& b) { b.setMaskFilter(&kTestMaskFilter5); }},
{0, 0, 0, 0,
[](DisplayListBuilder& b) { b.setMaskFilter(nullptr); }},
Expand Down
8 changes: 5 additions & 3 deletions lib/ui/painting/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ class Canvas : public RefCountedDartWrappable<Canvas>, DisplayListOpFlags {
SkCanvas* canvas() const { return canvas_; }
void Invalidate();

DisplayListBuilder* builder() {
return display_list_recorder_ ? display_list_recorder_->builder().get()
: nullptr;
}

private:
explicit Canvas(SkCanvas* canvas);

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

} // namespace flutter
Expand Down
10 changes: 7 additions & 3 deletions lib/ui/text/paragraph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,15 @@ void Paragraph::paint(Canvas* canvas, double x, double y) {
return;
}

SkCanvas* sk_canvas = canvas->canvas();
if (!sk_canvas) {
DisplayListBuilder* builder = canvas->builder();
if (builder && m_paragraph->Paint(builder, x, y)) {
return;
}
m_paragraph->Paint(sk_canvas, x, y);
// Fall back to SkCanvas if painting to DisplayListBuilder is not supported.
SkCanvas* sk_canvas = canvas->canvas();
if (sk_canvas) {
m_paragraph->Paint(sk_canvas, x, y);
}
}

static tonic::Float32List EncodeTextBoxes(
Expand Down
6 changes: 6 additions & 0 deletions lib/ui/text/paragraph_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,9 @@ void ParagraphBuilder::pushStyle(const tonic::Int32List& encoded,
SkPaint sk_paint;
style.has_background = true;
style.background = *background.paint(sk_paint);
DlPaint dl_paint;
background.toDlPaint(dl_paint);
style.background_dl = dl_paint;
}
}

Expand All @@ -481,6 +484,9 @@ void ParagraphBuilder::pushStyle(const tonic::Int32List& encoded,
SkPaint sk_paint;
style.has_foreground = true;
style.foreground = *foreground.paint(sk_paint);
DlPaint dl_paint;
foreground.toDlPaint(dl_paint);
style.foreground_dl = dl_paint;
}
}

Expand Down
1 change: 1 addition & 0 deletions third_party/txt/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ source_set("txt") {
configs += [ ":define_skshaper" ]

public_deps = [
"//flutter/display_list",
"//flutter/fml",
"//third_party/harfbuzz",
"//third_party/icu",
Expand Down
116 changes: 66 additions & 50 deletions third_party/txt/src/skia/paragraph_builder_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,68 @@ SkFontStyle MakeSkFontStyle(txt::FontWeight font_weight,
: SkFontStyle::Slant::kItalic_Slant);
}

skt::ParagraphStyle TxtToSkia(const ParagraphStyle& txt) {
} // anonymous namespace

ParagraphBuilderSkia::ParagraphBuilderSkia(
const ParagraphStyle& style,
std::shared_ptr<FontCollection> font_collection)
: base_style_(style.GetTextStyle()) {
builder_ = skt::ParagraphBuilder::make(
TxtToSkia(style), font_collection->CreateSktFontCollection());
}

ParagraphBuilderSkia::~ParagraphBuilderSkia() = default;

void ParagraphBuilderSkia::PushStyle(const TextStyle& style) {
builder_->pushStyle(TxtToSkia(style));
txt_style_stack_.push(style);
}

void ParagraphBuilderSkia::Pop() {
builder_->pop();
txt_style_stack_.pop();
}

const TextStyle& ParagraphBuilderSkia::PeekStyle() {
return txt_style_stack_.empty() ? base_style_ : txt_style_stack_.top();
}

void ParagraphBuilderSkia::AddText(const std::u16string& text) {
builder_->addText(text);
}

void ParagraphBuilderSkia::AddPlaceholder(PlaceholderRun& span) {
skt::PlaceholderStyle placeholder_style;
placeholder_style.fHeight = span.height;
placeholder_style.fWidth = span.width;
placeholder_style.fBaseline = static_cast<skt::TextBaseline>(span.baseline);
placeholder_style.fBaselineOffset = span.baseline_offset;
placeholder_style.fAlignment =
static_cast<skt::PlaceholderAlignment>(span.alignment);

builder_->addPlaceholder(placeholder_style);
}

std::unique_ptr<Paragraph> ParagraphBuilderSkia::Build() {
return std::make_unique<ParagraphSkia>(builder_->Build(),
std::move(dl_paints_));
}

skt::ParagraphPainter::PaintID ParagraphBuilderSkia::CreatePaintID(
const flutter::DlPaint& dl_paint) {
dl_paints_.push_back(dl_paint);
return dl_paints_.size() - 1;
}

skt::ParagraphStyle ParagraphBuilderSkia::TxtToSkia(const ParagraphStyle& txt) {
skt::ParagraphStyle skia;
skt::TextStyle text_style;

// Convert the default color of an SkParagraph text style into a DlPaint.
flutter::DlPaint dl_paint;
dl_paint.setColor(text_style.getColor());
text_style.setForegroundPaintID(CreatePaintID(dl_paint));

text_style.setFontStyle(MakeSkFontStyle(txt.font_weight, txt.font_style));
text_style.setFontSize(SkDoubleToScalar(txt.font_size));
text_style.setHeight(SkDoubleToScalar(txt.height));
Expand Down Expand Up @@ -84,7 +142,7 @@ skt::ParagraphStyle TxtToSkia(const ParagraphStyle& txt) {
return skia;
}

skt::TextStyle TxtToSkia(const TextStyle& txt) {
skt::TextStyle ParagraphBuilderSkia::TxtToSkia(const TextStyle& txt) {
skt::TextStyle skia;

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

skia.setLocale(SkString(txt.locale.c_str()));
if (txt.has_background) {
skia.setBackgroundColor(txt.background);
skia.setBackgroundPaintID(CreatePaintID(txt.background_dl));
}
if (txt.has_foreground) {
skia.setForegroundColor(txt.foreground);
skia.setForegroundPaintID(CreatePaintID(txt.foreground_dl));
} else {
flutter::DlPaint dl_paint;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This piece is new and I'm not sure why it's needed now...?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TextStyle API has color and foreground fields that are somewhat redundant. color sets the color of the text, and foreground sets all of the painting properties of the text including the color. If foreground is set, then it takes precedence over color.

Before this PR the style's color field would be forwarded to its SkPargraph counterpart. Now, if color is used then Flutter must create a DlPaint representing the color.

dl_paint.setColor(txt.color);
skia.setForegroundPaintID(CreatePaintID(dl_paint));
}

skia.resetFontFeatures();
Expand Down Expand Up @@ -153,50 +215,4 @@ skt::TextStyle TxtToSkia(const TextStyle& txt) {
return skia;
}

} // anonymous namespace

ParagraphBuilderSkia::ParagraphBuilderSkia(
const ParagraphStyle& style,
std::shared_ptr<FontCollection> font_collection)
: builder_(skt::ParagraphBuilder::make(
TxtToSkia(style),
font_collection->CreateSktFontCollection())),
base_style_(style.GetTextStyle()) {}

ParagraphBuilderSkia::~ParagraphBuilderSkia() = default;

void ParagraphBuilderSkia::PushStyle(const TextStyle& style) {
builder_->pushStyle(TxtToSkia(style));
txt_style_stack_.push(style);
}

void ParagraphBuilderSkia::Pop() {
builder_->pop();
txt_style_stack_.pop();
}

const TextStyle& ParagraphBuilderSkia::PeekStyle() {
return txt_style_stack_.empty() ? base_style_ : txt_style_stack_.top();
}

void ParagraphBuilderSkia::AddText(const std::u16string& text) {
builder_->addText(text);
}

void ParagraphBuilderSkia::AddPlaceholder(PlaceholderRun& span) {
skt::PlaceholderStyle placeholder_style;
placeholder_style.fHeight = span.height;
placeholder_style.fWidth = span.width;
placeholder_style.fBaseline = static_cast<skt::TextBaseline>(span.baseline);
placeholder_style.fBaselineOffset = span.baseline_offset;
placeholder_style.fAlignment =
static_cast<skt::PlaceholderAlignment>(span.alignment);

builder_->addPlaceholder(placeholder_style);
}

std::unique_ptr<Paragraph> ParagraphBuilderSkia::Build() {
return std::make_unique<ParagraphSkia>(builder_->Build());
}

} // namespace txt
7 changes: 7 additions & 0 deletions third_party/txt/src/skia/paragraph_builder_skia.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "txt/paragraph_builder.h"

#include "flutter/display_list/display_list_paint.h"
#include "third_party/skia/modules/skparagraph/include/ParagraphBuilder.h"

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

private:
skia::textlayout::ParagraphPainter::PaintID CreatePaintID(
const flutter::DlPaint& dl_paint);
skia::textlayout::ParagraphStyle TxtToSkia(const ParagraphStyle& txt);
skia::textlayout::TextStyle TxtToSkia(const TextStyle& txt);

std::shared_ptr<skia::textlayout::ParagraphBuilder> builder_;
TextStyle base_style_;
std::stack<TextStyle> txt_style_stack_;
std::vector<flutter::DlPaint> dl_paints_;
};

} // namespace txt
Expand Down
Loading