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