Skip to content

Commit c036058

Browse files
RusinoSkia Commit-Bot
authored andcommitted
Cache should work with INF values
Change-Id: I1ae8d95bb85d28fdce9e0cf270583f0224e4dfed Bug: skia:9874 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/268938 Commit-Queue: Julia Lavrova <jlavrova@google.com> Reviewed-by: Ben Wagner <bungeman@google.com>
1 parent 2bc6031 commit c036058

14 files changed

Lines changed: 242 additions & 87 deletions

modules/skparagraph/include/ParagraphStyle.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ struct StrutStyle {
3737
bool getHeightOverride() const { return fHeightOverride; }
3838
void setHeightOverride(bool v) { fHeightOverride = v; }
3939

40+
bool operator==(const StrutStyle& rhs) const {
41+
return this->fEnabled == rhs.fEnabled &&
42+
this->fHeightOverride == rhs.fHeightOverride &&
43+
this->fForceHeight == rhs.fForceHeight &&
44+
nearlyEqual(this->fLeading, rhs.fLeading) &&
45+
nearlyEqual(this->fHeight, rhs.fHeight) &&
46+
nearlyEqual(this->fFontSize, rhs.fFontSize) &&
47+
this->fFontStyle == rhs.fFontStyle &&
48+
this->fFontFamilies == rhs.fFontFamilies;
49+
}
50+
4051
private:
4152

4253
std::vector<SkString> fFontFamilies;

modules/skparagraph/include/TextStyle.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@
1818
namespace skia {
1919
namespace textlayout {
2020

21+
static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) {
22+
if (SkScalarIsFinite(x)) {
23+
return SkScalarNearlyZero(x, tolerance);
24+
}
25+
return false;
26+
}
27+
28+
static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_ScalarNearlyZero) {
29+
if (SkScalarIsFinite(x) && SkScalarIsFinite(x)) {
30+
return SkScalarNearlyEqual(x, y, tolerance);
31+
}
32+
// Inf == Inf, anything else is false
33+
return x == y;
34+
}
35+
2136
// Multiple decorations can be applied at once. Ex: Underline and overline is
2237
// (0x1 | 0x2)
2338
enum TextDecoration {
@@ -100,7 +115,13 @@ struct FontFeature {
100115
};
101116

102117
struct PlaceholderStyle {
103-
PlaceholderStyle() { }
118+
PlaceholderStyle()
119+
: fWidth(0)
120+
, fHeight(0)
121+
, fAlignment(PlaceholderAlignment::kBaseline)
122+
, fBaseline(TextBaseline::kAlphabetic)
123+
, fBaselineOffset(0) {}
124+
104125
PlaceholderStyle(SkScalar width, SkScalar height, PlaceholderAlignment alignment,
105126
TextBaseline baseline, SkScalar offset)
106127
: fWidth(width)
@@ -111,13 +132,10 @@ struct PlaceholderStyle {
111132

112133
bool equals(const PlaceholderStyle& other) const;
113134

114-
SkScalar fWidth = 0;
115-
SkScalar fHeight = 0;
116-
135+
SkScalar fWidth;
136+
SkScalar fHeight;
117137
PlaceholderAlignment fAlignment;
118-
119138
TextBaseline fBaseline;
120-
121139
// Distance from the top edge of the rect to the baseline position. This
122140
// baseline will be aligned against the alphabetic baseline of the surrounding
123141
// text.
@@ -126,7 +144,7 @@ struct PlaceholderStyle {
126144
// small or negative values will cause the rect to be positioned underneath
127145
// the line. When baseline == height, the bottom edge of the rect will rest on
128146
// the alphabetic baseline.
129-
SkScalar fBaselineOffset = 0;
147+
SkScalar fBaselineOffset;
130148
};
131149

132150
class TextStyle {

modules/skparagraph/src/OneLineShaper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ bool OneLineShaper::iterateThroughShapingRegions(const ShapeVisitor& shape) {
483483
run.fPositions[0] = { advanceX, 0 };
484484
run.fOffsets[0] = {0, 0};
485485
run.fClusterIndexes[0] = 0;
486-
run.fPlaceholder = &placeholder.fStyle;
486+
run.fPlaceholderIndex = &placeholder - fParagraph->fPlaceholders.begin();
487487
advanceX += placeholder.fStyle.fWidth;
488488
}
489489
return true;

modules/skparagraph/src/ParagraphCache.cpp

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ namespace textlayout {
88
namespace {
99
SkScalar relax(SkScalar a) {
1010
// This rounding is done to match Flutter tests. Must be removed..
11-
auto threshold = SkIntToScalar(1 << 12);
12-
return SkScalarRoundToScalar(a * threshold)/threshold;
11+
if (SkScalarIsFinite(a)) {
12+
auto threshold = SkIntToScalar(1 << 12);
13+
return SkScalarRoundToScalar(a * threshold)/threshold;
14+
} else {
15+
return a;
16+
}
1317
}
1418
}
1519

@@ -31,19 +35,15 @@ class ParagraphCacheValue {
3135
public:
3236
ParagraphCacheValue(const ParagraphImpl* paragraph)
3337
: fKey(ParagraphCacheKey(paragraph))
34-
, fInternalState(paragraph->fState)
3538
, fRuns(paragraph->fRuns)
36-
, fClusters(paragraph->fClusters)
37-
, fUnresolvedGlyphs(paragraph->fUnresolvedGlyphs){ }
39+
, fClusters(paragraph->fClusters) { }
3840

3941
// Input == key
4042
ParagraphCacheKey fKey;
4143

42-
// Shaped results:
43-
InternalState fInternalState;
44+
// Shaped results
4445
SkTArray<Run, false> fRuns;
4546
SkTArray<Cluster, true> fClusters;
46-
size_t fUnresolvedGlyphs;
4747
};
4848

4949
uint32_t ParagraphCache::KeyHash::mix(uint32_t hash, uint32_t data) const {
@@ -56,21 +56,20 @@ uint32_t ParagraphCache::KeyHash::mix(uint32_t hash, uint32_t data) const {
5656
uint32_t ParagraphCache::KeyHash::operator()(const ParagraphCacheKey& key) const {
5757
uint32_t hash = 0;
5858
for (auto& ph : key.fPlaceholders) {
59-
if (&ph == &key.fPlaceholders.back()) {
60-
// Skip the last "dummy" placeholder
61-
break;
59+
if (ph.fRange.width() == 0) {
60+
continue;
6261
}
6362
hash = mix(hash, SkGoodHash()(ph.fRange.start));
6463
hash = mix(hash, SkGoodHash()(ph.fRange.end));
65-
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fBaselineOffset)));
66-
hash = mix(hash, SkGoodHash()(ph.fStyle.fBaseline));
64+
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fHeight)));
65+
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fWidth)));
6766
hash = mix(hash, SkGoodHash()(ph.fStyle.fAlignment));
67+
hash = mix(hash, SkGoodHash()(ph.fStyle.fBaseline));
6868
if (ph.fStyle.fAlignment == PlaceholderAlignment::kBaseline) {
6969
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fBaselineOffset)));
7070
}
71-
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fHeight)));
72-
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fWidth)));
7371
}
72+
7473
for (auto& ts : key.fTextStyles) {
7574
if (ts.fStyle.isPlaceholder()) {
7675
continue;
@@ -79,22 +78,34 @@ uint32_t ParagraphCache::KeyHash::operator()(const ParagraphCacheKey& key) const
7978
hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getWordSpacing())));
8079
hash = mix(hash, SkGoodHash()(ts.fStyle.getLocale()));
8180
hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getHeight())));
82-
hash = mix(hash, SkGoodHash()(ts.fRange));
8381
for (auto& ff : ts.fStyle.getFontFamilies()) {
8482
hash = mix(hash, SkGoodHash()(ff));
8583
}
8684
for (auto& ff : ts.fStyle.getFontFeatures()) {
87-
hash = mix(hash, SkGoodHash()(ff));
85+
hash = mix(hash, SkGoodHash()(ff.fValue));
86+
hash = mix(hash, SkGoodHash()(ff.fName));
8887
}
8988
hash = mix(hash, SkGoodHash()(ts.fStyle.getFontStyle()));
9089
hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getFontSize())));
91-
hash = mix(hash, SkGoodHash()(ts.fRange.start));
92-
hash = mix(hash, SkGoodHash()(ts.fRange.end));
90+
hash = mix(hash, SkGoodHash()(ts.fRange));
9391
}
9492

