Reland "Cache text blobs computed by TextLine::paintText"
Change-Id: If166d7a2b287774054f833ac0f7b564bbcac9fa8 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/342936 Reviewed-by: Julia Lavrova <jlavrova@google.com> Commit-Queue: Jason Simmons <jsimmons@google.com>
This commit is contained in:
parent
7b80726d0e
commit
6d14f3841d
@ -105,7 +105,8 @@ TextLine::TextLine(ParagraphImpl* owner,
|
||||
, fHasShadows(false)
|
||||
, fHasDecorations(false)
|
||||
, fAscentStyle(LineMetricStyle::CSS)
|
||||
, fDescentStyle(LineMetricStyle::CSS) {
|
||||
, fDescentStyle(LineMetricStyle::CSS)
|
||||
, fTextBlobCachePopulated(false) {
|
||||
// Reorder visual runs
|
||||
auto& start = owner->cluster(fGhostClusterRange.start);
|
||||
auto& end = owner->cluster(fGhostClusterRange.end - 1);
|
||||
@ -192,21 +193,27 @@ SkRect TextLine::paint(SkCanvas* textCanvas, SkScalar x, SkScalar y) {
|
||||
});
|
||||
}
|
||||
|
||||
this->iterateThroughVisualRuns(false,
|
||||
[textCanvas, x, y, &bounds, this]
|
||||
(const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
|
||||
if (run->placeholderStyle() != nullptr) {
|
||||
*runWidthInLine = run->advance().fX;
|
||||
if (!fTextBlobCachePopulated) {
|
||||
this->iterateThroughVisualRuns(false,
|
||||
[textCanvas, x, y, this]
|
||||
(const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
|
||||
if (run->placeholderStyle() != nullptr) {
|
||||
*runWidthInLine = run->advance().fX;
|
||||
return true;
|
||||
}
|
||||
*runWidthInLine = this->iterateThroughSingleRunByStyles(
|
||||
run, runOffsetInLine, textRange, StyleType::kForeground,
|
||||
[textCanvas, x, y, this](TextRange textRange, const TextStyle& style, const ClipContext& context) {
|
||||
this->buildTextBlob(textCanvas, x, y, textRange, style, context);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
*runWidthInLine = this->iterateThroughSingleRunByStyles(
|
||||
run, runOffsetInLine, textRange, StyleType::kForeground,
|
||||
[textCanvas, x, y, &bounds, this](TextRange textRange, const TextStyle& style, const ClipContext& context) {
|
||||
auto textBounds = this->paintText(textCanvas, x, y, textRange, style, context);
|
||||
bounds.joinPossiblyEmptyRect(textBounds);
|
||||
});
|
||||
return true;
|
||||
});
|
||||
fTextBlobCachePopulated = true;
|
||||
}
|
||||
for (auto& record : fTextBlobCache) {
|
||||
record.paint(textCanvas, x, y);
|
||||
bounds.joinPossiblyEmptyRect(record.fBounds);
|
||||
}
|
||||
|
||||
if (fHasDecorations) {
|
||||
this->iterateThroughVisualRuns(false,
|
||||
@ -294,44 +301,49 @@ SkScalar TextLine::metricsWithoutMultiplier(TextHeightBehavior correction) {
|
||||
return delta;
|
||||
}
|
||||
|
||||
SkRect TextLine::paintText(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const {
|
||||
|
||||
void TextLine::buildTextBlob(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) {
|
||||
if (context.run->placeholderStyle() != nullptr) {
|
||||
return SkRect::MakeEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
fTextBlobCache.emplace_back();
|
||||
TextBlobRecord& record = fTextBlobCache.back();
|
||||
|
||||
if (style.hasForeground()) {
|
||||
paint = style.getForeground();
|
||||
record.fPaint = style.getForeground();
|
||||
} else {
|
||||
paint.setColor(style.getColor());
|
||||
record.fPaint.setColor(style.getColor());
|
||||
}
|
||||
|
||||
// TODO: This is the change for flutter, must be removed later
|
||||
SkTextBlobBuilder builder;
|
||||
context.run->copyTo(builder, SkToU32(context.pos), context.size);
|
||||
record.fClippingNeeded = context.clippingNeeded;
|
||||
if (context.clippingNeeded) {
|
||||
canvas->save();
|
||||
canvas->clipRect(extendHeight(context).makeOffset(this->offset() + SkPoint::Make(x, y)));
|
||||
record.fClipRect = extendHeight(context).makeOffset(this->offset());
|
||||
}
|
||||
|
||||
SkRect textBounds = SkRect::MakeEmpty();
|
||||
SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + 0.5);
|
||||
auto blob = builder.make();
|
||||
if (blob != nullptr) {
|
||||
auto bounds = blob->bounds();
|
||||
record.fBlob = builder.make();
|
||||
if (record.fBlob != nullptr) {
|
||||
auto bounds = record.fBlob->bounds();
|
||||
bounds.offset(x + this->offset().fX, y + this->offset().fY);
|
||||
textBounds.joinPossiblyEmptyRect(bounds);
|
||||
record.fBounds.joinPossiblyEmptyRect(bounds);
|
||||
}
|
||||
|
||||
canvas->drawTextBlob(blob,
|
||||
x + this->offset().fX + context.fTextShift, y + this->offset().fY + correctedBaseline, paint);
|
||||
record.fOffset = SkPoint::Make(this->offset().fX + context.fTextShift,
|
||||
this->offset().fY + correctedBaseline);
|
||||
}
|
||||
|
||||
if (context.clippingNeeded) {
|
||||
void TextLine::TextBlobRecord::paint(SkCanvas* canvas, SkScalar x, SkScalar y) {
|
||||
if (fClippingNeeded) {
|
||||
canvas->save();
|
||||
canvas->clipRect(fClipRect.makeOffset(x, y));
|
||||
}
|
||||
canvas->drawTextBlob(fBlob, x + fOffset.x(), y + fOffset.y(), fPaint);
|
||||
if (fClippingNeeded) {
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
return textBounds;
|
||||
}
|
||||
|
||||
void TextLine::paintBackground(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const {
|
||||
|
@ -121,7 +121,7 @@ private:
|
||||
std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, Run* run);
|
||||
void justify(SkScalar maxWidth);
|
||||
|
||||
SkRect paintText(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const;
|
||||
void buildTextBlob(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context);
|
||||
void paintBackground(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const;
|
||||
SkRect paintShadow(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const;
|
||||
void paintDecorations(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const;
|
||||
@ -149,6 +149,19 @@ private:
|
||||
|
||||
LineMetricStyle fAscentStyle;
|
||||
LineMetricStyle fDescentStyle;
|
||||
|
||||
struct TextBlobRecord {
|
||||
void paint(SkCanvas* canvas, SkScalar x, SkScalar y);
|
||||
|
||||
sk_sp<SkTextBlob> fBlob;
|
||||
SkPoint fOffset = SkPoint::Make(0.0f, 0.0f);
|
||||
SkPaint fPaint;
|
||||
SkRect fBounds = SkRect::MakeEmpty();
|
||||
bool fClippingNeeded = false;
|
||||
SkRect fClipRect = SkRect::MakeEmpty();
|
||||
};
|
||||
bool fTextBlobCachePopulated;
|
||||
std::vector<TextBlobRecord> fTextBlobCache;
|
||||
};
|
||||
} // namespace textlayout
|
||||
} // namespace skia
|
||||
|
Loading…
Reference in New Issue
Block a user