Skip to content

Commit

Permalink
Build display lists from SkParagraph output using the ParagraphPainte…
Browse files Browse the repository at this point in the history
…r interface (flutter#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.
  • Loading branch information
jason-simmons authored and schwa423 committed Nov 16, 2022
1 parent 8bb8946 commit c3cc00c
Show file tree
Hide file tree
Showing 15 changed files with 291 additions and 103 deletions.
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;
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

0 comments on commit c3cc00c

Please sign in to comment.