9593
hash = mix(hash, SkGoodHash()(relax(key.fParagraphStyle.getHeight())));
9694
hash = mix(hash, SkGoodHash()(key.fParagraphStyle.getTextDirection()));
9795

96+
auto& strutStyle = key.fParagraphStyle.getStrutStyle();
97+
if (strutStyle.getStrutEnabled()) {
98+
hash = mix(hash, SkGoodHash()(relax(strutStyle.getHeight())));
99+
hash = mix(hash, SkGoodHash()(relax(strutStyle.getLeading())));
100+
hash = mix(hash, SkGoodHash()(relax(strutStyle.getFontSize())));
101+
hash = mix(hash, SkGoodHash()(strutStyle.getHeightOverride()));
102+
hash = mix(hash, SkGoodHash()(strutStyle.getFontStyle()));
103+
hash = mix(hash, SkGoodHash()(strutStyle.getForceStrutHeight()));
104+
for (auto& ff : strutStyle.getFontFamilies()) {
105+
hash = mix(hash, SkGoodHash()(ff));
106+
}
107+
}
108+
98109
hash = mix(hash, SkGoodHash()(key.fText));
99110
return hash;
100111
}
@@ -114,13 +125,17 @@ bool operator==(const ParagraphCacheKey& a, const ParagraphCacheKey& b) {
114125
}
115126

