From 220c7b0618f949a88f62740043e482fa3ddf34ae Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Fri, 11 Nov 2022 08:39:23 -0800 Subject: [PATCH] Build display lists from SkParagraph output using the ParagraphPainter interface (flutter/engine#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. --- .../display_list/display_list_builder.cc | 7 + .../display_list/display_list_builder.h | 5 +- .../display_list/display_list_mask_filter.h | 18 +- .../display_list/display_list_test_utils.cc | 10 +- engine/src/flutter/lib/ui/painting/canvas.h | 8 +- engine/src/flutter/lib/ui/text/paragraph.cc | 10 +- .../flutter/lib/ui/text/paragraph_builder.cc | 6 + engine/src/flutter/third_party/txt/BUILD.gn | 1 + .../txt/src/skia/paragraph_builder_skia.cc | 116 ++++++----- .../txt/src/skia/paragraph_builder_skia.h | 7 + .../txt/src/skia/paragraph_skia.cc | 195 ++++++++++++++---- .../third_party/txt/src/skia/paragraph_skia.h | 7 +- .../third_party/txt/src/txt/paragraph.h | 4 + .../third_party/txt/src/txt/paragraph_txt.h | 5 + .../third_party/txt/src/txt/text_style.h | 3 + 15 files changed, 295 insertions(+), 107 deletions(-) diff --git a/engine/src/flutter/display_list/display_list_builder.cc b/engine/src/flutter/display_list/display_list_builder.cc index ccef2769aea..81c06b08b1b 100644 --- a/engine/src/flutter/display_list/display_list_builder.cc +++ b/engine/src/flutter/display_list/display_list_builder.cc @@ -1071,6 +1071,13 @@ void DisplayListBuilder::drawTextBlob(const sk_sp blob, Push(0, 1, blob, x, y); CheckLayerOpacityCompatibility(); } +void DisplayListBuilder::drawTextBlob(const sk_sp& 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, diff --git a/engine/src/flutter/display_list/display_list_builder.h b/engine/src/flutter/display_list/display_list_builder.h index 8bcc3ffa56d..5be4146b14e 100644 --- a/engine/src/flutter/display_list/display_list_builder.h +++ b/engine/src/flutter/display_list/display_list_builder.h @@ -334,6 +334,10 @@ class DisplayListBuilder final : public virtual Dispatcher, void drawTextBlob(const sk_sp blob, SkScalar x, SkScalar y) override; + void drawTextBlob(const sk_sp& blob, + SkScalar x, + SkScalar y, + const DlPaint& paint); void drawShadow(const SkPath& path, const DlColor color, const SkScalar elevation, @@ -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()| diff --git a/engine/src/flutter/display_list/display_list_mask_filter.h b/engine/src/flutter/display_list/display_list_mask_filter.h index 56233421a96..336d7c58e74 100644 --- a/engine/src/flutter/display_list/display_list_mask_filter.h +++ b/engine/src/flutter/display_list/display_list_mask_filter.h @@ -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); } @@ -73,24 +74,29 @@ class DlBlurMaskFilter final : public DlMaskFilter { } sk_sp 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(&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 diff --git a/engine/src/flutter/display_list/display_list_test_utils.cc b/engine/src/flutter/display_list/display_list_test_utils.cc index 74e9c9ed4ee..144fe140d74 100644 --- a/engine/src/flutter/display_list/display_list_test_utils.cc +++ b/engine/src/flutter/display_list/display_list_test_utils.cc @@ -284,15 +284,15 @@ std::vector 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); }}, diff --git a/engine/src/flutter/lib/ui/painting/canvas.h b/engine/src/flutter/lib/ui/painting/canvas.h index 22ef44315ca..0855c52c20f 100644 --- a/engine/src/flutter/lib/ui/painting/canvas.h +++ b/engine/src/flutter/lib/ui/painting/canvas.h @@ -190,6 +190,11 @@ class Canvas : public RefCountedDartWrappable, 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); @@ -205,9 +210,6 @@ class Canvas : public RefCountedDartWrappable, 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 display_list_recorder_; - DisplayListBuilder* builder() { - return display_list_recorder_->builder().get(); - } }; } // namespace flutter diff --git a/engine/src/flutter/lib/ui/text/paragraph.cc b/engine/src/flutter/lib/ui/text/paragraph.cc index 6b4bb3610bc..4b3df643918 100644 --- a/engine/src/flutter/lib/ui/text/paragraph.cc +++ b/engine/src/flutter/lib/ui/text/paragraph.cc @@ -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( diff --git a/engine/src/flutter/lib/ui/text/paragraph_builder.cc b/engine/src/flutter/lib/ui/text/paragraph_builder.cc index 03daf935845..82881ede24e 100644 --- a/engine/src/flutter/lib/ui/text/paragraph_builder.cc +++ b/engine/src/flutter/lib/ui/text/paragraph_builder.cc @@ -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; } } @@ -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; } } diff --git a/engine/src/flutter/third_party/txt/BUILD.gn b/engine/src/flutter/third_party/txt/BUILD.gn index 98327626ec2..3060859fe47 100644 --- a/engine/src/flutter/third_party/txt/BUILD.gn +++ b/engine/src/flutter/third_party/txt/BUILD.gn @@ -143,6 +143,7 @@ source_set("txt") { configs += [ ":define_skshaper" ] public_deps = [ + "//flutter/display_list", "//flutter/fml", "//third_party/harfbuzz", "//third_party/icu", diff --git a/engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.cc b/engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.cc index 79b7a65adb4..272b6e09cb2 100644 --- a/engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.cc +++ b/engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.cc @@ -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 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(span.baseline); + placeholder_style.fBaselineOffset = span.baseline_offset; + placeholder_style.fAlignment = + static_cast(span.alignment); + + builder_->addPlaceholder(placeholder_style); +} + +std::unique_ptr ParagraphBuilderSkia::Build() { + return std::make_unique(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)); @@ -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); @@ -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(); @@ -153,50 +215,4 @@ skt::TextStyle TxtToSkia(const TextStyle& txt) { return skia; } -} // anonymous namespace - -ParagraphBuilderSkia::ParagraphBuilderSkia( - const ParagraphStyle& style, - std::shared_ptr 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(span.baseline); - placeholder_style.fBaselineOffset = span.baseline_offset; - placeholder_style.fAlignment = - static_cast(span.alignment); - - builder_->addPlaceholder(placeholder_style); -} - -std::unique_ptr ParagraphBuilderSkia::Build() { - return std::make_unique(builder_->Build()); -} - } // namespace txt diff --git a/engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.h b/engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.h index 06b00caf43c..58869cfa0a5 100644 --- a/engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.h +++ b/engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.h @@ -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 { @@ -39,9 +40,15 @@ class ParagraphBuilderSkia : public ParagraphBuilder { virtual std::unique_ptr 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 builder_; TextStyle base_style_; std::stack txt_style_stack_; + std::vector dl_paints_; }; } // namespace txt diff --git a/engine/src/flutter/third_party/txt/src/skia/paragraph_skia.cc b/engine/src/flutter/third_party/txt/src/skia/paragraph_skia.cc index 2bf3fbeead6..359a0880de2 100644 --- a/engine/src/flutter/third_party/txt/src/skia/paragraph_skia.cc +++ b/engine/src/flutter/third_party/txt/src/skia/paragraph_skia.cc @@ -22,6 +22,9 @@ namespace txt { namespace skt = skia::textlayout; +using PaintID = skt::ParagraphPainter::PaintID; + +using namespace flutter; namespace { @@ -40,54 +43,108 @@ txt::FontStyle GetTxtFontStyle(SkFontStyle::Slant font_slant) { : txt::FontStyle::italic; } -TextStyle SkiaToTxt(const skt::TextStyle& skia) { - TextStyle txt; +class DisplayListParagraphPainter : public skt::ParagraphPainter { + public: + DisplayListParagraphPainter(DisplayListBuilder* builder, + const std::vector& dl_paints) + : builder_(builder), dl_paints_(dl_paints) {} - txt.color = skia.getColor(); - txt.decoration = static_cast(skia.getDecorationType()); - txt.decoration_color = skia.getDecorationColor(); - txt.decoration_style = - static_cast(skia.getDecorationStyle()); - txt.decoration_thickness_multiplier = - SkScalarToDouble(skia.getDecorationThicknessMultiplier()); - txt.font_weight = GetTxtFontWeight(skia.getFontStyle().weight()); - txt.font_style = GetTxtFontStyle(skia.getFontStyle().slant()); - - txt.text_baseline = static_cast(skia.getTextBaseline()); - - for (const SkString& font_family : skia.getFontFamilies()) { - txt.font_families.emplace_back(font_family.c_str()); + DlPaint toDlPaint(const DecorationStyle& decor_style, + DlDrawStyle draw_style = DlDrawStyle::kStroke) { + DlPaint paint; + paint.setDrawStyle(draw_style); + paint.setAntiAlias(true); + paint.setColor(decor_style.getColor()); + paint.setStrokeWidth(decor_style.getStrokeWidth()); + std::optional dash_path_effect = + decor_style.getDashPathEffect(); + if (dash_path_effect) { + std::array intervals{dash_path_effect->fOnLength, + dash_path_effect->fOffLength}; + paint.setPathEffect( + DlDashPathEffect::Make(intervals.data(), intervals.size(), 0)); + } + return paint; } - txt.font_size = SkScalarToDouble(skia.getFontSize()); - txt.letter_spacing = SkScalarToDouble(skia.getLetterSpacing()); - txt.word_spacing = SkScalarToDouble(skia.getWordSpacing()); - txt.height = SkScalarToDouble(skia.getHeight()); - - txt.locale = skia.getLocale().c_str(); - if (skia.hasBackground()) { - txt.background = skia.getBackground(); - } - if (skia.hasForeground()) { - txt.foreground = skia.getForeground(); + void drawTextBlob(const sk_sp& blob, + SkScalar x, + SkScalar y, + const SkPaintOrID& paint) override { + if (!blob) { + return; + } + size_t paint_id = std::get(paint); + FML_DCHECK(paint_id < dl_paints_.size()); + builder_->drawTextBlob(blob, x, y, dl_paints_[paint_id]); } - txt.text_shadows.clear(); - for (const skt::TextShadow& skia_shadow : skia.getShadows()) { - txt::TextShadow shadow; - shadow.offset = skia_shadow.fOffset; - shadow.blur_sigma = skia_shadow.fBlurSigma; - shadow.color = skia_shadow.fColor; - txt.text_shadows.emplace_back(shadow); + void drawTextShadow(const sk_sp& blob, + SkScalar x, + SkScalar y, + SkColor color, + SkScalar blur_sigma) override { + if (!blob) { + return; + } + DlPaint paint; + paint.setColor(color); + if (blur_sigma > 0.0) { + DlBlurMaskFilter filter(SkBlurStyle::kNormal_SkBlurStyle, blur_sigma, + false); + paint.setMaskFilter(&filter); + } + builder_->drawTextBlob(blob, x, y, paint); } - return txt; -} + void drawRect(const SkRect& rect, const SkPaintOrID& paint) override { + size_t paint_id = std::get(paint); + FML_DCHECK(paint_id < dl_paints_.size()); + builder_->drawRect(rect, dl_paints_[paint_id]); + } + + void drawFilledRect(const SkRect& rect, + const DecorationStyle& decor_style) override { + DlPaint paint = toDlPaint(decor_style, DlDrawStyle::kFill); + builder_->drawRect(rect, paint); + } + + void drawPath(const SkPath& path, + const DecorationStyle& decor_style) override { + builder_->drawPath(path, toDlPaint(decor_style)); + } + + void drawLine(SkScalar x0, + SkScalar y0, + SkScalar x1, + SkScalar y1, + const DecorationStyle& decor_style) override { + builder_->drawLine(SkPoint::Make(x0, y0), SkPoint::Make(x1, y1), + toDlPaint(decor_style)); + } + + void clipRect(const SkRect& rect) override { + builder_->clipRect(rect, SkClipOp::kIntersect, false); + } + + void translate(SkScalar dx, SkScalar dy) override { + builder_->translate(dx, dy); + } + + void save() override { builder_->save(); } + + void restore() override { builder_->restore(); } + + private: + DisplayListBuilder* builder_; + const std::vector& dl_paints_; +}; } // anonymous namespace -ParagraphSkia::ParagraphSkia(std::unique_ptr paragraph) - : paragraph_(std::move(paragraph)) {} +ParagraphSkia::ParagraphSkia(std::unique_ptr paragraph, + std::vector&& dl_paints) + : paragraph_(std::move(paragraph)), dl_paints_(dl_paints) {} double ParagraphSkia::GetMaxWidth() { return SkScalarToDouble(paragraph_->getMaxWidth()); @@ -170,6 +227,12 @@ void ParagraphSkia::Paint(SkCanvas* canvas, double x, double y) { paragraph_->paint(canvas, x, y); } +bool ParagraphSkia::Paint(DisplayListBuilder* builder, double x, double y) { + DisplayListParagraphPainter painter(builder, dl_paints_); + paragraph_->paint(&painter, x, y); + return true; +} + std::vector ParagraphSkia::GetRectsForRange( size_t start, size_t end, @@ -215,4 +278,60 @@ Paragraph::Range ParagraphSkia::GetWordBoundary(size_t offset) { return Paragraph::Range(range.start, range.end); } +TextStyle ParagraphSkia::SkiaToTxt(const skt::TextStyle& skia) { + TextStyle txt; + + txt.color = skia.getColor(); + txt.decoration = static_cast(skia.getDecorationType()); + txt.decoration_color = skia.getDecorationColor(); + txt.decoration_style = + static_cast(skia.getDecorationStyle()); + txt.decoration_thickness_multiplier = + SkScalarToDouble(skia.getDecorationThicknessMultiplier()); + txt.font_weight = GetTxtFontWeight(skia.getFontStyle().weight()); + txt.font_style = GetTxtFontStyle(skia.getFontStyle().slant()); + + txt.text_baseline = static_cast(skia.getTextBaseline()); + + for (const SkString& font_family : skia.getFontFamilies()) { + txt.font_families.emplace_back(font_family.c_str()); + } + + txt.font_size = SkScalarToDouble(skia.getFontSize()); + txt.letter_spacing = SkScalarToDouble(skia.getLetterSpacing()); + txt.word_spacing = SkScalarToDouble(skia.getWordSpacing()); + txt.height = SkScalarToDouble(skia.getHeight()); + + txt.locale = skia.getLocale().c_str(); + if (skia.hasBackground()) { + skt::ParagraphPainter::SkPaintOrID background = + skia.getBackgroundPaintOrID(); + if (std::holds_alternative(background)) { + txt.background = std::get(background); + } else if (std::holds_alternative(background)) { + txt.background_dl = dl_paints_[std::get(background)]; + } + } + if (skia.hasForeground()) { + skt::ParagraphPainter::SkPaintOrID foreground = + skia.getForegroundPaintOrID(); + if (std::holds_alternative(foreground)) { + txt.foreground = std::get(foreground); + } else if (std::holds_alternative(foreground)) { + txt.foreground_dl = dl_paints_[std::get(foreground)]; + } + } + + txt.text_shadows.clear(); + for (const skt::TextShadow& skia_shadow : skia.getShadows()) { + txt::TextShadow shadow; + shadow.offset = skia_shadow.fOffset; + shadow.blur_sigma = skia_shadow.fBlurSigma; + shadow.color = skia_shadow.fColor; + txt.text_shadows.emplace_back(shadow); + } + + return txt; +} + } // namespace txt diff --git a/engine/src/flutter/third_party/txt/src/skia/paragraph_skia.h b/engine/src/flutter/third_party/txt/src/skia/paragraph_skia.h index 286fbe47ca0..640ab479d41 100644 --- a/engine/src/flutter/third_party/txt/src/skia/paragraph_skia.h +++ b/engine/src/flutter/third_party/txt/src/skia/paragraph_skia.h @@ -28,7 +28,8 @@ namespace txt { // Implementation of Paragraph based on Skia's text layout module. class ParagraphSkia : public Paragraph { public: - ParagraphSkia(std::unique_ptr paragraph); + ParagraphSkia(std::unique_ptr paragraph, + std::vector&& dl_paints); virtual ~ParagraphSkia() = default; @@ -53,6 +54,7 @@ class ParagraphSkia : public Paragraph { void Layout(double width) override; void Paint(SkCanvas* canvas, double x, double y) override; + bool Paint(flutter::DisplayListBuilder* builder, double x, double y) override; std::vector GetRectsForRange( size_t start, @@ -68,7 +70,10 @@ class ParagraphSkia : public Paragraph { Range GetWordBoundary(size_t offset) override; private: + TextStyle SkiaToTxt(const skia::textlayout::TextStyle& skia); + std::unique_ptr paragraph_; + std::vector dl_paints_; std::optional> line_metrics_; std::vector line_metrics_styles_; }; diff --git a/engine/src/flutter/third_party/txt/src/txt/paragraph.h b/engine/src/flutter/third_party/txt/src/txt/paragraph.h index 2065a2d1cbd..db713241d59 100644 --- a/engine/src/flutter/third_party/txt/src/txt/paragraph.h +++ b/engine/src/flutter/third_party/txt/src/txt/paragraph.h @@ -18,6 +18,7 @@ #ifndef LIB_TXT_SRC_PARAGRAPH_H_ #define LIB_TXT_SRC_PARAGRAPH_H_ +#include "flutter/display_list/display_list_builder.h" #include "line_metrics.h" #include "paragraph_style.h" #include "third_party/skia/include/core/SkRect.h" @@ -146,6 +147,9 @@ class Paragraph { // Paints the laid out text onto the supplied SkCanvas at (x, y) offset from // the origin. Only valid after Layout() is called. virtual void Paint(SkCanvas* canvas, double x, double y) = 0; + virtual bool Paint(flutter::DisplayListBuilder* builder, + double x, + double y) = 0; // Returns a vector of bounding boxes that enclose all text between start and // end glyph indexes, including start and excluding end. diff --git a/engine/src/flutter/third_party/txt/src/txt/paragraph_txt.h b/engine/src/flutter/third_party/txt/src/txt/paragraph_txt.h index b536b40ef9a..989fc058bed 100644 --- a/engine/src/flutter/third_party/txt/src/txt/paragraph_txt.h +++ b/engine/src/flutter/third_party/txt/src/txt/paragraph_txt.h @@ -74,6 +74,11 @@ class ParagraphTxt : public Paragraph { virtual void Layout(double width) override; virtual void Paint(SkCanvas* canvas, double x, double y) override; + virtual bool Paint(flutter::DisplayListBuilder* builder, + double x, + double y) override { + return false; + } // Getter for paragraph_style_. const ParagraphStyle& GetParagraphStyle() const; diff --git a/engine/src/flutter/third_party/txt/src/txt/text_style.h b/engine/src/flutter/third_party/txt/src/txt/text_style.h index 2a63c685c81..7fcb30a2611 100644 --- a/engine/src/flutter/third_party/txt/src/txt/text_style.h +++ b/engine/src/flutter/third_party/txt/src/txt/text_style.h @@ -20,6 +20,7 @@ #include #include +#include "flutter/display_list/display_list_paint.h" #include "font_features.h" #include "font_style.h" #include "font_weight.h" @@ -56,8 +57,10 @@ class TextStyle { std::string locale; bool has_background = false; SkPaint background; + flutter::DlPaint background_dl; bool has_foreground = false; SkPaint foreground; + flutter::DlPaint foreground_dl; // An ordered list of shadows where the first shadow will be drawn first (at // the bottom). std::vector text_shadows;