blob: 5697cd376a1a11442e2318521a96227733cf3acd [file] [log] [blame]
fmalita00d5c2c2014-08-21 08:53:26 -07001/*
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
Florin Malitaab54e732018-07-27 09:47:15 -04008#include "SkTextBlob.h"
Mike Reed7d1eb332018-12-04 17:35:56 -05009#include "SkFontPriv.h"
Herb Derby4b3a5152018-07-17 16:10:30 -040010#include "SkGlyphRun.h"
Herb Derbyeb3f6742018-03-05 14:36:45 -050011#include "SkPaintPriv.h"
Mike Reedfadbfcd2017-12-06 16:09:20 -050012#include "SkReadBuffer.h"
Mike Reed30cf62b2018-12-20 11:18:24 -050013#include "SkRSXform.h"
Florin Malitad923a712017-11-22 10:11:12 -050014#include "SkSafeMath.h"
Cary Clark53c87692018-07-17 08:59:34 -040015#include "SkTextBlobPriv.h"
fmalita3dc40ac2015-01-28 10:56:06 -080016#include "SkTypeface.h"
fmalitab7425172014-08-26 07:56:44 -070017#include "SkWriteBuffer.h"
18
Mike Klein0ec1c572018-12-04 11:52:51 -050019#include <atomic>
Florin Malitad923a712017-11-22 10:11:12 -050020#include <limits>
Mike Klein79aea6a2018-06-11 10:45:26 -040021#include <new>
Florin Malitad923a712017-11-22 10:11:12 -050022
Florin Malita4a01ac92017-03-13 16:45:28 -040023#if SK_SUPPORT_GPU
24#include "text/GrTextBlobCache.h"
25#endif
26
Herb Derby434377a2018-10-02 16:48:17 -040027namespace {
fmalita055f6b52015-04-09 08:49:32 -070028struct RunFontStorageEquivalent {
29 SkScalar fSize, fScaleX;
30 void* fTypeface;
31 SkScalar fSkewX;
32 uint32_t fFlags;
33};
Mike Reed7b7ab592018-12-05 21:32:05 -050034static_assert(sizeof(SkFont) == sizeof(RunFontStorageEquivalent), "runfont_should_stay_packed");
Herb Derby434377a2018-10-02 16:48:17 -040035}
fmalita055f6b52015-04-09 08:49:32 -070036
Herb Derby434377a2018-10-02 16:48:17 -040037size_t SkTextBlob::RunRecord::StorageSize(uint32_t glyphCount, uint32_t textSize,
38 SkTextBlob::GlyphPositioning positioning,
39 SkSafeMath* safe) {
40 static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment");
fmalita055f6b52015-04-09 08:49:32 -070041
Herb Derby434377a2018-10-02 16:48:17 -040042 auto glyphSize = safe->mul(glyphCount, sizeof(uint16_t)),
43 posSize = safe->mul(PosCount(glyphCount, positioning, safe), sizeof(SkScalar));
fmalita3c196de2014-09-20 05:40:22 -070044
Herb Derby434377a2018-10-02 16:48:17 -040045 // RunRecord object + (aligned) glyph buffer + position buffer
46 auto size = sizeof(SkTextBlob::RunRecord);
47 size = safe->add(size, safe->alignUp(glyphSize, 4));
48 size = safe->add(size, posSize);
49
50 if (textSize) { // Extended run.
51 size = safe->add(size, sizeof(uint32_t));
52 size = safe->add(size, safe->mul(glyphCount, sizeof(uint32_t)));
53 size = safe->add(size, textSize);
54 }
55
56 return safe->alignUp(size, sizeof(void*));
57}
58
59const SkTextBlob::RunRecord* SkTextBlob::RunRecord::First(const SkTextBlob* blob) {
60 // The first record (if present) is stored following the blob object.
61 // (aligned up to make the RunRecord aligned too)
62 return reinterpret_cast<const RunRecord*>(SkAlignPtr((uintptr_t)(blob + 1)));
63}
64
65const SkTextBlob::RunRecord* SkTextBlob::RunRecord::Next(const RunRecord* run) {
66 return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run);
67}
fmalita3c196de2014-09-20 05:40:22 -070068
halcanary4f0a23a2016-08-30 11:58:33 -070069namespace {
70struct RunRecordStorageEquivalent {
Mike Reed7b7ab592018-12-05 21:32:05 -050071 SkFont fFont;
halcanary4f0a23a2016-08-30 11:58:33 -070072 SkPoint fOffset;
73 uint32_t fCount;
74 uint32_t fFlags;
75 SkDEBUGCODE(unsigned fMagic;)
76};
77}
78
Herb Derby434377a2018-10-02 16:48:17 -040079void SkTextBlob::RunRecord::validate(const uint8_t* storageTop) const {
80 SkASSERT(kRunRecordMagic == fMagic);
81 SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop);
Florin Malita3a9a7a32017-03-13 09:03:24 -040082
Herb Derby434377a2018-10-02 16:48:17 -040083 SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
84 SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning())
85 <= (SkScalar*)NextUnchecked(this));
86 if (isExtended()) {
87 SkASSERT(textSize() > 0);
88 SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this));
89 SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this));
90 SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this));
fmalita3c196de2014-09-20 05:40:22 -070091 }
Herb Derby434377a2018-10-02 16:48:17 -040092 static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent),
93 "runrecord_should_stay_packed");
94}
fmalita3c196de2014-09-20 05:40:22 -070095
Herb Derby434377a2018-10-02 16:48:17 -040096const SkTextBlob::RunRecord* SkTextBlob::RunRecord::NextUnchecked(const RunRecord* run) {
97 SkSafeMath safe;
98 auto res = reinterpret_cast<const RunRecord*>(
99 reinterpret_cast<const uint8_t*>(run)
100 + StorageSize(run->glyphCount(), run->textSize(), run->positioning(), &safe));
101 SkASSERT(safe);
102 return res;
103}
fmalita3c196de2014-09-20 05:40:22 -0700104
Herb Derby434377a2018-10-02 16:48:17 -0400105size_t SkTextBlob::RunRecord::PosCount(uint32_t glyphCount,
106 SkTextBlob::GlyphPositioning positioning,
107 SkSafeMath* safe) {
108 return safe->mul(glyphCount, ScalarsPerGlyph(positioning));
109}
fmalita3c196de2014-09-20 05:40:22 -0700110
Herb Derby434377a2018-10-02 16:48:17 -0400111uint32_t* SkTextBlob::RunRecord::textSizePtr() const {
112 // textSize follows the position buffer.
113 SkASSERT(isExtended());
114 SkSafeMath safe;
115 auto res = (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning(), &safe)]);
116 SkASSERT(safe);
117 return res;
118}
fmalita3c196de2014-09-20 05:40:22 -0700119
Herb Derby434377a2018-10-02 16:48:17 -0400120void SkTextBlob::RunRecord::grow(uint32_t count) {
121 SkScalar* initialPosBuffer = posBuffer();
122 uint32_t initialCount = fCount;
123 fCount += count;
fmalita3c196de2014-09-20 05:40:22 -0700124
Herb Derby434377a2018-10-02 16:48:17 -0400125 // Move the initial pos scalars to their new location.
126 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning());
127 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this));
fmalita3c196de2014-09-20 05:40:22 -0700128
Herb Derby434377a2018-10-02 16:48:17 -0400129 // memmove, as the buffers may overlap
130 memmove(posBuffer(), initialPosBuffer, copySize);
131}
fmalita3c196de2014-09-20 05:40:22 -0700132
joshualitt2af85832015-03-25 13:40:13 -0700133static int32_t next_id() {
Mike Klein0ec1c572018-12-04 11:52:51 -0500134 static std::atomic<int32_t> nextID{1};
joshualitt2af85832015-03-25 13:40:13 -0700135 int32_t id;
136 do {
Mike Klein0ec1c572018-12-04 11:52:51 -0500137 id = nextID++;
joshualitt2af85832015-03-25 13:40:13 -0700138 } while (id == SK_InvalidGenID);
139 return id;
140}
141
Florin Malita3a9a7a32017-03-13 09:03:24 -0400142SkTextBlob::SkTextBlob(const SkRect& bounds)
143 : fBounds(bounds)
Florin Malita4a01ac92017-03-13 16:45:28 -0400144 , fUniqueID(next_id())
Jim Van Verth474d6872017-12-14 13:00:05 -0500145 , fCacheID(SK_InvalidUniqueID) {}
fmalita00d5c2c2014-08-21 08:53:26 -0700146
fmalita3c196de2014-09-20 05:40:22 -0700147SkTextBlob::~SkTextBlob() {
Florin Malita4a01ac92017-03-13 16:45:28 -0400148#if SK_SUPPORT_GPU
Jim Van Verth474d6872017-12-14 13:00:05 -0500149 if (SK_InvalidUniqueID != fCacheID.load()) {
150 GrTextBlobCache::PostPurgeBlobMessage(fUniqueID, fCacheID);
Florin Malita4a01ac92017-03-13 16:45:28 -0400151 }
152#endif
153
Florin Malita3a9a7a32017-03-13 09:03:24 -0400154 const auto* run = RunRecord::First(this);
155 do {
156 const auto* nextRun = RunRecord::Next(run);
fmalita3c196de2014-09-20 05:40:22 -0700157 SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);)
158 run->~RunRecord();
159 run = nextRun;
Florin Malita3a9a7a32017-03-13 09:03:24 -0400160 } while (run);
fmalita3c196de2014-09-20 05:40:22 -0700161}
162
halcanary4f0a23a2016-08-30 11:58:33 -0700163namespace {
Florin Malita90dcafc2017-11-22 10:53:33 -0500164
halcanary4f0a23a2016-08-30 11:58:33 -0700165union PositioningAndExtended {
166 int32_t intValue;
167 struct {
Florin Malitaab54e732018-07-27 09:47:15 -0400168 uint8_t positioning;
Florin Malita90dcafc2017-11-22 10:53:33 -0500169 uint8_t extended;
halcanary4f0a23a2016-08-30 11:58:33 -0700170 uint16_t padding;
171 };
172};
Florin Malita90dcafc2017-11-22 10:53:33 -0500173
174static_assert(sizeof(PositioningAndExtended) == sizeof(int32_t), "");
175
halcanary4f0a23a2016-08-30 11:58:33 -0700176} // namespace
177
Florin Malitaab54e732018-07-27 09:47:15 -0400178enum SkTextBlob::GlyphPositioning : uint8_t {
Mike Reed30cf62b2018-12-20 11:18:24 -0500179 kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph.
180 kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph.
181 kFull_Positioning = 2, // Point positioning -- two scalars per glyph.
182 kRSXform_Positioning = 3, // RSXform positioning -- four scalars per glyph.
Florin Malitaab54e732018-07-27 09:47:15 -0400183};
184
fmalita3c196de2014-09-20 05:40:22 -0700185unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
Mike Reed30cf62b2018-12-20 11:18:24 -0500186 const uint8_t gScalarsPerPositioning[] = {
187 0, // kDefault_Positioning
188 1, // kHorizontal_Positioning
189 2, // kFull_Positioning
190 4, // kRSXform_Positioning
191 };
192 SkASSERT((unsigned)pos <= 3);
193 return gScalarsPerPositioning[pos];
fmalita3c196de2014-09-20 05:40:22 -0700194}
195
Yong-Hwan Baek688a8e52018-07-09 14:14:26 +0900196void SkTextBlob::operator delete(void* p) {
197 sk_free(p);
198}
199
200void* SkTextBlob::operator new(size_t) {
201 SK_ABORT("All blobs are created by placement new.");
202 return sk_malloc_throw(0);
203}
204
205void* SkTextBlob::operator new(size_t, void* p) {
206 return p;
207}
208
halcanary33779752015-10-27 14:01:05 -0700209SkTextBlobRunIterator::SkTextBlobRunIterator(const SkTextBlob* blob)
Florin Malita3a9a7a32017-03-13 09:03:24 -0400210 : fCurrentRun(SkTextBlob::RunRecord::First(blob)) {
fmalita3c196de2014-09-20 05:40:22 -0700211 SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;)
fmalita00d5c2c2014-08-21 08:53:26 -0700212}
213
halcanary33779752015-10-27 14:01:05 -0700214void SkTextBlobRunIterator::next() {
fmalita00d5c2c2014-08-21 08:53:26 -0700215 SkASSERT(!this->done());
fmalita3c196de2014-09-20 05:40:22 -0700216
217 if (!this->done()) {
218 SkDEBUGCODE(fCurrentRun->validate(fStorageTop);)
halcanary33779752015-10-27 14:01:05 -0700219 fCurrentRun = SkTextBlob::RunRecord::Next(fCurrentRun);
fmalita3c196de2014-09-20 05:40:22 -0700220 }
fmalita00d5c2c2014-08-21 08:53:26 -0700221}
222
Florin Malitaab54e732018-07-27 09:47:15 -0400223SkTextBlobRunIterator::GlyphPositioning SkTextBlobRunIterator::positioning() const {
fmalita00d5c2c2014-08-21 08:53:26 -0700224 SkASSERT(!this->done());
Florin Malitaab54e732018-07-27 09:47:15 -0400225 static_assert(static_cast<GlyphPositioning>(SkTextBlob::kDefault_Positioning) ==
226 kDefault_Positioning, "");
227 static_assert(static_cast<GlyphPositioning>(SkTextBlob::kHorizontal_Positioning) ==
228 kHorizontal_Positioning, "");
229 static_assert(static_cast<GlyphPositioning>(SkTextBlob::kFull_Positioning) ==
230 kFull_Positioning, "");
Mike Reed30cf62b2018-12-20 11:18:24 -0500231 static_assert(static_cast<GlyphPositioning>(SkTextBlob::kRSXform_Positioning) ==
232 kRSXform_Positioning, "");
Florin Malitaab54e732018-07-27 09:47:15 -0400233
234 return SkTo<GlyphPositioning>(fCurrentRun->positioning());
fmalita00d5c2c2014-08-21 08:53:26 -0700235}
236
halcanary33779752015-10-27 14:01:05 -0700237void SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const {
fmalita37ecbaf2014-08-22 09:01:19 -0700238 SkASSERT(!this->done());
239
Mike Reed7b7ab592018-12-05 21:32:05 -0500240 fCurrentRun->font().LEGACY_applyToPaint(paint);
241 paint->setTextEncoding(kGlyphID_SkTextEncoding);
fmalita37ecbaf2014-08-22 09:01:19 -0700242}
243
halcanary33779752015-10-27 14:01:05 -0700244bool SkTextBlobRunIterator::isLCD() const {
Mike Reedb3f4aac2018-12-05 15:40:29 -0500245 return fCurrentRun->font().getEdging() == SkFont::Edging::kSubpixelAntiAlias;
joshualitt9e36c1a2015-04-14 12:17:27 -0700246}
247
fmalita3c196de2014-09-20 05:40:22 -0700248SkTextBlobBuilder::SkTextBlobBuilder()
249 : fStorageSize(0)
250 , fStorageUsed(0)
251 , fRunCount(0)
252 , fDeferredBounds(false)
253 , fLastRun(0) {
fmalita00d5c2c2014-08-21 08:53:26 -0700254 fBounds.setEmpty();
255}
256
257SkTextBlobBuilder::~SkTextBlobBuilder() {
halcanary96fcdcc2015-08-27 07:41:13 -0700258 if (nullptr != fStorage.get()) {
fmalita3c196de2014-09-20 05:40:22 -0700259 // We are abandoning runs and must destruct the associated font data.
260 // The easiest way to accomplish that is to use the blob destructor.
fmalita37283c22016-09-13 10:00:23 -0700261 this->make();
fmalita3c196de2014-09-20 05:40:22 -0700262 }
fmalita00d5c2c2014-08-21 08:53:26 -0700263}
264
fmalita3dc40ac2015-01-28 10:56:06 -0800265SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) {
Mike Reedd1ca6722018-12-10 14:53:16 -0500266 const SkFont& font = run.font();
fmalita3dc40ac2015-01-28 10:56:06 -0800267 SkRect bounds;
fmalitab0b45d32015-10-09 14:46:28 -0700268
269 if (SkTextBlob::kDefault_Positioning == run.positioning()) {
Mike Reedd1ca6722018-12-10 14:53:16 -0500270 font.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t),
271 kGlyphID_SkTextEncoding, &bounds);
fmalitab0b45d32015-10-09 14:46:28 -0700272 return bounds.makeOffset(run.offset().x(), run.offset().y());
273 }
274
275 SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount());
Mike Reedd1ca6722018-12-10 14:53:16 -0500276 font.getBounds(run.glyphBuffer(), run.glyphCount(), glyphBounds.get(), nullptr);
fmalitab0b45d32015-10-09 14:46:28 -0700277
278 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
279 SkTextBlob::kHorizontal_Positioning == run.positioning());
280 // kFull_Positioning => [ x, y, x, y... ]
281 // kHorizontal_Positioning => [ x, x, x... ]
282 // (const y applied by runBounds.offset(run->offset()) later)
283 const SkScalar horizontalConstY = 0;
284 const SkScalar* glyphPosX = run.posBuffer();
285 const SkScalar* glyphPosY = (run.positioning() == SkTextBlob::kFull_Positioning) ?
286 glyphPosX + 1 : &horizontalConstY;
287 const unsigned posXInc = SkTextBlob::ScalarsPerGlyph(run.positioning());
288 const unsigned posYInc = (run.positioning() == SkTextBlob::kFull_Positioning) ?
289 posXInc : 0;
290
291 bounds.setEmpty();
292 for (unsigned i = 0; i < run.glyphCount(); ++i) {
293 bounds.join(glyphBounds[i].makeOffset(*glyphPosX, *glyphPosY));
294 glyphPosX += posXInc;
295 glyphPosY += posYInc;
296 }
297
298 SkASSERT((void*)glyphPosX <= SkTextBlob::RunRecord::Next(&run));
fmalita3dc40ac2015-01-28 10:56:06 -0800299
300 return bounds.makeOffset(run.offset().x(), run.offset().y());
301}
302
Mike Reed30cf62b2018-12-20 11:18:24 -0500303static SkRect map_quad_to_rect(const SkRSXform& xform, const SkRect& rect) {
304 return SkMatrix().setRSXform(xform).mapRect(rect);
305}
306
fmalita3dc40ac2015-01-28 10:56:06 -0800307SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run) {
fmalita3dc40ac2015-01-28 10:56:06 -0800308 SkASSERT(run.glyphCount() > 0);
fmalitaf9a40722015-01-29 12:24:24 -0800309 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
Mike Reed30cf62b2018-12-20 11:18:24 -0500310 SkTextBlob::kHorizontal_Positioning == run.positioning() ||
311 SkTextBlob::kRSXform_Positioning == run.positioning());
fmalita3dc40ac2015-01-28 10:56:06 -0800312
Mike Reedb3f4aac2018-12-05 15:40:29 -0500313 const SkRect fontBounds = SkFontPriv::GetFontBounds(run.font());
fmalitab0b45d32015-10-09 14:46:28 -0700314 if (fontBounds.isEmpty()) {
315 // Empty font bounds are likely a font bug. TightBounds has a better chance of
316 // producing useful results in this case.
317 return TightRunBounds(run);
318 }
319
320 // Compute the glyph position bbox.
fmalitaf9a40722015-01-29 12:24:24 -0800321 SkRect bounds;
322 switch (run.positioning()) {
323 case SkTextBlob::kHorizontal_Positioning: {
324 const SkScalar* glyphPos = run.posBuffer();
325 SkASSERT((void*)(glyphPos + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
326
327 SkScalar minX = *glyphPos;
328 SkScalar maxX = *glyphPos;
329 for (unsigned i = 1; i < run.glyphCount(); ++i) {
330 SkScalar x = glyphPos[i];
331 minX = SkMinScalar(x, minX);
332 maxX = SkMaxScalar(x, maxX);
333 }
334
335 bounds.setLTRB(minX, 0, maxX, 0);
336 } break;
337 case SkTextBlob::kFull_Positioning: {
338 const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuffer());
339 SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
340
341 bounds.setBounds(glyphPosPts, run.glyphCount());
342 } break;
Mike Reed30cf62b2018-12-20 11:18:24 -0500343 case SkTextBlob::kRSXform_Positioning: {
344 const SkRSXform* xform = reinterpret_cast<const SkRSXform*>(run.posBuffer());
345 SkASSERT((void*)(xform + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
346 bounds = map_quad_to_rect(xform[0], fontBounds);
347 for (unsigned i = 1; i < run.glyphCount(); ++i) {
348 bounds.join(map_quad_to_rect(xform[i], fontBounds));
349 }
350 } break;
fmalitaf9a40722015-01-29 12:24:24 -0800351 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400352 SK_ABORT("unsupported positioning mode");
fmalita3dc40ac2015-01-28 10:56:06 -0800353 }
354
Mike Reed30cf62b2018-12-20 11:18:24 -0500355 if (run.positioning() != SkTextBlob::kRSXform_Positioning) {
356 // Expand by typeface glyph bounds.
357 bounds.fLeft += fontBounds.left();
358 bounds.fTop += fontBounds.top();
359 bounds.fRight += fontBounds.right();
360 bounds.fBottom += fontBounds.bottom();
361 }
fmalita3dc40ac2015-01-28 10:56:06 -0800362
363 // Offset by run position.
364 return bounds.makeOffset(run.offset().x(), run.offset().y());
365}
366
fmalita00d5c2c2014-08-21 08:53:26 -0700367void SkTextBlobBuilder::updateDeferredBounds() {
fmalita3c196de2014-09-20 05:40:22 -0700368 SkASSERT(!fDeferredBounds || fRunCount > 0);
fmalita00d5c2c2014-08-21 08:53:26 -0700369
370 if (!fDeferredBounds) {
371 return;
372 }
373
Mike Klein93ce79d2018-08-10 12:41:57 +0000374 SkASSERT(fLastRun >= SkAlignPtr(sizeof(SkTextBlob)));
fmalita19653d12014-10-16 11:53:30 -0700375 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
376 fLastRun);
fmalita19653d12014-10-16 11:53:30 -0700377
fmalitaf9a40722015-01-29 12:24:24 -0800378 // FIXME: we should also use conservative bounds for kDefault_Positioning.
379 SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ?
380 TightRunBounds(*run) : ConservativeRunBounds(*run);
fmalita19653d12014-10-16 11:53:30 -0700381 fBounds.join(runBounds);
fmalita00d5c2c2014-08-21 08:53:26 -0700382 fDeferredBounds = false;
383}
384
fmalita3c196de2014-09-20 05:40:22 -0700385void SkTextBlobBuilder::reserve(size_t size) {
Florin Malitad923a712017-11-22 10:11:12 -0500386 SkSafeMath safe;
387
fmalita3c196de2014-09-20 05:40:22 -0700388 // We don't currently pre-allocate, but maybe someday...
Florin Malitad923a712017-11-22 10:11:12 -0500389 if (safe.add(fStorageUsed, size) <= fStorageSize && safe) {
fmalita3c196de2014-09-20 05:40:22 -0700390 return;
391 }
fmalita00d5c2c2014-08-21 08:53:26 -0700392
fmalita3c196de2014-09-20 05:40:22 -0700393 if (0 == fRunCount) {
halcanary96fcdcc2015-08-27 07:41:13 -0700394 SkASSERT(nullptr == fStorage.get());
fmalita3c196de2014-09-20 05:40:22 -0700395 SkASSERT(0 == fStorageSize);
396 SkASSERT(0 == fStorageUsed);
397
398 // the first allocation also includes blob storage
Mike Klein93ce79d2018-08-10 12:41:57 +0000399 // aligned up to a pointer alignment so SkTextBlob::RunRecords after it stay aligned.
400 fStorageUsed = SkAlignPtr(sizeof(SkTextBlob));
fmalita3c196de2014-09-20 05:40:22 -0700401 }
402
Florin Malitad923a712017-11-22 10:11:12 -0500403 fStorageSize = safe.add(fStorageUsed, size);
404
fmalita3c196de2014-09-20 05:40:22 -0700405 // FYI: This relies on everything we store being relocatable, particularly SkPaint.
Florin Malitad923a712017-11-22 10:11:12 -0500406 // Also, this is counting on the underlying realloc to throw when passed max().
407 fStorage.realloc(safe ? fStorageSize : std::numeric_limits<size_t>::max());
fmalita3c196de2014-09-20 05:40:22 -0700408}
409
Mike Reedb3f4aac2018-12-05 15:40:29 -0500410bool SkTextBlobBuilder::mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning,
Florin Malitad923a712017-11-22 10:11:12 -0500411 uint32_t count, SkPoint offset) {
fmalita3c196de2014-09-20 05:40:22 -0700412 if (0 == fLastRun) {
413 SkASSERT(0 == fRunCount);
414 return false;
415 }
416
Mike Klein93ce79d2018-08-10 12:41:57 +0000417 SkASSERT(fLastRun >= SkAlignPtr(sizeof(SkTextBlob)));
fmalita3c196de2014-09-20 05:40:22 -0700418 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
419 fLastRun);
420 SkASSERT(run->glyphCount() > 0);
421
halcanary4f0a23a2016-08-30 11:58:33 -0700422 if (run->textSize() != 0) {
423 return false;
424 }
425
fmalita3c196de2014-09-20 05:40:22 -0700426 if (run->positioning() != positioning
427 || run->font() != font
428 || (run->glyphCount() + count < run->glyphCount())) {
429 return false;
fmalita00d5c2c2014-08-21 08:53:26 -0700430 }
431
432 // we can merge same-font/same-positioning runs in the following cases:
433 // * fully positioned run following another fully positioned run
434 // * horizontally postioned run following another horizontally positioned run with the same
435 // y-offset
fmalita3c196de2014-09-20 05:40:22 -0700436 if (SkTextBlob::kFull_Positioning != positioning
437 && (SkTextBlob::kHorizontal_Positioning != positioning
438 || run->offset().y() != offset.y())) {
439 return false;
fmalita00d5c2c2014-08-21 08:53:26 -0700440 }
441
Florin Malitad923a712017-11-22 10:11:12 -0500442 SkSafeMath safe;
443 size_t sizeDelta =
444 SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, 0, positioning, &safe) -
445 SkTextBlob::RunRecord::StorageSize(run->glyphCount() , 0, positioning, &safe);
446 if (!safe) {
447 return false;
448 }
449
fmalita3c196de2014-09-20 05:40:22 -0700450 this->reserve(sizeDelta);
fmalita00d5c2c2014-08-21 08:53:26 -0700451
fmalita3c196de2014-09-20 05:40:22 -0700452 // reserve may have realloced
453 run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
454 uint32_t preMergeCount = run->glyphCount();
455 run->grow(count);
456
457 // Callers expect the buffers to point at the newly added slice, ant not at the beginning.
458 fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount;
459 fCurrentRunBuffer.pos = run->posBuffer()
460 + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning);
461
462 fStorageUsed += sizeDelta;
463
464 SkASSERT(fStorageUsed <= fStorageSize);
465 run->validate(fStorage.get() + fStorageUsed);
466
467 return true;
fmalita00d5c2c2014-08-21 08:53:26 -0700468}
469
Mike Reedb3f4aac2018-12-05 15:40:29 -0500470void SkTextBlobBuilder::allocInternal(const SkFont& font,
fmalita00d5c2c2014-08-21 08:53:26 -0700471 SkTextBlob::GlyphPositioning positioning,
Florin Malita1e18aa62017-11-19 10:22:22 -0500472 int count, int textSize, SkPoint offset,
473 const SkRect* bounds) {
Mike Reedb3f4aac2018-12-05 15:40:29 -0500474 if (count <= 0 || textSize < 0) {
Florin Malita1e18aa62017-11-19 10:22:22 -0500475 fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr };
476 return;
477 }
478
halcanary4f0a23a2016-08-30 11:58:33 -0700479 if (textSize != 0 || !this->mergeRun(font, positioning, count, offset)) {
fmalita19653d12014-10-16 11:53:30 -0700480 this->updateDeferredBounds();
fmalita00d5c2c2014-08-21 08:53:26 -0700481
Florin Malitad923a712017-11-22 10:11:12 -0500482 SkSafeMath safe;
483 size_t runSize = SkTextBlob::RunRecord::StorageSize(count, textSize, positioning, &safe);
484 if (!safe) {
485 fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr };
486 return;
487 }
488
fmalita3c196de2014-09-20 05:40:22 -0700489 this->reserve(runSize);
fmalita00d5c2c2014-08-21 08:53:26 -0700490
Mike Klein93ce79d2018-08-10 12:41:57 +0000491 SkASSERT(fStorageUsed >= SkAlignPtr(sizeof(SkTextBlob)));
fmalita3c196de2014-09-20 05:40:22 -0700492 SkASSERT(fStorageUsed + runSize <= fStorageSize);
fmalita00d5c2c2014-08-21 08:53:26 -0700493
fmalita3c196de2014-09-20 05:40:22 -0700494 SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed)
halcanary4f0a23a2016-08-30 11:58:33 -0700495 SkTextBlob::RunRecord(count, textSize, offset, font, positioning);
fmalita3c196de2014-09-20 05:40:22 -0700496 fCurrentRunBuffer.glyphs = run->glyphBuffer();
497 fCurrentRunBuffer.pos = run->posBuffer();
halcanary4f0a23a2016-08-30 11:58:33 -0700498 fCurrentRunBuffer.utf8text = run->textBuffer();
499 fCurrentRunBuffer.clusters = run->clusterBuffer();
fmalita00d5c2c2014-08-21 08:53:26 -0700500
fmalita3c196de2014-09-20 05:40:22 -0700501 fLastRun = fStorageUsed;
502 fStorageUsed += runSize;
503 fRunCount++;
504
505 SkASSERT(fStorageUsed <= fStorageSize);
506 run->validate(fStorage.get() + fStorageUsed);
507 }
halcanary4f0a23a2016-08-30 11:58:33 -0700508 SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.utf8text);
509 SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.clusters);
fmalita00d5c2c2014-08-21 08:53:26 -0700510 if (!fDeferredBounds) {
bsalomon49f085d2014-09-05 13:34:00 -0700511 if (bounds) {
fmalita00d5c2c2014-08-21 08:53:26 -0700512 fBounds.join(*bounds);
513 } else {
514 fDeferredBounds = true;
515 }
516 }
517}
518
Mike Reed3185f902018-10-26 16:33:00 -0400519// SkFont versions
520
521const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRun(const SkFont& font, int count,
522 SkScalar x, SkScalar y,
523 const SkRect* bounds) {
Mike Reedb3f4aac2018-12-05 15:40:29 -0500524 this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, 0, {x, y}, bounds);
525 return fCurrentRunBuffer;
Mike Reed3185f902018-10-26 16:33:00 -0400526}
527
528const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPosH(const SkFont& font, int count,
529 SkScalar y,
530 const SkRect* bounds) {
Mike Reedb3f4aac2018-12-05 15:40:29 -0500531 this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, 0, {0, y}, bounds);
532 return fCurrentRunBuffer;
Mike Reed3185f902018-10-26 16:33:00 -0400533}
534
535const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkFont& font, int count,
536 const SkRect* bounds) {
Mike Reedb3f4aac2018-12-05 15:40:29 -0500537 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, 0, {0, 0}, bounds);
538 return fCurrentRunBuffer;
Mike Reed3185f902018-10-26 16:33:00 -0400539}
540
Mike Reed30cf62b2018-12-20 11:18:24 -0500541const SkTextBlobBuilder::RunBuffer&
542SkTextBlobBuilder::allocRunRSXform(const SkFont& font, int count) {
543 this->allocInternal(font, SkTextBlob::kRSXform_Positioning, count, 0, {0, 0}, nullptr);
544 return fCurrentRunBuffer;
545}
546
Mike Reed6d595682018-12-05 17:28:14 -0500547const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunText(const SkFont& font, int count,
halcanary4f0a23a2016-08-30 11:58:33 -0700548 SkScalar x, SkScalar y,
549 int textByteCount,
550 SkString lang,
551 const SkRect* bounds) {
552 this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, textByteCount, SkPoint::Make(x, y), bounds);
fmalita00d5c2c2014-08-21 08:53:26 -0700553 return fCurrentRunBuffer;
554}
555
Mike Reed6d595682018-12-05 17:28:14 -0500556const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPosH(const SkFont& font, int count,
halcanary4f0a23a2016-08-30 11:58:33 -0700557 SkScalar y,
558 int textByteCount,
559 SkString lang,
560 const SkRect* bounds) {
561 this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, textByteCount, SkPoint::Make(0, y),
fmalita00d5c2c2014-08-21 08:53:26 -0700562 bounds);
fmalita00d5c2c2014-08-21 08:53:26 -0700563 return fCurrentRunBuffer;
564}
565
Mike Reed6d595682018-12-05 17:28:14 -0500566const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkFont& font, int count,
halcanary4f0a23a2016-08-30 11:58:33 -0700567 int textByteCount,
568 SkString lang,
569 const SkRect *bounds) {
Ben Wagnerdff47af2017-08-30 16:24:22 -0400570 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, textByteCount, SkPoint::Make(0, 0), bounds);
fmalita00d5c2c2014-08-21 08:53:26 -0700571 return fCurrentRunBuffer;
572}
573
Mike Reed30cf62b2018-12-20 11:18:24 -0500574const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunRSXform(const SkFont& font, int count,
575 int textByteCount,
576 SkString lang,
577 const SkRect* bounds) {
578 this->allocInternal(font, SkTextBlob::kRSXform_Positioning, count, textByteCount,
579 {0, 0}, bounds);
580 return fCurrentRunBuffer;
581}
582
reed2ab90572016-08-10 14:16:41 -0700583sk_sp<SkTextBlob> SkTextBlobBuilder::make() {
Florin Malita3a9a7a32017-03-13 09:03:24 -0400584 if (!fRunCount) {
585 // We don't instantiate empty blobs.
586 SkASSERT(!fStorage.get());
587 SkASSERT(fStorageUsed == 0);
588 SkASSERT(fStorageSize == 0);
589 SkASSERT(fLastRun == 0);
590 SkASSERT(fBounds.isEmpty());
591 return nullptr;
592 }
fmalita00d5c2c2014-08-21 08:53:26 -0700593
fmalita3c196de2014-09-20 05:40:22 -0700594 this->updateDeferredBounds();
fmalita00d5c2c2014-08-21 08:53:26 -0700595
Florin Malita3a9a7a32017-03-13 09:03:24 -0400596 // Tag the last run as such.
597 auto* lastRun = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
598 lastRun->fFlags |= SkTextBlob::RunRecord::kLast_Flag;
fmalita00d5c2c2014-08-21 08:53:26 -0700599
Florin Malita3a9a7a32017-03-13 09:03:24 -0400600 SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fBounds);
fmalita92d976c2015-10-05 11:09:57 -0700601 SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;)
602
fmalita3c196de2014-09-20 05:40:22 -0700603 SkDEBUGCODE(
Florin Malitad923a712017-11-22 10:11:12 -0500604 SkSafeMath safe;
Mike Klein93ce79d2018-08-10 12:41:57 +0000605 size_t validateSize = SkAlignPtr(sizeof(SkTextBlob));
Florin Malita3a9a7a32017-03-13 09:03:24 -0400606 for (const auto* run = SkTextBlob::RunRecord::First(blob); run;
607 run = SkTextBlob::RunRecord::Next(run)) {
halcanary4f0a23a2016-08-30 11:58:33 -0700608 validateSize += SkTextBlob::RunRecord::StorageSize(
Florin Malitad923a712017-11-22 10:11:12 -0500609 run->fCount, run->textSize(), run->positioning(), &safe);
fmalita92d976c2015-10-05 11:09:57 -0700610 run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed);
Florin Malita3a9a7a32017-03-13 09:03:24 -0400611 fRunCount--;
fmalita3c196de2014-09-20 05:40:22 -0700612 }
613 SkASSERT(validateSize == fStorageUsed);
Florin Malita3a9a7a32017-03-13 09:03:24 -0400614 SkASSERT(fRunCount == 0);
Florin Malitad923a712017-11-22 10:11:12 -0500615 SkASSERT(safe);
fmalita3c196de2014-09-20 05:40:22 -0700616 )
617
fmalita3c196de2014-09-20 05:40:22 -0700618 fStorageUsed = 0;
619 fStorageSize = 0;
620 fRunCount = 0;
621 fLastRun = 0;
622 fBounds.setEmpty();
623
reed2ab90572016-08-10 14:16:41 -0700624 return sk_sp<SkTextBlob>(blob);
fmalita00d5c2c2014-08-21 08:53:26 -0700625}
Mike Reedb99bedd2017-07-11 10:27:40 -0400626
627///////////////////////////////////////////////////////////////////////////////////////////////////
Mike Reedcfb01202018-12-11 15:09:04 -0500628#include "SkTextToPathIter.h"
629
630template <SkTextInterceptsIter::TextType TextType, typename Func>
Mike Reed5f6e20d2018-12-12 13:01:42 -0500631int GetTextIntercepts(const SkFont& font, const SkPaint* paint, const SkGlyphID glyphs[],
Mike Reedcfb01202018-12-11 15:09:04 -0500632 int glyphCount, const SkScalar bounds[2], SkScalar* array, Func posMaker) {
633 SkASSERT(glyphCount == 0 || glyphs != nullptr);
634
635 const SkPoint pos0 = posMaker(0);
636 SkTextInterceptsIter iter(glyphs, glyphCount, font, paint, bounds, pos0.x(), pos0.y(),
637 TextType);
638
639 int i = 0;
640 int count = 0;
641 while (iter.next(array, &count)) {
642 if (TextType == SkTextInterceptsIter::TextType::kPosText) {
643 const SkPoint pos = posMaker(++i);
644 iter.setPosition(pos.x(), pos.y());
645 }
646 }
647
648 return count;
649}
Mike Reedb99bedd2017-07-11 10:27:40 -0400650
Mike Reedae0d8602018-12-10 22:02:17 -0500651int SkTextBlob::getIntercepts(const SkScalar bounds[2], SkScalar intervals[],
652 const SkPaint* paint) const {
Mike Reedcfb01202018-12-11 15:09:04 -0500653 int count = 0;
654 SkTextBlobRunIterator it(this);
655
656 while (!it.done()) {
657 SkScalar* runIntervals = intervals ? intervals + count : nullptr;
658 const SkFont& font = it.font();
659 const SkGlyphID* glyphs = it.glyphs();
660 const int glyphCount = it.glyphCount();
661
662 switch (it.positioning()) {
663 case SkTextBlobRunIterator::kDefault_Positioning: {
664 SkPoint loc = it.offset();
665 count += GetTextIntercepts<SkTextInterceptsIter::TextType::kText>(
Mike Reed5f6e20d2018-12-12 13:01:42 -0500666 font, paint, glyphs, glyphCount, bounds, runIntervals, [loc] (int) {
Mike Reedcfb01202018-12-11 15:09:04 -0500667 return loc;
668 });
669 } break;
670 case SkTextBlobRunIterator::kHorizontal_Positioning: {
671 const SkScalar* xpos = it.pos();
672 const SkScalar constY = it.offset().fY;
673 count += GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
Mike Reed5f6e20d2018-12-12 13:01:42 -0500674 font, paint, glyphs, glyphCount, bounds, runIntervals, [xpos, constY] (int i) {
Mike Reedcfb01202018-12-11 15:09:04 -0500675 return SkPoint::Make(xpos[i], constY);
676 });
677 } break;
678 case SkTextBlobRunIterator::kFull_Positioning: {
679 const SkPoint* pos = reinterpret_cast<const SkPoint*>(it.pos());
680 count += GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
Mike Reed5f6e20d2018-12-12 13:01:42 -0500681 font, paint, glyphs, glyphCount, bounds, runIntervals, [pos] (int i) {
Mike Reedcfb01202018-12-11 15:09:04 -0500682 return pos[i];
683 });
684 } break;
Mike Reed30cf62b2018-12-20 11:18:24 -0500685 case SkTextBlobRunIterator::kRSXform_Positioning:
686 // Unimplemented for now -- can/should we try to make this work?
687 break;
Mike Reedcfb01202018-12-11 15:09:04 -0500688 }
689
690 it.next();
Mike Reedae0d8602018-12-10 22:02:17 -0500691 }
Mike Reedcfb01202018-12-11 15:09:04 -0500692
693 return count;
Mike Reedae0d8602018-12-10 22:02:17 -0500694}
695
Mike Reedcfb01202018-12-11 15:09:04 -0500696///////////////////////////////////////////////////////////////////////////////////////////////////
697
Cary Clark53c87692018-07-17 08:59:34 -0400698void SkTextBlobPriv::Flatten(const SkTextBlob& blob, SkWriteBuffer& buffer) {
Mike Reed0951cc22018-12-21 16:19:24 -0500699 // seems like we could skip this, and just recompute bounds in unflatten, but
700 // some cc_unittests fail if we remove this...
701 buffer.writeRect(blob.bounds());
Mike Reedf4dd96c2018-12-21 20:49:47 +0000702
Cary Clark53c87692018-07-17 08:59:34 -0400703 SkTextBlobRunIterator it(&blob);
Mike Reedb99bedd2017-07-11 10:27:40 -0400704 while (!it.done()) {
705 SkASSERT(it.glyphCount() > 0);
706
707 buffer.write32(it.glyphCount());
708 PositioningAndExtended pe;
709 pe.intValue = 0;
710 pe.positioning = it.positioning();
711 SkASSERT((int32_t)it.positioning() == pe.intValue); // backwards compat.
712
713 uint32_t textSize = it.textSize();
714 pe.extended = textSize > 0;
715 buffer.write32(pe.intValue);
716 if (pe.extended) {
717 buffer.write32(textSize);
718 }
719 buffer.writePoint(it.offset());
Mike Reed0951cc22018-12-21 16:19:24 -0500720
721 SkFontPriv::Flatten(it.font(), buffer);
Mike Reedb99bedd2017-07-11 10:27:40 -0400722
723 buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t));
724 buffer.writeByteArray(it.pos(),
Cary Clark53c87692018-07-17 08:59:34 -0400725 it.glyphCount() * sizeof(SkScalar) *
Florin Malitaab54e732018-07-27 09:47:15 -0400726 SkTextBlob::ScalarsPerGlyph(
727 SkTo<SkTextBlob::GlyphPositioning>(it.positioning())));
Mike Reedb99bedd2017-07-11 10:27:40 -0400728 if (pe.extended) {
729 buffer.writeByteArray(it.clusters(), sizeof(uint32_t) * it.glyphCount());
730 buffer.writeByteArray(it.text(), it.textSize());
731 }
732
733 it.next();
734 }
735
736 // Marker for the last run (0 is not a valid glyph count).
737 buffer.write32(0);
738}
739
Cary Clark53c87692018-07-17 08:59:34 -0400740sk_sp<SkTextBlob> SkTextBlobPriv::MakeFromBuffer(SkReadBuffer& reader) {
Mike Reedf4dd96c2018-12-21 20:49:47 +0000741 SkRect bounds;
742 reader.readRect(&bounds);
Mike Reedb99bedd2017-07-11 10:27:40 -0400743
744 SkTextBlobBuilder blobBuilder;
Khushalcea8e3d2018-05-07 13:57:43 -0700745 SkSafeMath safe;
Mike Reedc5166a92018-01-03 13:17:18 -0500746 for (;;) {
Mike Reedb99bedd2017-07-11 10:27:40 -0400747 int glyphCount = reader.read32();
Mike Reedc5166a92018-01-03 13:17:18 -0500748 if (glyphCount == 0) {
Mike Reedb99bedd2017-07-11 10:27:40 -0400749 // End-of-runs marker.
750 break;
751 }
752
753 PositioningAndExtended pe;
754 pe.intValue = reader.read32();
Florin Malitaab54e732018-07-27 09:47:15 -0400755 const auto pos = SkTo<SkTextBlob::GlyphPositioning>(pe.positioning);
Mike Reed30cf62b2018-12-20 11:18:24 -0500756 if (glyphCount <= 0 || pos > SkTextBlob::kRSXform_Positioning) {
Mike Reedb99bedd2017-07-11 10:27:40 -0400757 return nullptr;
758 }
Florin Malita1e18aa62017-11-19 10:22:22 -0500759 int textSize = pe.extended ? reader.read32() : 0;
Khushalcea8e3d2018-05-07 13:57:43 -0700760 if (textSize < 0) {
Florin Malita1e18aa62017-11-19 10:22:22 -0500761 return nullptr;
762 }
Mike Reedb99bedd2017-07-11 10:27:40 -0400763
764 SkPoint offset;
765 reader.readPoint(&offset);
Mike Reed0951cc22018-12-21 16:19:24 -0500766 SkFont font;
767 if (reader.isVersionLT(SkReadBuffer::kSerializeFonts_Version)) {
768 SkPaint paint;
769 reader.readPaint(&paint);
770 font = SkFont::LEGACY_ExtractFromPaint(paint);
771 } else {
772 SkFontPriv::Unflatten(&font, reader);
773 }
Mike Reedb99bedd2017-07-11 10:27:40 -0400774
Khushalcea8e3d2018-05-07 13:57:43 -0700775 // Compute the expected size of the buffer and ensure we have enough to deserialize
776 // a run before allocating it.
777 const size_t glyphSize = safe.mul(glyphCount, sizeof(uint16_t)),
778 posSize =
Cary Clark53c87692018-07-17 08:59:34 -0400779 safe.mul(glyphCount, safe.mul(sizeof(SkScalar),
780 SkTextBlob::ScalarsPerGlyph(pos))),
Khushalcea8e3d2018-05-07 13:57:43 -0700781 clusterSize = pe.extended ? safe.mul(glyphCount, sizeof(uint32_t)) : 0;
782 const size_t totalSize =
783 safe.add(safe.add(glyphSize, posSize), safe.add(clusterSize, textSize));
784
785 if (!reader.isValid() || !safe || totalSize > reader.available()) {
Florin Malita1e18aa62017-11-19 10:22:22 -0500786 return nullptr;
787 }
788
Mike Reedb99bedd2017-07-11 10:27:40 -0400789 const SkTextBlobBuilder::RunBuffer* buf = nullptr;
790 switch (pos) {
Cary Clark53c87692018-07-17 08:59:34 -0400791 case SkTextBlob::kDefault_Positioning:
Mike Reedb99bedd2017-07-11 10:27:40 -0400792 buf = &blobBuilder.allocRunText(font, glyphCount, offset.x(), offset.y(),
Mike Reedf4dd96c2018-12-21 20:49:47 +0000793 textSize, SkString(), &bounds);
Mike Reedb99bedd2017-07-11 10:27:40 -0400794 break;
Cary Clark53c87692018-07-17 08:59:34 -0400795 case SkTextBlob::kHorizontal_Positioning:
Mike Reedb99bedd2017-07-11 10:27:40 -0400796 buf = &blobBuilder.allocRunTextPosH(font, glyphCount, offset.y(),
Mike Reedf4dd96c2018-12-21 20:49:47 +0000797 textSize, SkString(), &bounds);
Mike Reedb99bedd2017-07-11 10:27:40 -0400798 break;
Cary Clark53c87692018-07-17 08:59:34 -0400799 case SkTextBlob::kFull_Positioning:
Mike Reedf4dd96c2018-12-21 20:49:47 +0000800 buf = &blobBuilder.allocRunTextPos(font, glyphCount, textSize, SkString(), &bounds);
Mike Reedb99bedd2017-07-11 10:27:40 -0400801 break;
Mike Reed30cf62b2018-12-20 11:18:24 -0500802 case SkTextBlob::kRSXform_Positioning:
Mike Reedf4dd96c2018-12-21 20:49:47 +0000803 buf = &blobBuilder.allocRunRSXform(font, glyphCount, textSize, SkString(), &bounds);
Mike Reed30cf62b2018-12-20 11:18:24 -0500804 break;
Mike Reedb99bedd2017-07-11 10:27:40 -0400805 }
806
Florin Malita90dcafc2017-11-22 10:53:33 -0500807 if (!buf->glyphs ||
808 !buf->pos ||
809 (pe.extended && (!buf->clusters || !buf->utf8text))) {
810 return nullptr;
811 }
812
Khushalcea8e3d2018-05-07 13:57:43 -0700813 if (!reader.readByteArray(buf->glyphs, glyphSize) ||
814 !reader.readByteArray(buf->pos, posSize)) {
815 return nullptr;
Mike Reedb99bedd2017-07-11 10:27:40 -0400816 }
817
818 if (pe.extended) {
Khushalcea8e3d2018-05-07 13:57:43 -0700819 if (!reader.readByteArray(buf->clusters, clusterSize) ||
Mike Reedb99bedd2017-07-11 10:27:40 -0400820 !reader.readByteArray(buf->utf8text, textSize)) {
821 return nullptr;
822 }
823 }
824 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400825
Mike Reedb99bedd2017-07-11 10:27:40 -0400826 return blobBuilder.make();
827}
828
Mike Reed3185f902018-10-26 16:33:00 -0400829sk_sp<SkTextBlob> SkTextBlob::MakeFromText(const void* text, size_t byteLength, const SkFont& font,
Mike Reed97f3cc22018-12-03 09:45:17 -0500830 SkTextEncoding encoding) {
Mike Reedefb518d2018-12-06 13:30:23 -0500831 // Note: we deliberately promote this to fully positioned blobs, since we'd have to pay the
832 // same cost down stream (i.e. computing bounds), so its cheaper to pay the cost once now.
833 const int count = font.countText(text, byteLength, encoding);
834 SkTextBlobBuilder builder;
835 auto buffer = builder.allocRunPos(font, count);
836 font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
837 font.getPos(buffer.glyphs, count, reinterpret_cast<SkPoint*>(buffer.pos), {0, 0});
838 return builder.make();
839}
Mike Reed3185f902018-10-26 16:33:00 -0400840
Mike Reedefb518d2018-12-06 13:30:23 -0500841sk_sp<SkTextBlob> SkTextBlob::MakeFromPosText(const void* text, size_t byteLength,
842 const SkPoint pos[], const SkFont& font,
843 SkTextEncoding encoding) {
844 const int count = font.countText(text, byteLength, encoding);
845 SkTextBlobBuilder builder;
846 auto buffer = builder.allocRunPos(font, count);
847 font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
848 memcpy(buffer.pos, pos, count * sizeof(SkPoint));
849 return builder.make();
850}
Herb Derby4b3a5152018-07-17 16:10:30 -0400851
Mike Reedefb518d2018-12-06 13:30:23 -0500852sk_sp<SkTextBlob> SkTextBlob::MakeFromPosTextH(const void* text, size_t byteLength,
853 const SkScalar xpos[], SkScalar constY,
854 const SkFont& font, SkTextEncoding encoding) {
855 const int count = font.countText(text, byteLength, encoding);
856 SkTextBlobBuilder builder;
857 auto buffer = builder.allocRunPosH(font, count, constY);
858 font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
859 memcpy(buffer.pos, xpos, count * sizeof(SkScalar));
860 return builder.make();
Herb Derby4b3a5152018-07-17 16:10:30 -0400861}
862
Mike Reed30cf62b2018-12-20 11:18:24 -0500863sk_sp<SkTextBlob> SkTextBlob::MakeFromRSXform(const void* text, size_t byteLength,
864 const SkRSXform xform[], const SkFont& font,
865 SkTextEncoding encoding) {
866 const int count = font.countText(text, byteLength, encoding);
867 SkTextBlobBuilder builder;
868 auto buffer = builder.allocRunRSXform(font, count);
869 font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
870 memcpy(buffer.pos, xform, count * sizeof(SkRSXform));
871 return builder.make();
872}
873
Mike Reed8e74cbc2017-12-08 13:20:01 -0500874sk_sp<SkData> SkTextBlob::serialize(const SkSerialProcs& procs) const {
875 SkBinaryWriteBuffer buffer;
876 buffer.setSerialProcs(procs);
Cary Clark53c87692018-07-17 08:59:34 -0400877 SkTextBlobPriv::Flatten(*this, buffer);
Mike Reedb99bedd2017-07-11 10:27:40 -0400878
879 size_t total = buffer.bytesWritten();
880 sk_sp<SkData> data = SkData::MakeUninitialized(total);
881 buffer.writeToMemory(data->writable_data());
882 return data;
883}
884
Mike Reed8e74cbc2017-12-08 13:20:01 -0500885sk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length,
886 const SkDeserialProcs& procs) {
887 SkReadBuffer buffer(data, length);
888 buffer.setDeserialProcs(procs);
Cary Clark53c87692018-07-17 08:59:34 -0400889 return SkTextBlobPriv::MakeFromBuffer(buffer);
Mike Reedf6eb1f92017-12-19 17:12:13 -0500890}
891
Mike Reed8e74cbc2017-12-08 13:20:01 -0500892///////////////////////////////////////////////////////////////////////////////////////////////////
893
Khushal42f8bc42018-04-03 17:51:40 -0700894size_t SkTextBlob::serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const {
895 SkBinaryWriteBuffer buffer(memory, memory_size);
896 buffer.setSerialProcs(procs);
Cary Clark53c87692018-07-17 08:59:34 -0400897 SkTextBlobPriv::Flatten(*this, buffer);
Khushal42f8bc42018-04-03 17:51:40 -0700898 return buffer.usingInitialStorage() ? buffer.bytesWritten() : 0u;
899}