1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkRSXform.h"
9 #include "include/core/SkTextBlob.h"
10 #include "include/core/SkTypeface.h"
11 #include "src/core/SkFontPriv.h"
12 #include "src/core/SkGlyphRun.h"
13 #include "src/core/SkPaintPriv.h"
14 #include "src/core/SkReadBuffer.h"
15 #include "src/core/SkSafeMath.h"
16 #include "src/core/SkStrikeCache.h"
17 #include "src/core/SkStrikeSpec.h"
18 #include "src/core/SkTextBlobPriv.h"
19 #include "src/core/SkWriteBuffer.h"
20 
21 #include <atomic>
22 #include <limits>
23 #include <new>
24 
25 #if SK_SUPPORT_GPU
26 #include "src/gpu/text/GrTextBlobCache.h"
27 #endif
28 
29 namespace {
30 struct RunFontStorageEquivalent {
31     SkScalar fSize, fScaleX;
32     void*    fTypeface;
33     SkScalar fSkewX;
34     uint32_t fFlags;
35 };
36 static_assert(sizeof(SkFont) == sizeof(RunFontStorageEquivalent), "runfont_should_stay_packed");
37 }  // namespace
38 
StorageSize(uint32_t glyphCount, uint32_t textSize, SkTextBlob::GlyphPositioning positioning, SkSafeMath* safe)39 size_t SkTextBlob::RunRecord::StorageSize(uint32_t glyphCount, uint32_t textSize,
40                                           SkTextBlob::GlyphPositioning positioning,
41                                           SkSafeMath* safe) {
42     static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment");
43 
44     auto glyphSize = safe->mul(glyphCount, sizeof(uint16_t)),
45             posSize = safe->mul(PosCount(glyphCount, positioning, safe), sizeof(SkScalar));
46 
47     // RunRecord object + (aligned) glyph buffer + position buffer
48     auto size = sizeof(SkTextBlob::RunRecord);
49     size = safe->add(size, safe->alignUp(glyphSize, 4));
50     size = safe->add(size, posSize);
51 
52     if (textSize) {  // Extended run.
53         size = safe->add(size, sizeof(uint32_t));
54         size = safe->add(size, safe->mul(glyphCount, sizeof(uint32_t)));
55         size = safe->add(size, textSize);
56     }
57 
58     return safe->alignUp(size, sizeof(void*));
59 }
60 
First(const SkTextBlob* blob)61 const SkTextBlob::RunRecord* SkTextBlob::RunRecord::First(const SkTextBlob* blob) {
62     // The first record (if present) is stored following the blob object.
63     // (aligned up to make the RunRecord aligned too)
64     return reinterpret_cast<const RunRecord*>(SkAlignPtr((uintptr_t)(blob + 1)));
65 }
66 
Next(const RunRecord* run)67 const SkTextBlob::RunRecord* SkTextBlob::RunRecord::Next(const RunRecord* run) {
68     return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run);
69 }
70 
71 namespace {
72 struct RunRecordStorageEquivalent {
73     SkFont   fFont;
74     SkPoint  fOffset;
75     uint32_t fCount;
76     uint32_t fFlags;
77     SkDEBUGCODE(unsigned fMagic;)
78 };
79 }  // namespace
80 
validate(const uint8_t* storageTop) const81 void SkTextBlob::RunRecord::validate(const uint8_t* storageTop) const {
82     SkASSERT(kRunRecordMagic == fMagic);
83     SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop);
84 
85     SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
86     SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning())
87              <= (SkScalar*)NextUnchecked(this));
88     if (isExtended()) {
89         SkASSERT(textSize() > 0);
90         SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this));
91         SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this));
92         SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this));
93     }
94     static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent),
95                   "runrecord_should_stay_packed");
96 }
97 
NextUnchecked(const RunRecord* run)98 const SkTextBlob::RunRecord* SkTextBlob::RunRecord::NextUnchecked(const RunRecord* run) {
99     SkSafeMath safe;
100     auto res = reinterpret_cast<const RunRecord*>(
101             reinterpret_cast<const uint8_t*>(run)
102             + StorageSize(run->glyphCount(), run->textSize(), run->positioning(), &safe));
103     SkASSERT(safe);
104     return res;
105 }
106 
PosCount(uint32_t glyphCount, SkTextBlob::GlyphPositioning positioning, SkSafeMath* safe)107 size_t SkTextBlob::RunRecord::PosCount(uint32_t glyphCount,
108                                        SkTextBlob::GlyphPositioning positioning,
109                                        SkSafeMath* safe) {
110     return safe->mul(glyphCount, ScalarsPerGlyph(positioning));
111 }
112 
textSizePtr() const113 uint32_t* SkTextBlob::RunRecord::textSizePtr() const {
114     // textSize follows the position buffer.
115     SkASSERT(isExtended());
116     SkSafeMath safe;
117     auto res = (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning(), &safe)]);
118     SkASSERT(safe);
119     return res;
120 }
121 
grow(uint32_t count)122 void SkTextBlob::RunRecord::grow(uint32_t count) {
123     SkScalar* initialPosBuffer = posBuffer();
124     uint32_t initialCount = fCount;
125     fCount += count;
126 
127     // Move the initial pos scalars to their new location.
128     size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning());
129     SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this));
130 
131     // memmove, as the buffers may overlap
132     memmove(posBuffer(), initialPosBuffer, copySize);
133 }
134 
next_id()135 static int32_t next_id() {
136     static std::atomic<int32_t> nextID{1};
137     int32_t id;
138     do {
139         id = nextID.fetch_add(1, std::memory_order_relaxed);
140     } while (id == SK_InvalidGenID);
141     return id;
142 }
143 
SkTextBlob(const SkRect& bounds)144 SkTextBlob::SkTextBlob(const SkRect& bounds)
145     : fBounds(bounds)
146     , fUniqueID(next_id())
147     , fCacheID(SK_InvalidUniqueID) {}
148 
~SkTextBlob()149 SkTextBlob::~SkTextBlob() {
150 #if SK_SUPPORT_GPU
151     if (SK_InvalidUniqueID != fCacheID.load()) {
152         GrTextBlobCache::PostPurgeBlobMessage(fUniqueID, fCacheID);
153     }
154 #endif
155 
156     const auto* run = RunRecord::First(this);
157     do {
158         const auto* nextRun = RunRecord::Next(run);
159         SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);)
160         run->~RunRecord();
161         run = nextRun;
162     } while (run);
163 }
164 
165 namespace {
166 
167 union PositioningAndExtended {
168     int32_t intValue;
169     struct {
170         uint8_t  positioning;
171         uint8_t  extended;
172         uint16_t padding;
173     };
174 };
175 
176 static_assert(sizeof(PositioningAndExtended) == sizeof(int32_t), "");
177 
178 } // namespace
179 
180 enum SkTextBlob::GlyphPositioning : uint8_t {
181     kDefault_Positioning      = 0, // Default glyph advances -- zero scalars per glyph.
182     kHorizontal_Positioning   = 1, // Horizontal positioning -- one scalar per glyph.
183     kFull_Positioning         = 2, // Point positioning -- two scalars per glyph.
184     kRSXform_Positioning      = 3, // RSXform positioning -- four scalars per glyph.
185 };
186 
ScalarsPerGlyph(GlyphPositioning pos)187 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
188     const uint8_t gScalarsPerPositioning[] = {
189         0,  // kDefault_Positioning
190         1,  // kHorizontal_Positioning
191         2,  // kFull_Positioning
192         4,  // kRSXform_Positioning
193     };
194     SkASSERT((unsigned)pos <= 3);
195     return gScalarsPerPositioning[pos];
196 }
197 
operator delete(void* p)198 void SkTextBlob::operator delete(void* p) {
199     sk_free(p);
200 }
201 
operator new(size_t)202 void* SkTextBlob::operator new(size_t) {
203     SK_ABORT("All blobs are created by placement new.");
204 }
205 
operator new(size_t, void* p)206 void* SkTextBlob::operator new(size_t, void* p) {
207     return p;
208 }
209 
SkTextBlobRunIterator(const SkTextBlob* blob)210 SkTextBlobRunIterator::SkTextBlobRunIterator(const SkTextBlob* blob)
211     : fCurrentRun(SkTextBlob::RunRecord::First(blob)) {
212     SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;)
213 }
214 
next()215 void SkTextBlobRunIterator::next() {
216     SkASSERT(!this->done());
217 
218     if (!this->done()) {
219         SkDEBUGCODE(fCurrentRun->validate(fStorageTop);)
220         fCurrentRun = SkTextBlob::RunRecord::Next(fCurrentRun);
221     }
222 }
223 
positioning() const224 SkTextBlobRunIterator::GlyphPositioning SkTextBlobRunIterator::positioning() const {
225     SkASSERT(!this->done());
226     static_assert(static_cast<GlyphPositioning>(SkTextBlob::kDefault_Positioning) ==
227                   kDefault_Positioning, "");
228     static_assert(static_cast<GlyphPositioning>(SkTextBlob::kHorizontal_Positioning) ==
229                   kHorizontal_Positioning, "");
230     static_assert(static_cast<GlyphPositioning>(SkTextBlob::kFull_Positioning) ==
231                   kFull_Positioning, "");
232     static_assert(static_cast<GlyphPositioning>(SkTextBlob::kRSXform_Positioning) ==
233                   kRSXform_Positioning, "");
234 
235     return SkTo<GlyphPositioning>(fCurrentRun->positioning());
236 }
237 
scalarsPerGlyph() const238 unsigned SkTextBlobRunIterator::scalarsPerGlyph() const {
239     return SkTextBlob::ScalarsPerGlyph(fCurrentRun->positioning());
240 }
241 
isLCD() const242 bool SkTextBlobRunIterator::isLCD() const {
243     return fCurrentRun->font().getEdging() == SkFont::Edging::kSubpixelAntiAlias;
244 }
245 
SkTextBlobBuilder()246 SkTextBlobBuilder::SkTextBlobBuilder()
247     : fStorageSize(0)
248     , fStorageUsed(0)
249     , fRunCount(0)
250     , fDeferredBounds(false)
251     , fLastRun(0) {
252     fBounds.setEmpty();
253 }
254 
~SkTextBlobBuilder()255 SkTextBlobBuilder::~SkTextBlobBuilder() {
256     if (nullptr != fStorage.get()) {
257         // We are abandoning runs and must destruct the associated font data.
258         // The easiest way to accomplish that is to use the blob destructor.
259         this->make();
260     }
261 }
262 
map_quad_to_rect(const SkRSXform& xform, const SkRect& rect)263 static SkRect map_quad_to_rect(const SkRSXform& xform, const SkRect& rect) {
264     return SkMatrix().setRSXform(xform).mapRect(rect);
265 }
266 
TightRunBounds(const SkTextBlob::RunRecord& run)267 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) {
268     const SkFont& font = run.font();
269     SkRect bounds;
270 
271     if (SkTextBlob::kDefault_Positioning == run.positioning()) {
272         font.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t),
273                          SkTextEncoding::kGlyphID, &bounds);
274         return bounds.makeOffset(run.offset().x(), run.offset().y());
275     }
276 
277     SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount());
278     font.getBounds(run.glyphBuffer(), run.glyphCount(), glyphBounds.get(), nullptr);
279 
280     if (SkTextBlob::kRSXform_Positioning == run.positioning()) {
281         bounds.setEmpty();
282         const SkRSXform* xform = run.xformBuffer();
283         SkASSERT((void*)(xform + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
284         for (unsigned i = 0; i < run.glyphCount(); ++i) {
285             bounds.join(map_quad_to_rect(xform[i], glyphBounds[i]));
286         }
287     } else {
288         SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
289                  SkTextBlob::kHorizontal_Positioning == run.positioning());
290         // kFull_Positioning       => [ x, y, x, y... ]
291         // kHorizontal_Positioning => [ x, x, x... ]
292         //                            (const y applied by runBounds.offset(run->offset()) later)
293         const SkScalar horizontalConstY = 0;
294         const SkScalar* glyphPosX = run.posBuffer();
295         const SkScalar* glyphPosY = (run.positioning() == SkTextBlob::kFull_Positioning) ?
296                                                         glyphPosX + 1 : &horizontalConstY;
297         const unsigned posXInc = SkTextBlob::ScalarsPerGlyph(run.positioning());
298         const unsigned posYInc = (run.positioning() == SkTextBlob::kFull_Positioning) ?
299                                                     posXInc : 0;
300 
301         bounds.setEmpty();
302         for (unsigned i = 0; i < run.glyphCount(); ++i) {
303             bounds.join(glyphBounds[i].makeOffset(*glyphPosX, *glyphPosY));
304             glyphPosX += posXInc;
305             glyphPosY += posYInc;
306         }
307 
308         SkASSERT((void*)glyphPosX <= SkTextBlob::RunRecord::Next(&run));
309     }
310     return bounds.makeOffset(run.offset().x(), run.offset().y());
311 }
312 
ConservativeRunBounds(const SkTextBlob::RunRecord& run)313 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run) {
314     SkASSERT(run.glyphCount() > 0);
315     SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
316              SkTextBlob::kHorizontal_Positioning == run.positioning() ||
317              SkTextBlob::kRSXform_Positioning == run.positioning());
318 
319     const SkRect fontBounds = SkFontPriv::GetFontBounds(run.font());
320     if (fontBounds.isEmpty()) {
321         // Empty font bounds are likely a font bug.  TightBounds has a better chance of
322         // producing useful results in this case.
323         return TightRunBounds(run);
324     }
325 
326     // Compute the glyph position bbox.
327     SkRect bounds;
328     switch (run.positioning()) {
329     case SkTextBlob::kHorizontal_Positioning: {
330         const SkScalar* glyphPos = run.posBuffer();
331         SkASSERT((void*)(glyphPos + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
332 
333         SkScalar minX = *glyphPos;
334         SkScalar maxX = *glyphPos;
335         for (unsigned i = 1; i < run.glyphCount(); ++i) {
336             SkScalar x = glyphPos[i];
337             minX = std::min(x, minX);
338             maxX = std::max(x, maxX);
339         }
340 
341         bounds.setLTRB(minX, 0, maxX, 0);
342     } break;
343     case SkTextBlob::kFull_Positioning: {
344         const SkPoint* glyphPosPts = run.pointBuffer();
345         SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
346 
347         bounds.setBounds(glyphPosPts, run.glyphCount());
348     } break;
349     case SkTextBlob::kRSXform_Positioning: {
350         const SkRSXform* xform = run.xformBuffer();
351         SkASSERT((void*)(xform + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
352         bounds.setEmpty();
353         for (unsigned i = 0; i < run.glyphCount(); ++i) {
354             bounds.join(map_quad_to_rect(xform[i], fontBounds));
355         }
356     } break;
357     default:
358         SK_ABORT("unsupported positioning mode");
359     }
360 
361     if (run.positioning() != SkTextBlob::kRSXform_Positioning) {
362         // Expand by typeface glyph bounds.
363         bounds.fLeft   += fontBounds.left();
364         bounds.fTop    += fontBounds.top();
365         bounds.fRight  += fontBounds.right();
366         bounds.fBottom += fontBounds.bottom();
367     }
368 
369     // Offset by run position.
370     return bounds.makeOffset(run.offset().x(), run.offset().y());
371 }
372 
updateDeferredBounds()373 void SkTextBlobBuilder::updateDeferredBounds() {
374     SkASSERT(!fDeferredBounds || fRunCount > 0);
375 
376     if (!fDeferredBounds) {
377         return;
378     }
379 
380     SkASSERT(fLastRun >= SkAlignPtr(sizeof(SkTextBlob)));
381     SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
382                                                                           fLastRun);
383 
384     // FIXME: we should also use conservative bounds for kDefault_Positioning.
385     SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ?
386                        TightRunBounds(*run) : ConservativeRunBounds(*run);
387     fBounds.join(runBounds);
388     fDeferredBounds = false;
389 }
390 
reserve(size_t size)391 void SkTextBlobBuilder::reserve(size_t size) {
392     SkSafeMath safe;
393 
394     // We don't currently pre-allocate, but maybe someday...
395     if (safe.add(fStorageUsed, size) <= fStorageSize && safe) {
396         return;
397     }
398 
399     if (0 == fRunCount) {
400         SkASSERT(nullptr == fStorage.get());
401         SkASSERT(0 == fStorageSize);
402         SkASSERT(0 == fStorageUsed);
403 
404         // the first allocation also includes blob storage
405         // aligned up to a pointer alignment so SkTextBlob::RunRecords after it stay aligned.
406         fStorageUsed = SkAlignPtr(sizeof(SkTextBlob));
407     }
408 
409     fStorageSize = safe.add(fStorageUsed, size);
410 
411     // FYI: This relies on everything we store being relocatable, particularly SkPaint.
412     //      Also, this is counting on the underlying realloc to throw when passed max().
413     fStorage.realloc(safe ? fStorageSize : std::numeric_limits<size_t>::max());
414 }
415 
mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning, uint32_t count, SkPoint offset)416 bool SkTextBlobBuilder::mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning,
417                                  uint32_t count, SkPoint offset) {
418     if (0 == fLastRun) {
419         SkASSERT(0 == fRunCount);
420         return false;
421     }
422 
423     SkASSERT(fLastRun >= SkAlignPtr(sizeof(SkTextBlob)));
424     SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
425                                                                           fLastRun);
426     SkASSERT(run->glyphCount() > 0);
427 
428     if (run->textSize() != 0) {
429         return false;
430     }
431 
432     if (run->positioning() != positioning
433         || run->font() != font
434         || (run->glyphCount() + count < run->glyphCount())) {
435         return false;
436     }
437 
438     // we can merge same-font/same-positioning runs in the following cases:
439     //   * fully positioned run following another fully positioned run
440     //   * horizontally postioned run following another horizontally positioned run with the same
441     //     y-offset
442     if (SkTextBlob::kFull_Positioning != positioning
443         && (SkTextBlob::kHorizontal_Positioning != positioning
444             || run->offset().y() != offset.y())) {
445         return false;
446     }
447 
448     SkSafeMath safe;
449     size_t sizeDelta =
450         SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, 0, positioning, &safe) -
451         SkTextBlob::RunRecord::StorageSize(run->glyphCount()        , 0, positioning, &safe);
452     if (!safe) {
453         return false;
454     }
455 
456     this->reserve(sizeDelta);
457 
458     // reserve may have realloced
459     run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
460     uint32_t preMergeCount = run->glyphCount();
461     run->grow(count);
462 
463     // Callers expect the buffers to point at the newly added slice, ant not at the beginning.
464     fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount;
465     fCurrentRunBuffer.pos = run->posBuffer()
466                           + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning);
467 
468     fStorageUsed += sizeDelta;
469 
470     SkASSERT(fStorageUsed <= fStorageSize);
471     run->validate(fStorage.get() + fStorageUsed);
472 
473     return true;
474 }
475 
allocInternal(const SkFont& font, SkTextBlob::GlyphPositioning positioning, int count, int textSize, SkPoint offset, const SkRect* bounds)476 void SkTextBlobBuilder::allocInternal(const SkFont& font,
477                                       SkTextBlob::GlyphPositioning positioning,
478                                       int count, int textSize, SkPoint offset,
479                                       const SkRect* bounds) {
480     if (count <= 0 || textSize < 0) {
481         fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr };
482         return;
483     }
484 
485     if (textSize != 0 || !this->mergeRun(font, positioning, count, offset)) {
486         this->updateDeferredBounds();
487 
488         SkSafeMath safe;
489         size_t runSize = SkTextBlob::RunRecord::StorageSize(count, textSize, positioning, &safe);
490         if (!safe) {
491             fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr };
492             return;
493         }
494 
495         this->reserve(runSize);
496 
497         SkASSERT(fStorageUsed >= SkAlignPtr(sizeof(SkTextBlob)));
498         SkASSERT(fStorageUsed + runSize <= fStorageSize);
499 
500         SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed)
501             SkTextBlob::RunRecord(count, textSize, offset, font, positioning);
502         fCurrentRunBuffer.glyphs = run->glyphBuffer();
503         fCurrentRunBuffer.pos = run->posBuffer();
504         fCurrentRunBuffer.utf8text = run->textBuffer();
505         fCurrentRunBuffer.clusters = run->clusterBuffer();
506 
507         fLastRun = fStorageUsed;
508         fStorageUsed += runSize;
509         fRunCount++;
510 
511         SkASSERT(fStorageUsed <= fStorageSize);
512         run->validate(fStorage.get() + fStorageUsed);
513     }
514     SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.utf8text);
515     SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.clusters);
516     if (!fDeferredBounds) {
517         if (bounds) {
518             fBounds.join(*bounds);
519         } else {
520             fDeferredBounds = true;
521         }
522     }
523 }
524 
525 // SkFont versions
526 
allocRun(const SkFont& font, int count, SkScalar x, SkScalar y, const SkRect* bounds)527 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRun(const SkFont& font, int count,
528                                                                 SkScalar x, SkScalar y,
529                                                                 const SkRect* bounds) {
530     this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, 0, {x, y}, bounds);
531     return fCurrentRunBuffer;
532 }
533 
allocRunPosH(const SkFont& font, int count, SkScalar y, const SkRect* bounds)534 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPosH(const SkFont& font, int count,
535                                                                     SkScalar y,
536                                                                     const SkRect* bounds) {
537     this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, 0, {0, y}, bounds);
538     return fCurrentRunBuffer;
539 }
540 
allocRunPos(const SkFont& font, int count, const SkRect* bounds)541 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkFont& font, int count,
542                                                                    const SkRect* bounds) {
543     this->allocInternal(font, SkTextBlob::kFull_Positioning, count, 0, {0, 0}, bounds);
544     return fCurrentRunBuffer;
545 }
546 
547 const SkTextBlobBuilder::RunBuffer&
allocRunRSXform(const SkFont& font, int count)548 SkTextBlobBuilder::allocRunRSXform(const SkFont& font, int count) {
549     this->allocInternal(font, SkTextBlob::kRSXform_Positioning, count, 0, {0, 0}, nullptr);
550     return fCurrentRunBuffer;
551 }
552 
allocRunText(const SkFont& font, int count, SkScalar x, SkScalar y, int textByteCount, const SkRect* bounds)553 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunText(const SkFont& font, int count,
554                                                                     SkScalar x, SkScalar y,
555                                                                     int textByteCount,
556                                                                     const SkRect* bounds) {
557     this->allocInternal(font,
558                         SkTextBlob::kDefault_Positioning,
559                         count,
560                         textByteCount,
561                         SkPoint::Make(x, y),
562                         bounds);
563     return fCurrentRunBuffer;
564 }
565 
allocRunTextPosH(const SkFont& font, int count, SkScalar y, int textByteCount, const SkRect* bounds)566 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPosH(const SkFont& font,
567                                                                         int count,
568                                                                         SkScalar y,
569                                                                         int textByteCount,
570                                                                         const SkRect* bounds) {
571     this->allocInternal(font,
572                         SkTextBlob::kHorizontal_Positioning,
573                         count,
574                         textByteCount,
575                         SkPoint::Make(0, y),
576                         bounds);
577     return fCurrentRunBuffer;
578 }
579 
allocRunTextPos(const SkFont& font, int count, int textByteCount, const SkRect *bounds)580 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkFont& font,
581                                                                        int count,
582                                                                        int textByteCount,
583                                                                        const SkRect *bounds) {
584     this->allocInternal(font,
585                         SkTextBlob::kFull_Positioning,
586                         count, textByteCount,
587                         SkPoint::Make(0, 0),
588                         bounds);
589     return fCurrentRunBuffer;
590 }
591 
allocRunTextRSXform(const SkFont& font, int count, int textByteCount, const SkRect *bounds)592 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextRSXform(const SkFont& font,
593                                                                            int count,
594                                                                            int textByteCount,
595                                                                            const SkRect *bounds) {
596     this->allocInternal(font,
597                         SkTextBlob::kRSXform_Positioning,
598                         count,
599                         textByteCount,
600                         {0, 0},
601                         bounds);
602     return fCurrentRunBuffer;
603 }
604 
make()605 sk_sp<SkTextBlob> SkTextBlobBuilder::make() {
606     if (!fRunCount) {
607         // We don't instantiate empty blobs.
608         SkASSERT(!fStorage.get());
609         SkASSERT(fStorageUsed == 0);
610         SkASSERT(fStorageSize == 0);
611         SkASSERT(fLastRun == 0);
612         SkASSERT(fBounds.isEmpty());
613         return nullptr;
614     }
615 
616     this->updateDeferredBounds();
617 
618     // Tag the last run as such.
619     auto* lastRun = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
620     lastRun->fFlags |= SkTextBlob::RunRecord::kLast_Flag;
621 
622     SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fBounds);
623     SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;)
624 
625     SkDEBUGCODE(
626         SkSafeMath safe;
627         size_t validateSize = SkAlignPtr(sizeof(SkTextBlob));
628         for (const auto* run = SkTextBlob::RunRecord::First(blob); run;
629              run = SkTextBlob::RunRecord::Next(run)) {
630             validateSize += SkTextBlob::RunRecord::StorageSize(
631                     run->fCount, run->textSize(), run->positioning(), &safe);
632             run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed);
633             fRunCount--;
634         }
635         SkASSERT(validateSize == fStorageUsed);
636         SkASSERT(fRunCount == 0);
637         SkASSERT(safe);
638     )
639 
640     fStorageUsed = 0;
641     fStorageSize = 0;
642     fRunCount = 0;
643     fLastRun = 0;
644     fBounds.setEmpty();
645 
646     return sk_sp<SkTextBlob>(blob);
647 }
648 
649 ///////////////////////////////////////////////////////////////////////////////////////////////////
650 
Flatten(const SkTextBlob& blob, SkWriteBuffer& buffer)651 void SkTextBlobPriv::Flatten(const SkTextBlob& blob, SkWriteBuffer& buffer) {
652     // seems like we could skip this, and just recompute bounds in unflatten, but
653     // some cc_unittests fail if we remove this...
654     buffer.writeRect(blob.bounds());
655 
656     SkTextBlobRunIterator it(&blob);
657     while (!it.done()) {
658         SkASSERT(it.glyphCount() > 0);
659 
660         buffer.write32(it.glyphCount());
661         PositioningAndExtended pe;
662         pe.intValue = 0;
663         pe.positioning = it.positioning();
664         SkASSERT((int32_t)it.positioning() == pe.intValue);  // backwards compat.
665 
666         uint32_t textSize = it.textSize();
667         pe.extended = textSize > 0;
668         buffer.write32(pe.intValue);
669         if (pe.extended) {
670             buffer.write32(textSize);
671         }
672         buffer.writePoint(it.offset());
673 
674         SkFontPriv::Flatten(it.font(), buffer);
675 
676         buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t));
677         buffer.writeByteArray(it.pos(),
678                               it.glyphCount() * sizeof(SkScalar) *
679                               SkTextBlob::ScalarsPerGlyph(
680                                   SkTo<SkTextBlob::GlyphPositioning>(it.positioning())));
681         if (pe.extended) {
682             buffer.writeByteArray(it.clusters(), sizeof(uint32_t) * it.glyphCount());
683             buffer.writeByteArray(it.text(), it.textSize());
684         }
685 
686         it.next();
687     }
688 
689     // Marker for the last run (0 is not a valid glyph count).
690     buffer.write32(0);
691 }
692 
MakeFromBuffer(SkReadBuffer& reader)693 sk_sp<SkTextBlob> SkTextBlobPriv::MakeFromBuffer(SkReadBuffer& reader) {
694     SkRect bounds;
695     reader.readRect(&bounds);
696 
697     SkTextBlobBuilder blobBuilder;
698     SkSafeMath safe;
699     for (;;) {
700         int glyphCount = reader.read32();
701         if (glyphCount == 0) {
702             // End-of-runs marker.
703             break;
704         }
705 
706         PositioningAndExtended pe;
707         pe.intValue = reader.read32();
708         const auto pos = SkTo<SkTextBlob::GlyphPositioning>(pe.positioning);
709         if (glyphCount <= 0 || pos > SkTextBlob::kRSXform_Positioning) {
710             return nullptr;
711         }
712         int textSize = pe.extended ? reader.read32() : 0;
713         if (textSize < 0) {
714             return nullptr;
715         }
716 
717         SkPoint offset;
718         reader.readPoint(&offset);
719         SkFont font;
720         SkFontPriv::Unflatten(&font, reader);
721 
722         // Compute the expected size of the buffer and ensure we have enough to deserialize
723         // a run before allocating it.
724         const size_t glyphSize = safe.mul(glyphCount, sizeof(uint16_t)),
725                      posSize =
726                              safe.mul(glyphCount, safe.mul(sizeof(SkScalar),
727                              SkTextBlob::ScalarsPerGlyph(pos))),
728                      clusterSize = pe.extended ? safe.mul(glyphCount, sizeof(uint32_t)) : 0;
729         const size_t totalSize =
730                 safe.add(safe.add(glyphSize, posSize), safe.add(clusterSize, textSize));
731 
732         if (!reader.isValid() || !safe || totalSize > reader.available()) {
733             return nullptr;
734         }
735 
736         const SkTextBlobBuilder::RunBuffer* buf = nullptr;
737         switch (pos) {
738             case SkTextBlob::kDefault_Positioning:
739                 buf = &blobBuilder.allocRunText(font, glyphCount, offset.x(), offset.y(),
740                                                 textSize, &bounds);
741                 break;
742             case SkTextBlob::kHorizontal_Positioning:
743                 buf = &blobBuilder.allocRunTextPosH(font, glyphCount, offset.y(),
744                                                     textSize, &bounds);
745                 break;
746             case SkTextBlob::kFull_Positioning:
747                 buf = &blobBuilder.allocRunTextPos(font, glyphCount, textSize, &bounds);
748                 break;
749             case SkTextBlob::kRSXform_Positioning:
750                 buf = &blobBuilder.allocRunTextRSXform(font, glyphCount, textSize, &bounds);
751                 break;
752         }
753 
754         if (!buf->glyphs ||
755             !buf->pos ||
756             (pe.extended && (!buf->clusters || !buf->utf8text))) {
757             return nullptr;
758         }
759 
760         if (!reader.readByteArray(buf->glyphs, glyphSize) ||
761             !reader.readByteArray(buf->pos, posSize)) {
762             return nullptr;
763             }
764 
765         if (pe.extended) {
766             if (!reader.readByteArray(buf->clusters, clusterSize) ||
767                 !reader.readByteArray(buf->utf8text, textSize)) {
768                 return nullptr;
769             }
770         }
771     }
772 
773     return blobBuilder.make();
774 }
775 
MakeFromText(const void* text, size_t byteLength, const SkFont& font, SkTextEncoding encoding)776 sk_sp<SkTextBlob> SkTextBlob::MakeFromText(const void* text, size_t byteLength, const SkFont& font,
777                                            SkTextEncoding encoding) {
778     // Note: we deliberately promote this to fully positioned blobs, since we'd have to pay the
779     // same cost down stream (i.e. computing bounds), so its cheaper to pay the cost once now.
780     const int count = font.countText(text, byteLength, encoding);
781     if (count < 1) {
782         return nullptr;
783     }
784     SkTextBlobBuilder builder;
785     auto buffer = builder.allocRunPos(font, count);
786     font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
787     font.getPos(buffer.glyphs, count, buffer.points(), {0, 0});
788     return builder.make();
789 }
790 
MakeFromPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkFont& font, SkTextEncoding encoding)791 sk_sp<SkTextBlob> SkTextBlob::MakeFromPosText(const void* text, size_t byteLength,
792                                               const SkPoint pos[], const SkFont& font,
793                                               SkTextEncoding encoding) {
794     const int count = font.countText(text, byteLength, encoding);
795     if (count < 1) {
796         return nullptr;
797     }
798     SkTextBlobBuilder builder;
799     auto buffer = builder.allocRunPos(font, count);
800     font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
801     memcpy(buffer.points(), pos, count * sizeof(SkPoint));
802     return builder.make();
803 }
804 
MakeFromPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkFont& font, SkTextEncoding encoding)805 sk_sp<SkTextBlob> SkTextBlob::MakeFromPosTextH(const void* text, size_t byteLength,
806                                                const SkScalar xpos[], SkScalar constY,
807                                                const SkFont& font, SkTextEncoding encoding) {
808     const int count = font.countText(text, byteLength, encoding);
809     if (count < 1) {
810         return nullptr;
811     }
812     SkTextBlobBuilder builder;
813     auto buffer = builder.allocRunPosH(font, count, constY);
814     font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
815     memcpy(buffer.pos, xpos, count * sizeof(SkScalar));
816     return builder.make();
817 }
818 
MakeFromRSXform(const void* text, size_t byteLength, const SkRSXform xform[], const SkFont& font, SkTextEncoding encoding)819 sk_sp<SkTextBlob> SkTextBlob::MakeFromRSXform(const void* text, size_t byteLength,
820                                               const SkRSXform xform[], const SkFont& font,
821                                               SkTextEncoding encoding) {
822     const int count = font.countText(text, byteLength, encoding);
823     if (count < 1) {
824         return nullptr;
825     }
826     SkTextBlobBuilder builder;
827     auto buffer = builder.allocRunRSXform(font, count);
828     font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
829     memcpy(buffer.xforms(), xform, count * sizeof(SkRSXform));
830     return builder.make();
831 }
832 
serialize(const SkSerialProcs& procs) const833 sk_sp<SkData> SkTextBlob::serialize(const SkSerialProcs& procs) const {
834     SkBinaryWriteBuffer buffer;
835     buffer.setSerialProcs(procs);
836     SkTextBlobPriv::Flatten(*this, buffer);
837 
838     size_t total = buffer.bytesWritten();
839     sk_sp<SkData> data = SkData::MakeUninitialized(total);
840     buffer.writeToMemory(data->writable_data());
841     return data;
842 }
843 
Deserialize(const void* data, size_t length, const SkDeserialProcs& procs)844 sk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length,
845                                           const SkDeserialProcs& procs) {
846     SkReadBuffer buffer(data, length);
847     buffer.setDeserialProcs(procs);
848     return SkTextBlobPriv::MakeFromBuffer(buffer);
849 }
850 
dump(std::string& desc, int depth) const851 void SkTextBlob::dump(std::string& desc, int depth) const {
852     std::string split(depth, '\t');
853     desc += split + "\n SkTextBlob:{ \n";
854     fBounds.dump(desc, depth + 1);
855     desc += split + "\t fUniqueID:" + std::to_string(fUniqueID) + "\n";
856     desc += split + "}\n";
857 }
858 
859 ///////////////////////////////////////////////////////////////////////////////////////////////////
860 
serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const861 size_t SkTextBlob::serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const {
862     SkBinaryWriteBuffer buffer(memory, memory_size);
863     buffer.setSerialProcs(procs);
864     SkTextBlobPriv::Flatten(*this, buffer);
865     return buffer.usingInitialStorage() ? buffer.bytesWritten() : 0u;
866 }
867 
868 ///////////////////////////////////////////////////////////////////////////////////////////////////
869 
870 namespace {
get_glyph_run_intercepts(const SkGlyphRun& glyphRun, const SkPaint& paint, const SkScalar bounds[2], SkScalar intervals[], int* intervalCount)871 int get_glyph_run_intercepts(const SkGlyphRun& glyphRun,
872                              const SkPaint& paint,
873                              const SkScalar bounds[2],
874                              SkScalar intervals[],
875                              int* intervalCount) {
876     SkScalar scale = SK_Scalar1;
877     SkPaint interceptPaint{paint};
878     SkFont interceptFont{glyphRun.font()};
879 
880     interceptPaint.setMaskFilter(nullptr);   // don't want this affecting our path-cache lookup
881 
882     // can't use our canonical size if we need to apply path effects
883     if (interceptPaint.getPathEffect() == nullptr) {
884         // If the wrong size is going to be used, don't hint anything.
885         interceptFont.setHinting(SkFontHinting::kNone);
886         interceptFont.setSubpixel(true);
887         scale = interceptFont.getSize() / SkFontPriv::kCanonicalTextSizeForPaths;
888         interceptFont.setSize(SkIntToScalar(SkFontPriv::kCanonicalTextSizeForPaths));
889         // Note: fScale can be zero here (even if it wasn't before the divide). It can also
890         // be very very small. We call sk_ieee_float_divide below to ensure IEEE divide behavior,
891         // since downstream we will check for the resulting coordinates being non-finite anyway.
892         // Thus we don't need to check for zero here.
893         if (interceptPaint.getStrokeWidth() > 0
894             && interceptPaint.getStyle() != SkPaint::kFill_Style) {
895             interceptPaint.setStrokeWidth(
896                     sk_ieee_float_divide(interceptPaint.getStrokeWidth(), scale));
897         }
898     }
899 
900     interceptPaint.setStyle(SkPaint::kFill_Style);
901     interceptPaint.setPathEffect(nullptr);
902 
903     SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(interceptFont, &interceptPaint);
904     SkBulkGlyphMetricsAndPaths metricsAndPaths{strikeSpec};
905 
906     const SkPoint* posCursor = glyphRun.positions().begin();
907     for (const SkGlyph* glyph : metricsAndPaths.glyphs(glyphRun.glyphsIDs())) {
908         SkPoint pos = *posCursor++;
909 
910         if (glyph->path() != nullptr) {
911             // The typeface is scaled, so un-scale the bounds to be in the space of the typeface.
912             // Also ensure the bounds are properly offset by the vertical positioning of the glyph.
913             SkScalar scaledBounds[2] = {
914                 (bounds[0] - pos.y()) / scale,
915                 (bounds[1] - pos.y()) / scale
916             };
917             metricsAndPaths.findIntercepts(
918                     scaledBounds, scale, pos.x(), glyph, intervals, intervalCount);
919         }
920     }
921     return *intervalCount;
922 }
923 }  // namespace
924 
getIntercepts(const SkScalar bounds[2], SkScalar intervals[], const SkPaint* paint) const925 int SkTextBlob::getIntercepts(const SkScalar bounds[2], SkScalar intervals[],
926                               const SkPaint* paint) const {
927     SkTLazy<SkPaint> defaultPaint;
928     if (paint == nullptr) {
929         defaultPaint.init();
930         paint = defaultPaint.get();
931     }
932 
933     SkGlyphRunBuilder builder;
934     auto glyphRunList = builder.blobToGlyphRunList(*this, {0, 0});
935 
936     int intervalCount = 0;
937     for (const SkGlyphRun& glyphRun : glyphRunList) {
938         // Ignore RSXForm runs.
939         if (glyphRun.scaledRotations().empty()) {
940             intervalCount = get_glyph_run_intercepts(
941                 glyphRun, *paint, bounds, intervals, &intervalCount);
942         }
943     }
944 
945     return intervalCount;
946 }
947 
getIntercepts(const SkGlyphID glyphs[], int count, const SkPoint positions[], SkScalar top, SkScalar bottom, const SkPaint* paintPtr) const948 std::vector<SkScalar> SkFont::getIntercepts(const SkGlyphID glyphs[], int count,
949                                             const SkPoint positions[],
950                                             SkScalar top, SkScalar bottom,
951                                             const SkPaint* paintPtr) const {
952     if (count <= 0) {
953         return std::vector<SkScalar>();
954     }
955 
956     const SkPaint paint(paintPtr ? *paintPtr : SkPaint());
957     const SkScalar bounds[] = {top, bottom};
958     const SkGlyphRun run(*this,
959                          {positions, size_t(count)}, {glyphs, size_t(count)},
960                          {nullptr, 0}, {nullptr, 0}, {nullptr, 0});
961 
962     std::vector<SkScalar> result;
963     result.resize(count * 2);   // worst case allocation
964     int intervalCount = 0;
965     intervalCount = get_glyph_run_intercepts(run, paint, bounds, result.data(), &intervalCount);
966     result.resize(intervalCount);
967     return result;
968 }
969 
970 ////////
971 
Iter(const SkTextBlob& blob)972 SkTextBlob::Iter::Iter(const SkTextBlob& blob) {
973     fRunRecord = RunRecord::First(&blob);
974 }
975 
next(Run* rec)976 bool SkTextBlob::Iter::next(Run* rec) {
977     if (fRunRecord) {
978         if (rec) {
979             rec->fTypeface = fRunRecord->font().getTypeface();
980             rec->fGlyphCount = fRunRecord->glyphCount();
981             rec->fGlyphIndices = fRunRecord->glyphBuffer();
982 #ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED
983             rec->fClusterIndex_forTest = fRunRecord->clusterBuffer();
984             rec->fUtf8Size_forTest = fRunRecord->textSize();
985             rec->fUtf8_forTest = fRunRecord->textBuffer();
986 #endif
987         }
988         if (fRunRecord->isLastRun()) {
989             fRunRecord = nullptr;
990         } else {
991             fRunRecord = RunRecord::Next(fRunRecord);
992         }
993         return true;
994     }
995     return false;
996 }
997 
experimentalNext(ExperimentalRun* rec)998 bool SkTextBlob::Iter::experimentalNext(ExperimentalRun* rec) {
999     if (fRunRecord) {
1000         if (rec) {
1001             rec->font = fRunRecord->font();
1002             rec->count = fRunRecord->glyphCount();
1003             rec->glyphs = fRunRecord->glyphBuffer();
1004             rec->positions = fRunRecord->pointBuffer();
1005         }
1006         if (fRunRecord->isLastRun()) {
1007             fRunRecord = nullptr;
1008         } else {
1009             fRunRecord = RunRecord::Next(fRunRecord);
1010         }
1011         return true;
1012     }
1013     return false;
1014 }
1015 
GetGlyphIDforTextBlob(const SkTextBlob* blob, std::vector<SkGlyphID>& glyphIds)1016 void GetGlyphIDforTextBlob(const SkTextBlob* blob, std::vector<SkGlyphID>& glyphIds)
1017 {
1018     if (blob == nullptr) {
1019         return;
1020     }
1021     SkTextBlobRunIterator it(blob);
1022     if (!it.done()) {
1023         size_t runSize = it.glyphCount();
1024         auto glyphIDs = it.glyphs();
1025         for (size_t i = 0; i < runSize; ++i) {
1026             glyphIds.push_back(glyphIDs[i]);
1027         }
1028     }
1029 }
1030 
GetPathforTextBlob(const SkGlyphID& glyphId, const SkTextBlob* blob)1031 SkPath GetPathforTextBlob(const SkGlyphID& glyphId, const SkTextBlob* blob)
1032 {
1033     SkPath path;
1034     if (blob == nullptr) {
1035         return path;
1036     }
1037     SkTextBlobRunIterator it(blob);
1038     if (!it.done()) {
1039         SkFont font = it.font();
1040         font.getPath(glyphId, &path);
1041     }
1042     return path;
1043 }
1044 
GetPointsForTextBlob(const SkTextBlob* blob, std::vector<SkPoint>& points)1045 void GetPointsForTextBlob(const SkTextBlob* blob, std::vector<SkPoint>& points)
1046 {
1047     if (blob == nullptr) {
1048         return;
1049     }
1050     SkTextBlobRunIterator run(blob);
1051     if (!run.done()) {
1052         const auto glyphCount = run.glyphCount();
1053         switch (run.positioning()) {
1054             case SkTextBlobRunIterator::kFull_Positioning: {
1055                 for (auto i = 0; i < glyphCount; i++) {
1056                     const SkPoint* glyphPoints = run.points();
1057                     const auto* point = glyphPoints + i;
1058                     points.push_back(*point);
1059                 }
1060                 break;
1061             }
1062             default:
1063                 break;
1064         }
1065         run.next();
1066     }
1067 }
1068