116127
// There is no need to compare default paragraph styles - they are included into fTextStyles
117-
if (!SkScalarNearlyEqual(a.fParagraphStyle.getHeight(), b.fParagraphStyle.getHeight())) {
128+
if (!nearlyEqual(a.fParagraphStyle.getHeight(), b.fParagraphStyle.getHeight())) {
118129
return false;
119130
}
120131
if (a.fParagraphStyle.getTextDirection() != b.fParagraphStyle.getTextDirection()) {
121132
return false;
122133
}
123134

135+
if (!(a.fParagraphStyle.getStrutStyle() == b.fParagraphStyle.getStrutStyle())) {
136+
return false;
137+
}
138+
124139
for (size_t i = 0; i < a.fTextStyles.size(); ++i) {
125140
auto& tsa = a.fTextStyles[i];
126141
auto& tsb = b.fTextStyles[i];
@@ -137,9 +152,12 @@ bool operator==(const ParagraphCacheKey& a, const ParagraphCacheKey& b) {
137152
return false;
138153
}
139154
}
140-
for (size_t i = 0; i < a.fPlaceholders.size() - 1; ++i) {
155+
for (size_t i = 0; i < a.fPlaceholders.size(); ++i) {
141156
auto& tsa = a.fPlaceholders[i];
142157
auto& tsb = b.fPlaceholders[i];
158+
if (tsa.fRange.width() == 0 && tsb.fRange.width() == 0) {
159+
continue;
160+
}
143161
if (!(tsa.fStyle.equals(tsb.fStyle))) {
144162
return false;
145163
}
@@ -175,7 +193,6 @@ ParagraphCache::~ParagraphCache() { }
175193

176194
void ParagraphCache::updateFrom(const ParagraphImpl* paragraph, Entry* entry) {
177195

178-
entry->fValue->fInternalState = paragraph->state();
179196
for (size_t i = 0; i < paragraph->fRuns.size(); ++i) {
180197
auto& run = paragraph->fRuns[i];
181198
if (run.fSpaced) {
@@ -185,6 +202,7 @@ void ParagraphCache::updateFrom(const ParagraphImpl* paragraph, Entry* entry) {
185202
}
186203

187204
void ParagraphCache::updateTo(ParagraphImpl* paragraph, const Entry* entry) {
205+
188206
paragraph->fRuns.reset();
189207
paragraph->fRuns = entry->fValue->fRuns;
190208
for (auto& run : paragraph->fRuns) {
@@ -197,8 +215,7 @@ void ParagraphCache::updateTo(ParagraphImpl* paragraph, const Entry* entry) {
197215
cluster.setMaster(paragraph);
198216
}
199217

200-
paragraph->fState = entry->fValue->fInternalState;
201-
paragraph->fUnresolvedGlyphs = entry->fValue->fUnresolvedGlyphs;
218+
paragraph->fState = kMarked;
202219
}
203220

204221
void ParagraphCache::printStatistics() {

modules/skparagraph/src/ParagraphImpl.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ void ParagraphImpl::breakShapedTextIntoLines(SkScalar maxWidth) {
414414
}
415415
}
416416

417-
fLongestLine = SkTMax(fLongestLine, SkScalarNearlyZero(advance.fX) ? widthWithSpaces : advance.fX);
417+
fLongestLine = SkTMax(fLongestLine, nearlyZero(advance.fX) ? widthWithSpaces : advance.fX);
418418
});
419419
fHeight = textWrapper.height();
420420
fWidth = maxWidth;
@@ -427,9 +427,17 @@ void ParagraphImpl::breakShapedTextIntoLines(SkScalar maxWidth) {
427427

428428
void ParagraphImpl::formatLines(SkScalar maxWidth) {
429429
auto effectiveAlign = fParagraphStyle.effective_align();
430+
431+
if (!SkScalarIsFinite(maxWidth) && effectiveAlign != TextAlign::kLeft) {
432+
// Special case: clean all text in case of maxWidth == INF & align != left
433+
// We had to go through shaping though because we need all the measurement numbers
434+
fLines.reset();
435+
return;
436+
}
430437
if (effectiveAlign == TextAlign::kJustify) {
431438
this->resetRunShifts();
432439
}
440+
433441
for (auto& line : fLines) {
434442
if (&line == &fLines.back() && effectiveAlign == TextAlign::kJustify) {
435443
effectiveAlign = line.assumedTextAlign();
@@ -768,16 +776,16 @@ std::vector<TextBox> ParagraphImpl::getRectsForRange(unsigned start,
768776
bool mergedBoxes = false;
769777
if (!results.empty() &&
770778
lastRun != nullptr &&
771-
lastRun->placeholder() == nullptr &&
772-
context.run->placeholder() == nullptr &&
773-
SkScalarNearlyEqual(lastRun->lineHeight(), context.run->lineHeight()) &&
779+
lastRun->placeholderStyle() == nullptr &&
780+
context.run->placeholderStyle() == nullptr &&
781+
nearlyEqual(lastRun->lineHeight(), context.run->lineHeight()) &&
774782
lastRun->font() == context.run->font())
775783
{
776784
auto& lastBox = results.back();
777-
if (SkScalarNearlyEqual(lastBox.rect.fTop, clip.fTop) &&
778-
SkScalarNearlyEqual(lastBox.rect.fBottom, clip.fBottom) &&
779-
(SkScalarNearlyEqual(lastBox.rect.fLeft, clip.fRight) ||
780-
SkScalarNearlyEqual(lastBox.rect.fRight, clip.fLeft)))
785+
if (nearlyEqual(lastBox.rect.fTop, clip.fTop) &&
786+
nearlyEqual(lastBox.rect.fBottom, clip.fBottom) &&
787+
(nearlyEqual(lastBox.rect.fLeft, clip.fRight) ||
788+
nearlyEqual(lastBox.rect.fRight, clip.fLeft)))
781789
{
782790
lastBox.rect.fLeft = SkTMin(lastBox.rect.fLeft, clip.fLeft);
783791
lastBox.rect.fRight = SkTMax(lastBox.rect.fRight, clip.fRight);
@@ -792,7 +800,7 @@ std::vector<TextBox> ParagraphImpl::getRectsForRange(unsigned start,
792800
results.emplace_back(
793801
clip, context.run->leftToRight() ? TextDirection::kLtr : TextDirection::kRtl);
794802
}
795-
if (!SkScalarNearlyZero(trailingSpaces.width()) && !merge(trailingSpaces)) {
803+
if (!nearlyZero(trailingSpaces.width()) && !merge(trailingSpaces)) {
796804
results.emplace_back(trailingSpaces, paragraphTextDirection);
797805
}
798806

@@ -843,7 +851,7 @@ std::vector<TextBox> ParagraphImpl::getRectsForPlaceholders() {
843851
auto context =
844852
line.measureTextInsideOneRun(textRange, run, runOffset, 0, true, false);
845853
*width = context.clip.width();
846-
if (run->placeholder() == nullptr) {
854+
if (run->placeholderStyle() == nullptr) {
847855
return true;
848856
}
849857
if (run->textRange().width() == 0) {
@@ -1120,7 +1128,9 @@ void ParagraphImpl::computeEmptyMetrics() {
11201128
fEmptyMetrics.leading() * multiplier);
11211129
}
11221130

1123-
fStrutMetrics.updateLineMetrics(fEmptyMetrics);
1131+
if (fParagraphStyle.getStrutStyle().getStrutEnabled()) {
1132+
fStrutMetrics.updateLineMetrics(fEmptyMetrics);
1133+
}
11241134
}
11251135

11261136
void ParagraphImpl::updateText(size_t from, SkString text) {

modules/skparagraph/src/ParagraphImpl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ class ParagraphImpl final : public Paragraph {
135135
SkSpan<Block> styles() {
136136
return SkSpan<Block>(fTextStyles.data(), fTextStyles.size());
137137
}
138+
SkSpan<Placeholder> placeholders() {
139+
return SkSpan<Placeholder>(fPlaceholders.data(), fPlaceholders.size());
140+
}
138141
SkSpan<TextLine> lines() { return SkSpan<TextLine>(fLines.data(), fLines.size()); }
139142
const ParagraphStyle& paragraphStyle() const { return fParagraphStyle; }
140143
SkSpan<Cluster> clusters() { return SkSpan<Cluster>(fClusters.begin(), fClusters.size()); }

modules/skparagraph/src/Run.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Run::Run(ParagraphImpl* master,
4747
fOffsets[info.glyphCount] = { 0, 0};
4848
fClusterIndexes[info.glyphCount] = this->leftToRight() ? info.utf8Range.end() : info.utf8Range.begin();
4949
fEllipsis = false;
50-
fPlaceholder = nullptr;
50+
fPlaceholderIndex = std::numeric_limits<size_t>::max();
5151
}
5252

5353
SkShaper::RunHandler::Buffer Run::newRunBuffer() {
@@ -238,9 +238,11 @@ void Run::shift(const Cluster* cluster, SkScalar offset) {
238238

239239
void Run::updateMetrics(InternalLineMetrics* endlineMetrics) {
240240

241+
SkASSERT(isPlaceholder());
242+
auto placeholderStyle = this->placeholderStyle();
241243
// Difference between the placeholder baseline and the line bottom
242244
SkScalar baselineAdjustment = 0;
243-
switch (fPlaceholder->fBaseline) {
245+
switch (placeholderStyle->fBaseline) {
244246
case TextBaseline::kAlphabetic:
245247
break;
246248

@@ -249,11 +251,11 @@ void Run::updateMetrics(InternalLineMetrics* endlineMetrics) {
249251
break;
250252
}
251253

252-
auto height = fPlaceholder->fHeight;
253-
auto offset = fPlaceholder->fBaselineOffset;
254+
auto height = placeholderStyle->fHeight;
255+
auto offset = placeholderStyle->fBaselineOffset;
254256

255257
fFontMetrics.fLeading = 0;
256-
switch (fPlaceholder->fAlignment) {
258+
switch (placeholderStyle->fAlignment) {
257259
case PlaceholderAlignment::kBaseline:
258260
fFontMetrics.fAscent = baselineAdjustment - offset;
259261
fFontMetrics.fDescent = baselineAdjustment + height - offset;
@@ -339,6 +341,14 @@ SkScalar Run::positionX(size_t pos) const {
339341
return posX(pos) + fShifts[pos] + fMaster->posShift(fIndex, pos);
340342
}
341343

344+
PlaceholderStyle* Run::placeholderStyle() const {
345+
if (isPlaceholder()) {
346+
return &fMaster->placeholders()[fPlaceholderIndex].fStyle;
347+
} else {
348+
return nullptr;
349+
}
350+
}
351+
342352
Run* Cluster::run() const {
343353
if (fRunIndex >= fMaster->runs().size()) {
344354
return nullptr;

0 commit comments

Comments
 (0)