Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkTextBlob.cpp
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 "SkTextBlob.h"
9
10 #include "SkReadBuffer.h"
11 #include "SkWriteBuffer.h"
12
13 //
14 // Textblob data is laid out into externally-managed storage as follows:
15 //
16 //    -----------------------------------------------------------------------------
17 //   | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
18 //    -----------------------------------------------------------------------------
19 //
20 //  Each run record describes a text blob run, and can be used to determine the (implicit)
21 //  location of the following record.
22
23 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
24
25 class SkTextBlob::RunRecord {
26 public:
27     RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos)
28         : fCount(count)
29         , fOffset(offset)
30         , fFont(font)
31         , fPositioning(pos) {
32         SkDEBUGCODE(fMagic = kRunRecordMagic);
33     }
34
35     uint32_t glyphCount() const {
36         return fCount;
37     }
38
39     const SkPoint& offset() const {
40         return fOffset;
41     }
42
43     const SkPaint& font() const {
44         return fFont;
45     }
46
47     GlyphPositioning positioning() const {
48         return fPositioning;
49     }
50
51     uint16_t* glyphBuffer() const {
52         // Glyph are stored immediately following the record.
53         return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
54     }
55
56     SkScalar* posBuffer() const {
57         // Position scalars follow the (aligned) glyph buffer.
58         return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
59                                            SkAlign4(fCount * sizeof(uint16_t)));
60     }
61
62     static size_t StorageSize(int glyphCount, SkTextBlob::GlyphPositioning positioning) {
63         // RunRecord object + (aligned) glyph buffer + position buffer
64         return SkAlignPtr(sizeof(SkTextBlob::RunRecord)
65                         + SkAlign4(glyphCount* sizeof(uint16_t))
66                         + glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning));
67     }
68
69     static const RunRecord* First(const SkTextBlob* blob) {
70         // The first record (if present) is stored following the blob object.
71         return reinterpret_cast<const RunRecord*>(blob + 1);
72     }
73
74     static const RunRecord* Next(const RunRecord* run) {
75         return reinterpret_cast<const RunRecord*>(reinterpret_cast<const uint8_t*>(run)
76             + StorageSize(run->glyphCount(), run->positioning()));
77     }
78
79     void validate(uint8_t* storageTop) const {
80         SkASSERT(kRunRecordMagic == fMagic);
81         SkASSERT((uint8_t*)Next(this) <= storageTop);
82         SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
83         SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) <= (SkScalar*)Next(this));
84     }
85
86 private:
87     friend class SkTextBlobBuilder;
88
89     void grow(uint32_t count) {
90         SkScalar* initialPosBuffer = posBuffer();
91         uint32_t initialCount = fCount;
92         fCount += count;
93
94         // Move the initial pos scalars to their new location.
95         size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPositioning);
96         SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this));
97
98         // memmove, as the buffers may overlap
99         memmove(posBuffer(), initialPosBuffer, copySize);
100     }
101
102     uint32_t         fCount;
103     SkPoint          fOffset;
104     SkPaint          fFont;
105     GlyphPositioning fPositioning;
106
107     SkDEBUGCODE(unsigned fMagic;)
108 };
109
110 SkTextBlob::SkTextBlob(int runCount, const SkRect& bounds)
111     : fRunCount(runCount)
112     , fBounds(bounds) {
113 }
114
115 SkTextBlob::~SkTextBlob() {
116     const RunRecord* run = RunRecord::First(this);
117     for (int i = 0; i < fRunCount; ++i) {
118         const RunRecord* nextRun = RunRecord::Next(run);
119         SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);)
120         run->~RunRecord();
121         run = nextRun;
122     }
123 }
124
125 void SkTextBlob::internal_dispose() const {
126     // SkTextBlobs use externally-managed storage.
127     this->internal_dispose_restore_refcnt_to_1();
128     this->~SkTextBlob();
129     sk_free(const_cast<SkTextBlob*>(this));
130 }
131
132 uint32_t SkTextBlob::uniqueID() const {
133     static int32_t  gTextBlobGenerationID; // = 0;
134
135     // loop in case our global wraps around, as we never want to return SK_InvalidGenID
136     while (SK_InvalidGenID == fUniqueID) {
137         fUniqueID = sk_atomic_inc(&gTextBlobGenerationID) + 1;
138     }
139
140     return fUniqueID;
141 }
142
143 void SkTextBlob::flatten(SkWriteBuffer& buffer) const {
144     int runCount = fRunCount;
145
146     buffer.write32(runCount);
147     buffer.writeRect(fBounds);
148
149     SkPaint runPaint;
150     RunIterator it(this);
151     while (!it.done()) {
152         SkASSERT(it.glyphCount() > 0);
153
154         buffer.write32(it.glyphCount());
155         buffer.write32(it.positioning());
156         buffer.writePoint(it.offset());
157         // This should go away when switching to SkFont
158         it.applyFontToPaint(&runPaint);
159         buffer.writePaint(runPaint);
160
161         buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t));
162         buffer.writeByteArray(it.pos(),
163             it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning()));
164
165         it.next();
166         SkDEBUGCODE(runCount--);
167     }
168     SkASSERT(0 == runCount);
169 }
170
171 const SkTextBlob* SkTextBlob::CreateFromBuffer(SkReadBuffer& reader) {
172     int runCount = reader.read32();
173     if (runCount < 0) {
174         return NULL;
175     }
176
177     SkRect bounds;
178     reader.readRect(&bounds);
179
180     SkTextBlobBuilder blobBuilder;
181     for (int i = 0; i < runCount; ++i) {
182         int glyphCount = reader.read32();
183         GlyphPositioning pos = static_cast<GlyphPositioning>(reader.read32());
184         if (glyphCount <= 0 || pos > kFull_Positioning) {
185             return NULL;
186         }
187
188         SkPoint offset;
189         reader.readPoint(&offset);
190         SkPaint font;
191         reader.readPaint(&font);
192
193         const SkTextBlobBuilder::RunBuffer* buf = NULL;
194         switch (pos) {
195         case kDefault_Positioning:
196             buf = &blobBuilder.allocRun(font, glyphCount, offset.x(), offset.y(), &bounds);
197             break;
198         case kHorizontal_Positioning:
199             buf = &blobBuilder.allocRunPosH(font, glyphCount, offset.y(), &bounds);
200             break;
201         case kFull_Positioning:
202             buf = &blobBuilder.allocRunPos(font, glyphCount, &bounds);
203             break;
204         default:
205             return NULL;
206         }
207
208         if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) ||
209             !reader.readByteArray(buf->pos,
210                                   glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(pos))) {
211             return NULL;
212         }
213     }
214
215     return blobBuilder.build();
216 }
217
218 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
219     // GlyphPositioning values are directly mapped to scalars-per-glyph.
220     SkASSERT(pos <= 2);
221     return pos;
222 }
223
224 SkTextBlob::RunIterator::RunIterator(const SkTextBlob* blob)
225     : fCurrentRun(RunRecord::First(blob))
226     , fRemainingRuns(blob->fRunCount) {
227     SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;)
228 }
229
230 bool SkTextBlob::RunIterator::done() const {
231     return fRemainingRuns <= 0;
232 }
233
234 void SkTextBlob::RunIterator::next() {
235     SkASSERT(!this->done());
236
237     if (!this->done()) {
238         SkDEBUGCODE(fCurrentRun->validate(fStorageTop);)
239         fCurrentRun = RunRecord::Next(fCurrentRun);
240         fRemainingRuns--;
241     }
242 }
243
244 uint32_t SkTextBlob::RunIterator::glyphCount() const {
245     SkASSERT(!this->done());
246     return fCurrentRun->glyphCount();
247 }
248
249 const uint16_t* SkTextBlob::RunIterator::glyphs() const {
250     SkASSERT(!this->done());
251     return fCurrentRun->glyphBuffer();
252 }
253
254 const SkScalar* SkTextBlob::RunIterator::pos() const {
255     SkASSERT(!this->done());
256     return fCurrentRun->posBuffer();
257 }
258
259 const SkPoint& SkTextBlob::RunIterator::offset() const {
260     SkASSERT(!this->done());
261     return fCurrentRun->offset();
262 }
263
264 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const {
265     SkASSERT(!this->done());
266     return fCurrentRun->positioning();
267 }
268
269 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const {
270     SkASSERT(!this->done());
271
272     const SkPaint& font = fCurrentRun->font();
273
274     paint->setTypeface(font.getTypeface());
275     paint->setTextEncoding(font.getTextEncoding());
276     paint->setTextSize(font.getTextSize());
277     paint->setTextScaleX(font.getTextScaleX());
278     paint->setTextSkewX(font.getTextSkewX());
279     paint->setHinting(font.getHinting());
280
281     uint32_t flagsMask = SkPaint::kAntiAlias_Flag
282                        | SkPaint::kUnderlineText_Flag
283                        | SkPaint::kStrikeThruText_Flag
284                        | SkPaint::kFakeBoldText_Flag
285                        | SkPaint::kLinearText_Flag
286                        | SkPaint::kSubpixelText_Flag
287                        | SkPaint::kDevKernText_Flag
288                        | SkPaint::kLCDRenderText_Flag
289                        | SkPaint::kEmbeddedBitmapText_Flag
290                        | SkPaint::kAutoHinting_Flag
291                        | SkPaint::kVerticalText_Flag
292                        | SkPaint::kGenA8FromLCD_Flag
293                        | SkPaint::kDistanceFieldTextTEMP_Flag;
294     paint->setFlags((paint->getFlags() & ~flagsMask) | (font.getFlags() & flagsMask));
295 }
296
297 SkTextBlobBuilder::SkTextBlobBuilder()
298     : fStorageSize(0)
299     , fStorageUsed(0)
300     , fRunCount(0)
301     , fDeferredBounds(false)
302     , fLastRun(0) {
303     fBounds.setEmpty();
304 }
305
306 SkTextBlobBuilder::~SkTextBlobBuilder() {
307     if (NULL != fStorage.get()) {
308         // We are abandoning runs and must destruct the associated font data.
309         // The easiest way to accomplish that is to use the blob destructor.
310         build()->unref();
311     }
312 }
313
314 void SkTextBlobBuilder::updateDeferredBounds() {
315     SkASSERT(!fDeferredBounds || fRunCount > 0);
316
317     if (!fDeferredBounds) {
318         return;
319     }
320
321     // FIXME: measure the current run & union bounds
322     fDeferredBounds = false;
323 }
324
325 void SkTextBlobBuilder::reserve(size_t size) {
326     // We don't currently pre-allocate, but maybe someday...
327     if (fStorageUsed + size <= fStorageSize) {
328         return;
329     }
330
331     if (0 == fRunCount) {
332         SkASSERT(NULL == fStorage.get());
333         SkASSERT(0 == fStorageSize);
334         SkASSERT(0 == fStorageUsed);
335
336         // the first allocation also includes blob storage
337         fStorageUsed += sizeof(SkTextBlob);
338     }
339
340     fStorageSize = fStorageUsed + size;
341     // FYI: This relies on everything we store being relocatable, particularly SkPaint.
342     fStorage.realloc(fStorageSize);
343 }
344
345 bool SkTextBlobBuilder::mergeRun(const SkPaint &font, SkTextBlob::GlyphPositioning positioning,
346                                  int count, SkPoint offset) {
347     if (0 == fLastRun) {
348         SkASSERT(0 == fRunCount);
349         return false;
350     }
351
352     SkASSERT(fLastRun >= sizeof(SkTextBlob));
353     SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
354                                                                           fLastRun);
355     SkASSERT(run->glyphCount() > 0);
356
357     if (run->positioning() != positioning
358         || run->font() != font
359         || (run->glyphCount() + count < run->glyphCount())) {
360         return false;
361     }
362
363     // we can merge same-font/same-positioning runs in the following cases:
364     //   * fully positioned run following another fully positioned run
365     //   * horizontally postioned run following another horizontally positioned run with the same
366     //     y-offset
367     if (SkTextBlob::kFull_Positioning != positioning
368         && (SkTextBlob::kHorizontal_Positioning != positioning
369             || run->offset().y() != offset.y())) {
370         return false;
371     }
372
373     size_t sizeDelta = SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, positioning) -
374                        SkTextBlob::RunRecord::StorageSize(run->glyphCount(), positioning);
375     this->reserve(sizeDelta);
376
377     // reserve may have realloced
378     run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
379     uint32_t preMergeCount = run->glyphCount();
380     run->grow(count);
381
382     // Callers expect the buffers to point at the newly added slice, ant not at the beginning.
383     fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount;
384     fCurrentRunBuffer.pos = run->posBuffer()
385                           + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning);
386
387     fStorageUsed += sizeDelta;
388
389     SkASSERT(fStorageUsed <= fStorageSize);
390     run->validate(fStorage.get() + fStorageUsed);
391
392     return true;
393 }
394
395 void SkTextBlobBuilder::allocInternal(const SkPaint &font,
396                                       SkTextBlob::GlyphPositioning positioning,
397                                       int count, SkPoint offset, const SkRect* bounds) {
398     SkASSERT(count > 0);
399     SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding());
400
401     if (!this->mergeRun(font, positioning, count, offset)) {
402         updateDeferredBounds();
403
404         size_t runSize = SkTextBlob::RunRecord::StorageSize(count, positioning);
405         this->reserve(runSize);
406
407         SkASSERT(fStorageUsed >= sizeof(SkTextBlob));
408         SkASSERT(fStorageUsed + runSize <= fStorageSize);
409
410         SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed)
411                                          SkTextBlob::RunRecord(count, offset, font, positioning);
412
413         fCurrentRunBuffer.glyphs = run->glyphBuffer();
414         fCurrentRunBuffer.pos = run->posBuffer();
415
416         fLastRun = fStorageUsed;
417         fStorageUsed += runSize;
418         fRunCount++;
419
420         SkASSERT(fStorageUsed <= fStorageSize);
421         run->validate(fStorage.get() + fStorageUsed);
422     }
423
424     if (!fDeferredBounds) {
425         if (bounds) {
426             fBounds.join(*bounds);
427         } else {
428             fDeferredBounds = true;
429         }
430     }
431 }
432
433 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRun(const SkPaint& font, int count,
434                                                                 SkScalar x, SkScalar y,
435                                                                 const SkRect* bounds) {
436     this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, SkPoint::Make(x, y), bounds);
437
438     return fCurrentRunBuffer;
439 }
440
441 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPosH(const SkPaint& font, int count,
442                                                                     SkScalar y,
443                                                                     const SkRect* bounds) {
444     this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, SkPoint::Make(0, y),
445                         bounds);
446
447     return fCurrentRunBuffer;
448 }
449
450 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkPaint& font, int count,
451                                                                    const SkRect *bounds) {
452     this->allocInternal(font, SkTextBlob::kFull_Positioning, count, SkPoint::Make(0, 0), bounds);
453
454     return fCurrentRunBuffer;
455 }
456
457 const SkTextBlob* SkTextBlobBuilder::build() {
458     SkASSERT((fRunCount > 0) == (NULL != fStorage.get()));
459
460     this->updateDeferredBounds();
461
462     if (0 == fRunCount) {
463         SkASSERT(NULL == fStorage.get());
464         fStorageUsed = sizeof(SkTextBlob);
465         fStorage.realloc(fStorageUsed);
466     }
467
468     SkDEBUGCODE(
469         size_t validateSize = sizeof(SkTextBlob);
470         const SkTextBlob::RunRecord* run =
471             SkTextBlob::RunRecord::First(reinterpret_cast<const SkTextBlob*>(fStorage.get()));
472         for (int i = 0; i < fRunCount; ++i) {
473             validateSize += SkTextBlob::RunRecord::StorageSize(run->fCount, run->fPositioning);
474             run->validate(fStorage.get() + fStorageUsed);
475             run = SkTextBlob::RunRecord::Next(run);
476         }
477         SkASSERT(validateSize == fStorageUsed);
478     )
479
480     const SkTextBlob* blob = new (fStorage.detach()) SkTextBlob(fRunCount, fBounds);
481     SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;)
482
483     fStorageUsed = 0;
484     fStorageSize = 0;
485     fRunCount = 0;
486     fLastRun = 0;
487     fBounds.setEmpty();
488
489     return blob;
490 }
491