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 "SkTextBlobRunIterator.h"
9 
10 #include "SkReadBuffer.h"
11 #include "SkSafeMath.h"
12 #include "SkTypeface.h"
13 #include "SkWriteBuffer.h"
14 
15 #include <limits>
16 
17 #if SK_SUPPORT_GPU
18 #include "text/GrTextBlobCache.h"
19 #endif
20 
21 namespace {
22 
23 // TODO(fmalita): replace with SkFont.
24 class RunFont : SkNoncopyable {
25 public:
RunFont(const SkPaint & paint)26     RunFont(const SkPaint& paint)
27         : fSize(paint.getTextSize())
28         , fScaleX(paint.getTextScaleX())
29         , fTypeface(SkSafeRef(paint.getTypeface()))
30         , fSkewX(paint.getTextSkewX())
31         , fAlign(paint.getTextAlign())
32         , fHinting(paint.getHinting())
33         , fFlags(paint.getFlags() & kFlagsMask) { }
34 
applyToPaint(SkPaint * paint) const35     void applyToPaint(SkPaint* paint) const {
36         paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
37         paint->setTypeface(fTypeface);
38         paint->setTextSize(fSize);
39         paint->setTextScaleX(fScaleX);
40         paint->setTextSkewX(fSkewX);
41         paint->setTextAlign(static_cast<SkPaint::Align>(fAlign));
42         paint->setHinting(static_cast<SkPaint::Hinting>(fHinting));
43 
44         paint->setFlags((paint->getFlags() & ~kFlagsMask) | fFlags);
45     }
46 
operator ==(const RunFont & other) const47     bool operator==(const RunFont& other) const {
48         return fTypeface == other.fTypeface
49             && fSize == other.fSize
50             && fScaleX == other.fScaleX
51             && fSkewX == other.fSkewX
52             && fAlign == other.fAlign
53             && fHinting == other.fHinting
54             && fFlags == other.fFlags;
55     }
56 
operator !=(const RunFont & other) const57     bool operator!=(const RunFont& other) const {
58         return !(*this == other);
59     }
60 
flags() const61     uint32_t flags() const { return fFlags; }
62 
63 private:
64     const static uint32_t kFlagsMask =
65         SkPaint::kAntiAlias_Flag          |
66         SkPaint::kFakeBoldText_Flag       |
67         SkPaint::kLinearText_Flag         |
68         SkPaint::kSubpixelText_Flag       |
69         SkPaint::kDevKernText_Flag        |
70         SkPaint::kLCDRenderText_Flag      |
71         SkPaint::kEmbeddedBitmapText_Flag |
72         SkPaint::kAutoHinting_Flag        |
73         SkPaint::kVerticalText_Flag       |
74         SkPaint::kGenA8FromLCD_Flag;
75 
76     SkScalar                 fSize;
77     SkScalar                 fScaleX;
78 
79     // Keep this sk_sp off the first position, to avoid interfering with SkNoncopyable
80     // empty baseclass optimization (http://code.google.com/p/skia/issues/detail?id=3694).
81     sk_sp<SkTypeface>        fTypeface;
82     SkScalar                 fSkewX;
83 
84     static_assert(SkPaint::kAlignCount < 4, "insufficient_align_bits");
85     uint32_t                 fAlign : 2;
86     static_assert(SkPaint::kFull_Hinting < 4, "insufficient_hinting_bits");
87     uint32_t                 fHinting : 2;
88     static_assert((kFlagsMask & 0xffff) == kFlagsMask, "insufficient_flags_bits");
89     uint32_t                 fFlags : 16;
90 
91     typedef SkNoncopyable INHERITED;
92 };
93 
94 struct RunFontStorageEquivalent {
95     SkScalar fSize, fScaleX;
96     void*    fTypeface;
97     SkScalar fSkewX;
98     uint32_t fFlags;
99 };
100 static_assert(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), "runfont_should_stay_packed");
101 
102 } // anonymous namespace
103 
104 //
105 // Textblob data is laid out into externally-managed storage as follows:
106 //
107 //    -----------------------------------------------------------------------------
108 //   | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
109 //    -----------------------------------------------------------------------------
110 //
111 //  Each run record describes a text blob run, and can be used to determine the (implicit)
112 //  location of the following record.
113 //
114 // Extended Textblob runs have more data after the Pos[] array:
115 //
116 //    -------------------------------------------------------------------------
117 //    ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ...
118 //    -------------------------------------------------------------------------
119 //
120 // To determine the length of the extended run data, the TextSize must be read.
121 //
122 // Extended Textblob runs may be mixed with non-extended runs.
123 
124 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
125 
126 namespace {
127 struct RunRecordStorageEquivalent {
128     RunFont  fFont;
129     SkPoint  fOffset;
130     uint32_t fCount;
131     uint32_t fFlags;
132     SkDEBUGCODE(unsigned fMagic;)
133 };
134 }
135 
136 class SkTextBlob::RunRecord {
137 public:
RunRecord(uint32_t count,uint32_t textSize,const SkPoint & offset,const SkPaint & font,GlyphPositioning pos)138     RunRecord(uint32_t count, uint32_t textSize,  const SkPoint& offset, const SkPaint& font, GlyphPositioning pos)
139         : fFont(font)
140         , fCount(count)
141         , fOffset(offset)
142         , fFlags(pos) {
143         SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask);
144 
145         SkDEBUGCODE(fMagic = kRunRecordMagic);
146         if (textSize > 0) {
147             fFlags |= kExtended_Flag;
148             *this->textSizePtr() = textSize;
149         }
150     }
151 
glyphCount() const152     uint32_t glyphCount() const {
153         return fCount;
154     }
155 
offset() const156     const SkPoint& offset() const {
157         return fOffset;
158     }
159 
font() const160     const RunFont& font() const {
161         return fFont;
162     }
163 
positioning() const164     GlyphPositioning positioning() const {
165         return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
166     }
167 
glyphBuffer() const168     uint16_t* glyphBuffer() const {
169         static_assert(SkIsAlignPtr(sizeof(RunRecord)), "");
170         // Glyphs are stored immediately following the record.
171         return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
172     }
173 
posBuffer() const174     SkScalar* posBuffer() const {
175         // Position scalars follow the (aligned) glyph buffer.
176         return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
177                                            SkAlign4(fCount * sizeof(uint16_t)));
178     }
179 
textSize() const180     uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
181 
clusterBuffer() const182     uint32_t* clusterBuffer() const {
183         // clusters follow the textSize.
184         return isExtended() ? 1 + this->textSizePtr() : nullptr;
185     }
186 
textBuffer() const187     char* textBuffer() const {
188         return isExtended()
189             ? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
190             : nullptr;
191     }
192 
StorageSize(uint32_t glyphCount,uint32_t textSize,SkTextBlob::GlyphPositioning positioning,SkSafeMath * safe)193     static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
194                               SkTextBlob::GlyphPositioning positioning,
195                               SkSafeMath* safe) {
196         static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment");
197 
198         auto glyphSize = safe->mul(glyphCount, sizeof(uint16_t)),
199                posSize = safe->mul(PosCount(glyphCount, positioning, safe), sizeof(SkScalar));
200 
201         // RunRecord object + (aligned) glyph buffer + position buffer
202         auto size = sizeof(SkTextBlob::RunRecord);
203              size = safe->add(size, safe->alignUp(glyphSize, 4));
204              size = safe->add(size, posSize);
205 
206         if (textSize) {  // Extended run.
207              size = safe->add(size, sizeof(uint32_t));
208              size = safe->add(size, safe->mul(glyphCount, sizeof(uint32_t)));
209              size = safe->add(size, textSize);
210         }
211 
212         return safe->alignUp(size, sizeof(void*));
213     }
214 
First(const SkTextBlob * blob)215     static const RunRecord* First(const SkTextBlob* blob) {
216         // The first record (if present) is stored following the blob object.
217         return reinterpret_cast<const RunRecord*>(blob + 1);
218     }
219 
Next(const RunRecord * run)220     static const RunRecord* Next(const RunRecord* run) {
221         return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run);
222     }
223 
validate(const uint8_t * storageTop) const224     void validate(const uint8_t* storageTop) const {
225         SkASSERT(kRunRecordMagic == fMagic);
226         SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop);
227 
228         SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
229         SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning())
230                  <= (SkScalar*)NextUnchecked(this));
231         if (isExtended()) {
232             SkASSERT(textSize() > 0);
233             SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this));
234             SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this));
235             SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this));
236         }
237         static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent),
238                       "runrecord_should_stay_packed");
239     }
240 
241 private:
242     friend class SkTextBlobBuilder;
243 
244     enum Flags {
245         kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
246         kLast_Flag        = 0x04, // set for the last blob run
247         kExtended_Flag    = 0x08, // set for runs with text/cluster info
248     };
249 
NextUnchecked(const RunRecord * run)250     static const RunRecord* NextUnchecked(const RunRecord* run) {
251         SkSafeMath safe;
252         auto res = reinterpret_cast<const RunRecord*>(
253                    reinterpret_cast<const uint8_t*>(run)
254                    + StorageSize(run->glyphCount(), run->textSize(), run->positioning(), &safe));
255         SkASSERT(safe);
256         return res;
257     }
258 
PosCount(uint32_t glyphCount,SkTextBlob::GlyphPositioning positioning,SkSafeMath * safe)259     static size_t PosCount(uint32_t glyphCount,
260                            SkTextBlob::GlyphPositioning positioning,
261                            SkSafeMath* safe) {
262         return safe->mul(glyphCount, ScalarsPerGlyph(positioning));
263     }
264 
textSizePtr() const265     uint32_t* textSizePtr() const {
266         // textSize follows the position buffer.
267         SkASSERT(isExtended());
268         SkSafeMath safe;
269         auto res = (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning(), &safe)]);
270         SkASSERT(safe);
271         return res;
272     }
273 
grow(uint32_t count)274     void grow(uint32_t count) {
275         SkScalar* initialPosBuffer = posBuffer();
276         uint32_t initialCount = fCount;
277         fCount += count;
278 
279         // Move the initial pos scalars to their new location.
280         size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning());
281         SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this));
282 
283         // memmove, as the buffers may overlap
284         memmove(posBuffer(), initialPosBuffer, copySize);
285     }
286 
isExtended() const287     bool isExtended() const {
288         return fFlags & kExtended_Flag;
289     }
290 
291     RunFont          fFont;
292     uint32_t         fCount;
293     SkPoint          fOffset;
294     uint32_t         fFlags;
295 
296     SkDEBUGCODE(unsigned fMagic;)
297 };
298 
299 static int32_t gNextID = 1;
next_id()300 static int32_t next_id() {
301     int32_t id;
302     do {
303         id = sk_atomic_inc(&gNextID);
304     } while (id == SK_InvalidGenID);
305     return id;
306 }
307 
SkTextBlob(const SkRect & bounds)308 SkTextBlob::SkTextBlob(const SkRect& bounds)
309     : fBounds(bounds)
310     , fUniqueID(next_id())
311     , fCacheID(SK_InvalidUniqueID) {}
312 
~SkTextBlob()313 SkTextBlob::~SkTextBlob() {
314 #if SK_SUPPORT_GPU
315     if (SK_InvalidUniqueID != fCacheID.load()) {
316         GrTextBlobCache::PostPurgeBlobMessage(fUniqueID, fCacheID);
317     }
318 #endif
319 
320     const auto* run = RunRecord::First(this);
321     do {
322         const auto* nextRun = RunRecord::Next(run);
323         SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);)
324         run->~RunRecord();
325         run = nextRun;
326     } while (run);
327 }
328 
329 namespace {
330 
331 union PositioningAndExtended {
332     int32_t intValue;
333     struct {
334         SkTextBlob::GlyphPositioning positioning;
335         uint8_t  extended;
336         uint16_t padding;
337     };
338 };
339 
340 static_assert(sizeof(PositioningAndExtended) == sizeof(int32_t), "");
341 
342 } // namespace
343 
ScalarsPerGlyph(GlyphPositioning pos)344 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
345     // GlyphPositioning values are directly mapped to scalars-per-glyph.
346     SkASSERT(pos <= 2);
347     return pos;
348 }
349 
SkTextBlobRunIterator(const SkTextBlob * blob)350 SkTextBlobRunIterator::SkTextBlobRunIterator(const SkTextBlob* blob)
351     : fCurrentRun(SkTextBlob::RunRecord::First(blob)) {
352     SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;)
353 }
354 
done() const355 bool SkTextBlobRunIterator::done() const {
356     return !fCurrentRun;
357 }
358 
next()359 void SkTextBlobRunIterator::next() {
360     SkASSERT(!this->done());
361 
362     if (!this->done()) {
363         SkDEBUGCODE(fCurrentRun->validate(fStorageTop);)
364         fCurrentRun = SkTextBlob::RunRecord::Next(fCurrentRun);
365     }
366 }
367 
glyphCount() const368 uint32_t SkTextBlobRunIterator::glyphCount() const {
369     SkASSERT(!this->done());
370     return fCurrentRun->glyphCount();
371 }
372 
glyphs() const373 const uint16_t* SkTextBlobRunIterator::glyphs() const {
374     SkASSERT(!this->done());
375     return fCurrentRun->glyphBuffer();
376 }
377 
pos() const378 const SkScalar* SkTextBlobRunIterator::pos() const {
379     SkASSERT(!this->done());
380     return fCurrentRun->posBuffer();
381 }
382 
offset() const383 const SkPoint& SkTextBlobRunIterator::offset() const {
384     SkASSERT(!this->done());
385     return fCurrentRun->offset();
386 }
387 
positioning() const388 SkTextBlob::GlyphPositioning SkTextBlobRunIterator::positioning() const {
389     SkASSERT(!this->done());
390     return fCurrentRun->positioning();
391 }
392 
applyFontToPaint(SkPaint * paint) const393 void SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const {
394     SkASSERT(!this->done());
395 
396     fCurrentRun->font().applyToPaint(paint);
397 }
398 
clusters() const399 uint32_t* SkTextBlobRunIterator::clusters() const {
400     SkASSERT(!this->done());
401     return fCurrentRun->clusterBuffer();
402 }
textSize() const403 uint32_t SkTextBlobRunIterator::textSize() const {
404     SkASSERT(!this->done());
405     return fCurrentRun->textSize();
406 }
text() const407 char* SkTextBlobRunIterator::text() const {
408     SkASSERT(!this->done());
409     return fCurrentRun->textBuffer();
410 }
411 
412 
isLCD() const413 bool SkTextBlobRunIterator::isLCD() const {
414     return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag);
415 }
416 
SkTextBlobBuilder()417 SkTextBlobBuilder::SkTextBlobBuilder()
418     : fStorageSize(0)
419     , fStorageUsed(0)
420     , fRunCount(0)
421     , fDeferredBounds(false)
422     , fLastRun(0) {
423     fBounds.setEmpty();
424 }
425 
~SkTextBlobBuilder()426 SkTextBlobBuilder::~SkTextBlobBuilder() {
427     if (nullptr != fStorage.get()) {
428         // We are abandoning runs and must destruct the associated font data.
429         // The easiest way to accomplish that is to use the blob destructor.
430         this->make();
431     }
432 }
433 
TightRunBounds(const SkTextBlob::RunRecord & run)434 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) {
435     SkRect bounds;
436     SkPaint paint;
437     run.font().applyToPaint(&paint);
438 
439     if (SkTextBlob::kDefault_Positioning == run.positioning()) {
440         paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &bounds);
441         return bounds.makeOffset(run.offset().x(), run.offset().y());
442     }
443 
444     SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount());
445     paint.getTextWidths(run.glyphBuffer(),
446                         run.glyphCount() * sizeof(uint16_t),
447                         nullptr,
448                         glyphBounds.get());
449 
450     SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
451              SkTextBlob::kHorizontal_Positioning == run.positioning());
452     // kFull_Positioning       => [ x, y, x, y... ]
453     // kHorizontal_Positioning => [ x, x, x... ]
454     //                            (const y applied by runBounds.offset(run->offset()) later)
455     const SkScalar horizontalConstY = 0;
456     const SkScalar* glyphPosX = run.posBuffer();
457     const SkScalar* glyphPosY = (run.positioning() == SkTextBlob::kFull_Positioning) ?
458                                                       glyphPosX + 1 : &horizontalConstY;
459     const unsigned posXInc = SkTextBlob::ScalarsPerGlyph(run.positioning());
460     const unsigned posYInc = (run.positioning() == SkTextBlob::kFull_Positioning) ?
461                                                    posXInc : 0;
462 
463     bounds.setEmpty();
464     for (unsigned i = 0; i < run.glyphCount(); ++i) {
465         bounds.join(glyphBounds[i].makeOffset(*glyphPosX, *glyphPosY));
466         glyphPosX += posXInc;
467         glyphPosY += posYInc;
468     }
469 
470     SkASSERT((void*)glyphPosX <= SkTextBlob::RunRecord::Next(&run));
471 
472     return bounds.makeOffset(run.offset().x(), run.offset().y());
473 }
474 
ConservativeRunBounds(const SkTextBlob::RunRecord & run)475 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run) {
476     SkASSERT(run.glyphCount() > 0);
477     SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
478              SkTextBlob::kHorizontal_Positioning == run.positioning());
479 
480     SkPaint paint;
481     run.font().applyToPaint(&paint);
482     const SkRect fontBounds = paint.getFontBounds();
483     if (fontBounds.isEmpty()) {
484         // Empty font bounds are likely a font bug.  TightBounds has a better chance of
485         // producing useful results in this case.
486         return TightRunBounds(run);
487     }
488 
489     // Compute the glyph position bbox.
490     SkRect bounds;
491     switch (run.positioning()) {
492     case SkTextBlob::kHorizontal_Positioning: {
493         const SkScalar* glyphPos = run.posBuffer();
494         SkASSERT((void*)(glyphPos + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
495 
496         SkScalar minX = *glyphPos;
497         SkScalar maxX = *glyphPos;
498         for (unsigned i = 1; i < run.glyphCount(); ++i) {
499             SkScalar x = glyphPos[i];
500             minX = SkMinScalar(x, minX);
501             maxX = SkMaxScalar(x, maxX);
502         }
503 
504         bounds.setLTRB(minX, 0, maxX, 0);
505     } break;
506     case SkTextBlob::kFull_Positioning: {
507         const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuffer());
508         SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
509 
510         bounds.setBounds(glyphPosPts, run.glyphCount());
511     } break;
512     default:
513         SK_ABORT("unsupported positioning mode");
514     }
515 
516     // Expand by typeface glyph bounds.
517     bounds.fLeft   += fontBounds.left();
518     bounds.fTop    += fontBounds.top();
519     bounds.fRight  += fontBounds.right();
520     bounds.fBottom += fontBounds.bottom();
521 
522     // Offset by run position.
523     return bounds.makeOffset(run.offset().x(), run.offset().y());
524 }
525 
updateDeferredBounds()526 void SkTextBlobBuilder::updateDeferredBounds() {
527     SkASSERT(!fDeferredBounds || fRunCount > 0);
528 
529     if (!fDeferredBounds) {
530         return;
531     }
532 
533     SkASSERT(fLastRun >= sizeof(SkTextBlob));
534     SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
535                                                                           fLastRun);
536 
537     // FIXME: we should also use conservative bounds for kDefault_Positioning.
538     SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ?
539                        TightRunBounds(*run) : ConservativeRunBounds(*run);
540     fBounds.join(runBounds);
541     fDeferredBounds = false;
542 }
543 
reserve(size_t size)544 void SkTextBlobBuilder::reserve(size_t size) {
545     SkSafeMath safe;
546 
547     // We don't currently pre-allocate, but maybe someday...
548     if (safe.add(fStorageUsed, size) <= fStorageSize && safe) {
549         return;
550     }
551 
552     if (0 == fRunCount) {
553         SkASSERT(nullptr == fStorage.get());
554         SkASSERT(0 == fStorageSize);
555         SkASSERT(0 == fStorageUsed);
556 
557         // the first allocation also includes blob storage
558         fStorageUsed = sizeof(SkTextBlob);
559     }
560 
561     fStorageSize = safe.add(fStorageUsed, size);
562 
563     // FYI: This relies on everything we store being relocatable, particularly SkPaint.
564     //      Also, this is counting on the underlying realloc to throw when passed max().
565     fStorage.realloc(safe ? fStorageSize : std::numeric_limits<size_t>::max());
566 }
567 
mergeRun(const SkPaint & font,SkTextBlob::GlyphPositioning positioning,uint32_t count,SkPoint offset)568 bool SkTextBlobBuilder::mergeRun(const SkPaint &font, SkTextBlob::GlyphPositioning positioning,
569                                  uint32_t count, SkPoint offset) {
570     if (0 == fLastRun) {
571         SkASSERT(0 == fRunCount);
572         return false;
573     }
574 
575     SkASSERT(fLastRun >= sizeof(SkTextBlob));
576     SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
577                                                                           fLastRun);
578     SkASSERT(run->glyphCount() > 0);
579 
580     if (run->textSize() != 0) {
581         return false;
582     }
583 
584     if (run->positioning() != positioning
585         || run->font() != font
586         || (run->glyphCount() + count < run->glyphCount())) {
587         return false;
588     }
589 
590     // we can merge same-font/same-positioning runs in the following cases:
591     //   * fully positioned run following another fully positioned run
592     //   * horizontally postioned run following another horizontally positioned run with the same
593     //     y-offset
594     if (SkTextBlob::kFull_Positioning != positioning
595         && (SkTextBlob::kHorizontal_Positioning != positioning
596             || run->offset().y() != offset.y())) {
597         return false;
598     }
599 
600     SkSafeMath safe;
601     size_t sizeDelta =
602         SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, 0, positioning, &safe) -
603         SkTextBlob::RunRecord::StorageSize(run->glyphCount()        , 0, positioning, &safe);
604     if (!safe) {
605         return false;
606     }
607 
608     this->reserve(sizeDelta);
609 
610     // reserve may have realloced
611     run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
612     uint32_t preMergeCount = run->glyphCount();
613     run->grow(count);
614 
615     // Callers expect the buffers to point at the newly added slice, ant not at the beginning.
616     fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount;
617     fCurrentRunBuffer.pos = run->posBuffer()
618                           + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning);
619 
620     fStorageUsed += sizeDelta;
621 
622     SkASSERT(fStorageUsed <= fStorageSize);
623     run->validate(fStorage.get() + fStorageUsed);
624 
625     return true;
626 }
627 
allocInternal(const SkPaint & font,SkTextBlob::GlyphPositioning positioning,int count,int textSize,SkPoint offset,const SkRect * bounds)628 void SkTextBlobBuilder::allocInternal(const SkPaint &font,
629                                       SkTextBlob::GlyphPositioning positioning,
630                                       int count, int textSize, SkPoint offset,
631                                       const SkRect* bounds) {
632     if (count <= 0 || textSize < 0 || font.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
633         fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr };
634         return;
635     }
636 
637     if (textSize != 0 || !this->mergeRun(font, positioning, count, offset)) {
638         this->updateDeferredBounds();
639 
640         SkSafeMath safe;
641         size_t runSize = SkTextBlob::RunRecord::StorageSize(count, textSize, positioning, &safe);
642         if (!safe) {
643             fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr };
644             return;
645         }
646 
647         this->reserve(runSize);
648 
649         SkASSERT(fStorageUsed >= sizeof(SkTextBlob));
650         SkASSERT(fStorageUsed + runSize <= fStorageSize);
651 
652         SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed)
653             SkTextBlob::RunRecord(count, textSize, offset, font, positioning);
654         fCurrentRunBuffer.glyphs = run->glyphBuffer();
655         fCurrentRunBuffer.pos = run->posBuffer();
656         fCurrentRunBuffer.utf8text = run->textBuffer();
657         fCurrentRunBuffer.clusters = run->clusterBuffer();
658 
659         fLastRun = fStorageUsed;
660         fStorageUsed += runSize;
661         fRunCount++;
662 
663         SkASSERT(fStorageUsed <= fStorageSize);
664         run->validate(fStorage.get() + fStorageUsed);
665     }
666     SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.utf8text);
667     SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.clusters);
668     if (!fDeferredBounds) {
669         if (bounds) {
670             fBounds.join(*bounds);
671         } else {
672             fDeferredBounds = true;
673         }
674     }
675 }
676 
allocRunText(const SkPaint & font,int count,SkScalar x,SkScalar y,int textByteCount,SkString lang,const SkRect * bounds)677 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunText(const SkPaint& font, int count,
678                                                                     SkScalar x, SkScalar y,
679                                                                     int textByteCount,
680                                                                     SkString lang,
681                                                                     const SkRect* bounds) {
682     this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, textByteCount, SkPoint::Make(x, y), bounds);
683     return fCurrentRunBuffer;
684 }
685 
allocRunTextPosH(const SkPaint & font,int count,SkScalar y,int textByteCount,SkString lang,const SkRect * bounds)686 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPosH(const SkPaint& font, int count,
687                                                                         SkScalar y,
688                                                                         int textByteCount,
689                                                                         SkString lang,
690                                                                         const SkRect* bounds) {
691     this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, textByteCount, SkPoint::Make(0, y),
692                         bounds);
693 
694     return fCurrentRunBuffer;
695 }
696 
allocRunTextPos(const SkPaint & font,int count,int textByteCount,SkString lang,const SkRect * bounds)697 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkPaint& font, int count,
698                                                                        int textByteCount,
699                                                                        SkString lang,
700                                                                        const SkRect *bounds) {
701     this->allocInternal(font, SkTextBlob::kFull_Positioning, count, textByteCount, SkPoint::Make(0, 0), bounds);
702 
703     return fCurrentRunBuffer;
704 }
705 
make()706 sk_sp<SkTextBlob> SkTextBlobBuilder::make() {
707     if (!fRunCount) {
708         // We don't instantiate empty blobs.
709         SkASSERT(!fStorage.get());
710         SkASSERT(fStorageUsed == 0);
711         SkASSERT(fStorageSize == 0);
712         SkASSERT(fLastRun == 0);
713         SkASSERT(fBounds.isEmpty());
714         return nullptr;
715     }
716 
717     this->updateDeferredBounds();
718 
719     // Tag the last run as such.
720     auto* lastRun = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
721     lastRun->fFlags |= SkTextBlob::RunRecord::kLast_Flag;
722 
723     SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fBounds);
724     SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;)
725 
726     SkDEBUGCODE(
727         SkSafeMath safe;
728         size_t validateSize = sizeof(SkTextBlob);
729         for (const auto* run = SkTextBlob::RunRecord::First(blob); run;
730              run = SkTextBlob::RunRecord::Next(run)) {
731             validateSize += SkTextBlob::RunRecord::StorageSize(
732                     run->fCount, run->textSize(), run->positioning(), &safe);
733             run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed);
734             fRunCount--;
735         }
736         SkASSERT(validateSize == fStorageUsed);
737         SkASSERT(fRunCount == 0);
738         SkASSERT(safe);
739     )
740 
741     fStorageUsed = 0;
742     fStorageSize = 0;
743     fRunCount = 0;
744     fLastRun = 0;
745     fBounds.setEmpty();
746 
747     return sk_sp<SkTextBlob>(blob);
748 }
749 
750 ///////////////////////////////////////////////////////////////////////////////////////////////////
751 
flatten(SkWriteBuffer & buffer) const752 void SkTextBlob::flatten(SkWriteBuffer& buffer) const {
753     buffer.writeRect(fBounds);
754 
755     SkPaint runPaint;
756     SkTextBlobRunIterator it(this);
757     while (!it.done()) {
758         SkASSERT(it.glyphCount() > 0);
759 
760         buffer.write32(it.glyphCount());
761         PositioningAndExtended pe;
762         pe.intValue = 0;
763         pe.positioning = it.positioning();
764         SkASSERT((int32_t)it.positioning() == pe.intValue);  // backwards compat.
765 
766         uint32_t textSize = it.textSize();
767         pe.extended = textSize > 0;
768         buffer.write32(pe.intValue);
769         if (pe.extended) {
770             buffer.write32(textSize);
771         }
772         buffer.writePoint(it.offset());
773         // This should go away when switching to SkFont
774         it.applyFontToPaint(&runPaint);
775         buffer.writePaint(runPaint);
776 
777         buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t));
778         buffer.writeByteArray(it.pos(),
779                               it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning()));
780         if (pe.extended) {
781             buffer.writeByteArray(it.clusters(), sizeof(uint32_t) * it.glyphCount());
782             buffer.writeByteArray(it.text(), it.textSize());
783         }
784 
785         it.next();
786     }
787 
788     // Marker for the last run (0 is not a valid glyph count).
789     buffer.write32(0);
790 }
791 
MakeFromBuffer(SkReadBuffer & reader)792 sk_sp<SkTextBlob> SkTextBlob::MakeFromBuffer(SkReadBuffer& reader) {
793     SkRect bounds;
794     reader.readRect(&bounds);
795 
796     SkTextBlobBuilder blobBuilder;
797     for (;;) {
798         int glyphCount = reader.read32();
799         if (glyphCount == 0) {
800             // End-of-runs marker.
801             break;
802         }
803 
804         PositioningAndExtended pe;
805         pe.intValue = reader.read32();
806         GlyphPositioning pos = pe.positioning;
807         if (glyphCount <= 0 || pos > kFull_Positioning) {
808             return nullptr;
809         }
810         int textSize = pe.extended ? reader.read32() : 0;
811         if (textSize < 0) {
812             return nullptr;
813         }
814 
815         SkPoint offset;
816         reader.readPoint(&offset);
817         SkPaint font;
818         reader.readPaint(&font);
819 
820         if (!reader.isValid()) {
821             return nullptr;
822         }
823 
824         const SkTextBlobBuilder::RunBuffer* buf = nullptr;
825         switch (pos) {
826             case kDefault_Positioning:
827                 buf = &blobBuilder.allocRunText(font, glyphCount, offset.x(), offset.y(),
828                                                 textSize, SkString(), &bounds);
829                 break;
830             case kHorizontal_Positioning:
831                 buf = &blobBuilder.allocRunTextPosH(font, glyphCount, offset.y(),
832                                                     textSize, SkString(), &bounds);
833                 break;
834             case kFull_Positioning:
835                 buf = &blobBuilder.allocRunTextPos(font, glyphCount, textSize, SkString(), &bounds);
836                 break;
837             default:
838                 return nullptr;
839         }
840 
841         if (!buf->glyphs ||
842             !buf->pos ||
843             (pe.extended && (!buf->clusters || !buf->utf8text))) {
844             return nullptr;
845         }
846 
847         if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) ||
848             !reader.readByteArray(buf->pos,
849                                   glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(pos))) {
850                 return nullptr;
851             }
852 
853         if (pe.extended) {
854             if (!reader.readByteArray(buf->clusters, glyphCount * sizeof(uint32_t))  ||
855                 !reader.readByteArray(buf->utf8text, textSize)) {
856                 return nullptr;
857             }
858         }
859     }
860 
861     return blobBuilder.make();
862 }
863 
serialize(const SkSerialProcs & procs) const864 sk_sp<SkData> SkTextBlob::serialize(const SkSerialProcs& procs) const {
865     SkBinaryWriteBuffer buffer;
866     buffer.setSerialProcs(procs);
867     this->flatten(buffer);
868 
869     size_t total = buffer.bytesWritten();
870     sk_sp<SkData> data = SkData::MakeUninitialized(total);
871     buffer.writeToMemory(data->writable_data());
872     return data;
873 }
874 
serialize() const875 sk_sp<SkData> SkTextBlob::serialize() const {
876     return this->serialize(SkSerialProcs());
877 }
878 
Deserialize(const void * data,size_t length,const SkDeserialProcs & procs)879 sk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length,
880                                           const SkDeserialProcs& procs) {
881     SkReadBuffer buffer(data, length);
882     buffer.setDeserialProcs(procs);
883     return SkTextBlob::MakeFromBuffer(buffer);
884 }
885 
Deserialize(const void * data,size_t length)886 sk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length) {
887     return SkTextBlob::Deserialize(data, length, SkDeserialProcs());
888 }
889 
890 ///////////////////////////////////////////////////////////////////////////////////////////////////
891 
892 namespace {
893     struct CatalogState {
894         SkTypefaceCatalogerProc fProc;
895         void*                   fCtx;
896     };
897 
catalog_typeface_proc(SkTypeface * face,void * ctx)898     sk_sp<SkData> catalog_typeface_proc(SkTypeface* face, void* ctx) {
899         CatalogState* state = static_cast<CatalogState*>(ctx);
900         state->fProc(face, state->fCtx);
901         uint32_t id = face->uniqueID();
902         return SkData::MakeWithCopy(&id, sizeof(uint32_t));
903     }
904 }
905 
serialize(SkTypefaceCatalogerProc proc,void * ctx) const906 sk_sp<SkData> SkTextBlob::serialize(SkTypefaceCatalogerProc proc, void* ctx) const {
907     CatalogState state = { proc, ctx };
908     SkSerialProcs procs;
909     procs.fTypefaceProc = catalog_typeface_proc;
910     procs.fTypefaceCtx  = &state;
911     return this->serialize(procs);
912 }
913 
914 namespace {
915     struct ResolverState {
916         SkTypefaceResolverProc  fProc;
917         void*                   fCtx;
918     };
919 
resolver_typeface_proc(const void * data,size_t length,void * ctx)920     sk_sp<SkTypeface> resolver_typeface_proc(const void* data, size_t length, void* ctx) {
921         if (length != 4) {
922             return nullptr;
923         }
924 
925         ResolverState* state = static_cast<ResolverState*>(ctx);
926         uint32_t id;
927         memcpy(&id, data, length);
928         return state->fProc(id, state->fCtx);
929     }
930 }
931 
Deserialize(const void * data,size_t length,SkTypefaceResolverProc proc,void * ctx)932 sk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length,
933                                           SkTypefaceResolverProc proc, void* ctx) {
934     ResolverState state = { proc, ctx };
935     SkDeserialProcs procs;
936     procs.fTypefaceProc = resolver_typeface_proc;
937     procs.fTypefaceCtx  = &state;
938     return Deserialize(data, length, procs);
939 }
940