mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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.
This commit is contained in:
parent
16525e9817
commit
220c7b0618
@ -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,
|
||||
|
||||
@ -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,
|
||||
@ -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()|
|
||||
|
||||
@ -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<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
|
||||
|
||||
@ -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); }},
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
engine/src/flutter/third_party/txt/BUILD.gn
vendored
1
engine/src/flutter/third_party/txt/BUILD.gn
vendored
@ -143,6 +143,7 @@ source_set("txt") {
|
||||
configs += [ ":define_skshaper" ]
|
||||
|
||||
public_deps = [
|
||||
"//flutter/display_list",
|
||||
"//flutter/fml",
|
||||
"//third_party/harfbuzz",
|
||||
"//third_party/icu",
|
||||
|
||||
@ -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));
|
||||
@ -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<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
|
||||
|
||||
@ -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<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
|
||||
|
||||
@ -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<DlPaint>& dl_paints)
|
||||
: builder_(builder), dl_paints_(dl_paints) {}
|
||||
|
||||
txt.color = skia.getColor();
|
||||
txt.decoration = static_cast<TextDecoration>(skia.getDecorationType());
|
||||
txt.decoration_color = skia.getDecorationColor();
|
||||
txt.decoration_style =
|
||||
static_cast<TextDecorationStyle>(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<TextBaseline>(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<DashPathEffect> dash_path_effect =
|
||||
decor_style.getDashPathEffect();
|
||||
if (dash_path_effect) {
|
||||
std::array<SkScalar, 2> 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<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y,
|
||||
const SkPaintOrID& paint) override {
|
||||
if (!blob) {
|
||||
return;
|
||||
}
|
||||
size_t paint_id = std::get<PaintID>(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<SkTextBlob>& 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<PaintID>(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<DlPaint>& dl_paints_;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ParagraphSkia::ParagraphSkia(std::unique_ptr<skt::Paragraph> paragraph)
|
||||
: paragraph_(std::move(paragraph)) {}
|
||||
ParagraphSkia::ParagraphSkia(std::unique_ptr<skt::Paragraph> paragraph,
|
||||
std::vector<flutter::DlPaint>&& 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<Paragraph::TextBox> ParagraphSkia::GetRectsForRange(
|
||||
size_t start,
|
||||
size_t end,
|
||||
@ -215,4 +278,60 @@ Paragraph::Range<size_t> ParagraphSkia::GetWordBoundary(size_t offset) {
|
||||
return Paragraph::Range<size_t>(range.start, range.end);
|
||||
}
|
||||
|
||||
TextStyle ParagraphSkia::SkiaToTxt(const skt::TextStyle& skia) {
|
||||
TextStyle txt;
|
||||
|
||||
txt.color = skia.getColor();
|
||||
txt.decoration = static_cast<TextDecoration>(skia.getDecorationType());
|
||||
txt.decoration_color = skia.getDecorationColor();
|
||||
txt.decoration_style =
|
||||
static_cast<TextDecorationStyle>(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<TextBaseline>(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<SkPaint>(background)) {
|
||||
txt.background = std::get<SkPaint>(background);
|
||||
} else if (std::holds_alternative<PaintID>(background)) {
|
||||
txt.background_dl = dl_paints_[std::get<PaintID>(background)];
|
||||
}
|
||||
}
|
||||
if (skia.hasForeground()) {
|
||||
skt::ParagraphPainter::SkPaintOrID foreground =
|
||||
skia.getForegroundPaintOrID();
|
||||
if (std::holds_alternative<SkPaint>(foreground)) {
|
||||
txt.foreground = std::get<SkPaint>(foreground);
|
||||
} else if (std::holds_alternative<PaintID>(foreground)) {
|
||||
txt.foreground_dl = dl_paints_[std::get<PaintID>(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
|
||||
|
||||
@ -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<skia::textlayout::Paragraph> paragraph);
|
||||
ParagraphSkia(std::unique_ptr<skia::textlayout::Paragraph> paragraph,
|
||||
std::vector<flutter::DlPaint>&& 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<TextBox> GetRectsForRange(
|
||||
size_t start,
|
||||
@ -68,7 +70,10 @@ class ParagraphSkia : public Paragraph {
|
||||
Range<size_t> GetWordBoundary(size_t offset) override;
|
||||
|
||||
private:
|
||||
TextStyle SkiaToTxt(const skia::textlayout::TextStyle& skia);
|
||||
|
||||
std::unique_ptr<skia::textlayout::Paragraph> paragraph_;
|
||||
std::vector<flutter::DlPaint> dl_paints_;
|
||||
std::optional<std::vector<LineMetrics>> line_metrics_;
|
||||
std::vector<TextStyle> line_metrics_styles_;
|
||||
};
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<TextShadow> text_shadows;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user