OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkTextBlob.h" | 8 #include "SkTextBlob.h" |
9 | 9 |
10 #include "SkReadBuffer.h" | 10 #include "SkReadBuffer.h" |
11 #include "SkTypeface.h" | 11 #include "SkTypeface.h" |
12 #include "SkWriteBuffer.h" | 12 #include "SkWriteBuffer.h" |
13 | 13 |
| 14 namespace { |
| 15 |
| 16 // TODO(fmalita): replace with SkFont. |
| 17 class RunFont : SkNoncopyable { |
| 18 public: |
| 19 RunFont(const SkPaint& paint) |
| 20 : fSize(paint.getTextSize()) |
| 21 , fScaleX(paint.getTextScaleX()) |
| 22 , fTypeface(SkSafeRef(paint.getTypeface())) |
| 23 , fSkewX(paint.getTextSkewX()) |
| 24 , fHinting(paint.getHinting()) |
| 25 , fFlags(paint.getFlags() & kFlagsMask) { } |
| 26 |
| 27 void applyToPaint(SkPaint* paint) const { |
| 28 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 29 paint->setTypeface(fTypeface.get()); |
| 30 paint->setTextSize(fSize); |
| 31 paint->setTextScaleX(fScaleX); |
| 32 paint->setTextSkewX(fSkewX); |
| 33 paint->setHinting(static_cast<SkPaint::Hinting>(fHinting)); |
| 34 |
| 35 paint->setFlags((paint->getFlags() & ~kFlagsMask) | fFlags); |
| 36 } |
| 37 |
| 38 bool operator==(const RunFont& other) const { |
| 39 return fTypeface == other.fTypeface |
| 40 && fSize == other.fSize |
| 41 && fScaleX == other.fScaleX |
| 42 && fSkewX == other.fSkewX |
| 43 && fHinting == other.fHinting |
| 44 && fFlags == other.fFlags; |
| 45 } |
| 46 |
| 47 bool operator!=(const RunFont& other) const { |
| 48 return !(*this == other); |
| 49 } |
| 50 private: |
| 51 const static uint32_t kFlagsMask = |
| 52 SkPaint::kAntiAlias_Flag | |
| 53 SkPaint::kUnderlineText_Flag | |
| 54 SkPaint::kStrikeThruText_Flag | |
| 55 SkPaint::kFakeBoldText_Flag | |
| 56 SkPaint::kLinearText_Flag | |
| 57 SkPaint::kSubpixelText_Flag | |
| 58 SkPaint::kDevKernText_Flag | |
| 59 SkPaint::kLCDRenderText_Flag | |
| 60 SkPaint::kEmbeddedBitmapText_Flag | |
| 61 SkPaint::kAutoHinting_Flag | |
| 62 SkPaint::kVerticalText_Flag | |
| 63 SkPaint::kGenA8FromLCD_Flag | |
| 64 SkPaint::kDistanceFieldTextTEMP_Flag; |
| 65 |
| 66 SkScalar fSize; |
| 67 SkScalar fScaleX; |
| 68 |
| 69 // Keep this SkAutoTUnref off the first position, to avoid interfering with
SkNoncopyable |
| 70 // empty baseclass optimization (http://code.google.com/p/skia/issues/detail
?id=3694). |
| 71 SkAutoTUnref<SkTypeface> fTypeface; |
| 72 SkScalar fSkewX; |
| 73 |
| 74 SK_COMPILE_ASSERT(SkPaint::kFull_Hinting < 4, insufficient_hinting_bits); |
| 75 uint32_t fHinting : 2; |
| 76 SK_COMPILE_ASSERT((kFlagsMask & 0xffff) == kFlagsMask, insufficient_flags_bi
ts); |
| 77 uint32_t fFlags : 16; |
| 78 |
| 79 typedef SkNoncopyable INHERITED; |
| 80 }; |
| 81 |
| 82 struct RunFontStorageEquivalent { |
| 83 SkScalar fSize, fScaleX; |
| 84 void* fTypeface; |
| 85 SkScalar fSkewX; |
| 86 uint32_t fFlags; |
| 87 }; |
| 88 SK_COMPILE_ASSERT(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), runfont_s
hould_stay_packed); |
| 89 |
| 90 } // anonymous namespace |
| 91 |
14 // | 92 // |
15 // Textblob data is laid out into externally-managed storage as follows: | 93 // Textblob data is laid out into externally-managed storage as follows: |
16 // | 94 // |
17 // --------------------------------------------------------------------------
--- | 95 // --------------------------------------------------------------------------
--- |
18 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[]
| ... | 96 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[]
| ... |
19 // --------------------------------------------------------------------------
--- | 97 // --------------------------------------------------------------------------
--- |
20 // | 98 // |
21 // Each run record describes a text blob run, and can be used to determine the
(implicit) | 99 // Each run record describes a text blob run, and can be used to determine the
(implicit) |
22 // location of the following record. | 100 // location of the following record. |
23 | 101 |
24 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) | 102 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) |
25 | 103 |
26 class SkTextBlob::RunRecord { | 104 class SkTextBlob::RunRecord { |
27 public: | 105 public: |
28 RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphP
ositioning pos) | 106 RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphP
ositioning pos) |
29 : fCount(count) | 107 : fFont(font) |
| 108 , fCount(count) |
30 , fOffset(offset) | 109 , fOffset(offset) |
31 , fFont(font) | |
32 , fPositioning(pos) { | 110 , fPositioning(pos) { |
33 SkDEBUGCODE(fMagic = kRunRecordMagic); | 111 SkDEBUGCODE(fMagic = kRunRecordMagic); |
34 } | 112 } |
35 | 113 |
36 uint32_t glyphCount() const { | 114 uint32_t glyphCount() const { |
37 return fCount; | 115 return fCount; |
38 } | 116 } |
39 | 117 |
40 const SkPoint& offset() const { | 118 const SkPoint& offset() const { |
41 return fOffset; | 119 return fOffset; |
42 } | 120 } |
43 | 121 |
44 const SkPaint& font() const { | 122 const RunFont& font() const { |
45 return fFont; | 123 return fFont; |
46 } | 124 } |
47 | 125 |
48 GlyphPositioning positioning() const { | 126 GlyphPositioning positioning() const { |
49 return fPositioning; | 127 return fPositioning; |
50 } | 128 } |
51 | 129 |
52 uint16_t* glyphBuffer() const { | 130 uint16_t* glyphBuffer() const { |
53 // Glyph are stored immediately following the record. | 131 // Glyph are stored immediately following the record. |
54 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); | 132 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 fCount += count; | 171 fCount += count; |
94 | 172 |
95 // Move the initial pos scalars to their new location. | 173 // Move the initial pos scalars to their new location. |
96 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos
itioning); | 174 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos
itioning); |
97 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); | 175 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); |
98 | 176 |
99 // memmove, as the buffers may overlap | 177 // memmove, as the buffers may overlap |
100 memmove(posBuffer(), initialPosBuffer, copySize); | 178 memmove(posBuffer(), initialPosBuffer, copySize); |
101 } | 179 } |
102 | 180 |
| 181 RunFont fFont; |
103 uint32_t fCount; | 182 uint32_t fCount; |
104 SkPoint fOffset; | 183 SkPoint fOffset; |
105 SkPaint fFont; | |
106 GlyphPositioning fPositioning; | 184 GlyphPositioning fPositioning; |
107 | 185 |
108 SkDEBUGCODE(unsigned fMagic;) | 186 SkDEBUGCODE(unsigned fMagic;) |
109 }; | 187 }; |
110 | 188 |
111 static int32_t gNextID = 1; | 189 static int32_t gNextID = 1; |
112 static int32_t next_id() { | 190 static int32_t next_id() { |
113 int32_t id; | 191 int32_t id; |
114 do { | 192 do { |
115 id = sk_atomic_inc(&gNextID); | 193 id = sk_atomic_inc(&gNextID); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 } | 333 } |
256 | 334 |
257 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const { | 335 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const { |
258 SkASSERT(!this->done()); | 336 SkASSERT(!this->done()); |
259 return fCurrentRun->positioning(); | 337 return fCurrentRun->positioning(); |
260 } | 338 } |
261 | 339 |
262 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const { | 340 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const { |
263 SkASSERT(!this->done()); | 341 SkASSERT(!this->done()); |
264 | 342 |
265 const SkPaint& font = fCurrentRun->font(); | 343 fCurrentRun->font().applyToPaint(paint); |
266 | |
267 paint->setTypeface(font.getTypeface()); | |
268 paint->setTextEncoding(font.getTextEncoding()); | |
269 paint->setTextSize(font.getTextSize()); | |
270 paint->setTextScaleX(font.getTextScaleX()); | |
271 paint->setTextSkewX(font.getTextSkewX()); | |
272 paint->setHinting(font.getHinting()); | |
273 | |
274 uint32_t flagsMask = SkPaint::kAntiAlias_Flag | |
275 | SkPaint::kUnderlineText_Flag | |
276 | SkPaint::kStrikeThruText_Flag | |
277 | SkPaint::kFakeBoldText_Flag | |
278 | SkPaint::kLinearText_Flag | |
279 | SkPaint::kSubpixelText_Flag | |
280 | SkPaint::kDevKernText_Flag | |
281 | SkPaint::kLCDRenderText_Flag | |
282 | SkPaint::kEmbeddedBitmapText_Flag | |
283 | SkPaint::kAutoHinting_Flag | |
284 | SkPaint::kVerticalText_Flag | |
285 | SkPaint::kGenA8FromLCD_Flag | |
286 | SkPaint::kDistanceFieldTextTEMP_Flag; | |
287 paint->setFlags((paint->getFlags() & ~flagsMask) | (font.getFlags() & flagsM
ask)); | |
288 } | 344 } |
289 | 345 |
290 SkTextBlobBuilder::SkTextBlobBuilder() | 346 SkTextBlobBuilder::SkTextBlobBuilder() |
291 : fStorageSize(0) | 347 : fStorageSize(0) |
292 , fStorageUsed(0) | 348 , fStorageUsed(0) |
293 , fRunCount(0) | 349 , fRunCount(0) |
294 , fDeferredBounds(false) | 350 , fDeferredBounds(false) |
295 , fLastRun(0) { | 351 , fLastRun(0) { |
296 fBounds.setEmpty(); | 352 fBounds.setEmpty(); |
297 } | 353 } |
298 | 354 |
299 SkTextBlobBuilder::~SkTextBlobBuilder() { | 355 SkTextBlobBuilder::~SkTextBlobBuilder() { |
300 if (NULL != fStorage.get()) { | 356 if (NULL != fStorage.get()) { |
301 // We are abandoning runs and must destruct the associated font data. | 357 // We are abandoning runs and must destruct the associated font data. |
302 // The easiest way to accomplish that is to use the blob destructor. | 358 // The easiest way to accomplish that is to use the blob destructor. |
303 build()->unref(); | 359 build()->unref(); |
304 } | 360 } |
305 } | 361 } |
306 | 362 |
307 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { | 363 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { |
308 SkASSERT(SkTextBlob::kDefault_Positioning == run.positioning()); | 364 SkASSERT(SkTextBlob::kDefault_Positioning == run.positioning()); |
309 | 365 |
310 SkRect bounds; | 366 SkRect bounds; |
311 run.font().measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t
), &bounds); | 367 SkPaint paint; |
| 368 run.font().applyToPaint(&paint); |
| 369 paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &b
ounds); |
312 | 370 |
313 return bounds.makeOffset(run.offset().x(), run.offset().y()); | 371 return bounds.makeOffset(run.offset().x(), run.offset().y()); |
314 } | 372 } |
315 | 373 |
316 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run
) { | 374 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run
) { |
317 SkASSERT(run.glyphCount() > 0); | 375 SkASSERT(run.glyphCount() > 0); |
318 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || | 376 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || |
319 SkTextBlob::kHorizontal_Positioning == run.positioning()); | 377 SkTextBlob::kHorizontal_Positioning == run.positioning()); |
320 | 378 |
321 // First, compute the glyph position bbox. | 379 // First, compute the glyph position bbox. |
(...skipping 17 matching lines...) Expand all Loading... |
339 const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuf
fer()); | 397 const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuf
fer()); |
340 SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecor
d::Next(&run)); | 398 SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecor
d::Next(&run)); |
341 | 399 |
342 bounds.setBounds(glyphPosPts, run.glyphCount()); | 400 bounds.setBounds(glyphPosPts, run.glyphCount()); |
343 } break; | 401 } break; |
344 default: | 402 default: |
345 SkFAIL("unsupported positioning mode"); | 403 SkFAIL("unsupported positioning mode"); |
346 } | 404 } |
347 | 405 |
348 // Expand by typeface glyph bounds. | 406 // Expand by typeface glyph bounds. |
349 const SkRect fontBounds = run.font().getFontBounds(); | 407 SkPaint paint; |
| 408 run.font().applyToPaint(&paint); |
| 409 const SkRect fontBounds = paint.getFontBounds(); |
350 bounds.fLeft += fontBounds.left(); | 410 bounds.fLeft += fontBounds.left(); |
351 bounds.fTop += fontBounds.top(); | 411 bounds.fTop += fontBounds.top(); |
352 bounds.fRight += fontBounds.right(); | 412 bounds.fRight += fontBounds.right(); |
353 bounds.fBottom += fontBounds.bottom(); | 413 bounds.fBottom += fontBounds.bottom(); |
354 | 414 |
355 // Offset by run position. | 415 // Offset by run position. |
356 return bounds.makeOffset(run.offset().x(), run.offset().y()); | 416 return bounds.makeOffset(run.offset().x(), run.offset().y()); |
357 } | 417 } |
358 | 418 |
359 void SkTextBlobBuilder::updateDeferredBounds() { | 419 void SkTextBlobBuilder::updateDeferredBounds() { |
360 SkASSERT(!fDeferredBounds || fRunCount > 0); | 420 SkASSERT(!fDeferredBounds || fRunCount > 0); |
361 | 421 |
362 if (!fDeferredBounds) { | 422 if (!fDeferredBounds) { |
363 return; | 423 return; |
364 } | 424 } |
365 | 425 |
366 SkASSERT(fLastRun >= sizeof(SkTextBlob)); | 426 SkASSERT(fLastRun >= sizeof(SkTextBlob)); |
367 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora
ge.get() + | 427 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora
ge.get() + |
368 fLastR
un); | 428 fLastR
un); |
369 SkASSERT(SkPaint::kGlyphID_TextEncoding == run->font().getTextEncoding()); | |
370 | 429 |
371 // FIXME: we should also use conservative bounds for kDefault_Positioning. | 430 // FIXME: we should also use conservative bounds for kDefault_Positioning. |
372 SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ? | 431 SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ? |
373 TightRunBounds(*run) : ConservativeRunBounds(*run); | 432 TightRunBounds(*run) : ConservativeRunBounds(*run); |
374 fBounds.join(runBounds); | 433 fBounds.join(runBounds); |
375 fDeferredBounds = false; | 434 fDeferredBounds = false; |
376 } | 435 } |
377 | 436 |
378 void SkTextBlobBuilder::reserve(size_t size) { | 437 void SkTextBlobBuilder::reserve(size_t size) { |
379 // We don't currently pre-allocate, but maybe someday... | 438 // We don't currently pre-allocate, but maybe someday... |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 | 594 |
536 fStorageUsed = 0; | 595 fStorageUsed = 0; |
537 fStorageSize = 0; | 596 fStorageSize = 0; |
538 fRunCount = 0; | 597 fRunCount = 0; |
539 fLastRun = 0; | 598 fLastRun = 0; |
540 fBounds.setEmpty(); | 599 fBounds.setEmpty(); |
541 | 600 |
542 return blob; | 601 return blob; |
543 } | 602 } |
544 | 603 |
OLD | NEW |