OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 #ifndef SkFindAndPositionGlyph_DEFINED | 8 #ifndef SkFindAndPositionGlyph_DEFINED |
9 #define SkFindAndPositionGlyph_DEFINED | 9 #define SkFindAndPositionGlyph_DEFINED |
10 | 10 |
11 #include "SkAutoKern.h" | 11 #include "SkAutoKern.h" |
12 #include "SkGlyph.h" | 12 #include "SkGlyph.h" |
13 #include "SkGlyphCache.h" | 13 #include "SkGlyphCache.h" |
14 #include "SkPaint.h" | 14 #include "SkPaint.h" |
15 #include "SkTemplates.h" | 15 #include "SkTemplates.h" |
| 16 #include "SkUtils.h" |
16 | 17 |
17 // Calculate a type with the same size as the max of all the Ts. | 18 // Calculate a type with the same size as the max of all the Ts. |
18 // This must be top level because the is no specialization of inner classes. | 19 // This must be top level because the is no specialization of inner classes. |
19 template<typename... Ts> struct SkMaxSizeOf; | 20 template<typename... Ts> struct SkMaxSizeOf; |
20 | 21 |
21 template<> | 22 template<> |
22 struct SkMaxSizeOf<> { | 23 struct SkMaxSizeOf<> { |
23 static const size_t value = 0; | 24 static const size_t value = 0; |
24 }; | 25 }; |
25 | 26 |
26 template<typename H, typename... Ts> | 27 template<typename H, typename... Ts> |
27 struct SkMaxSizeOf<H, Ts...> { | 28 struct SkMaxSizeOf<H, Ts...> { |
28 static const size_t value = | 29 static const size_t value = |
29 sizeof(H) >= SkMaxSizeOf<Ts...>::value ? sizeof(H) : SkMaxSizeOf<Ts...>:
:value; | 30 sizeof(H) >= SkMaxSizeOf<Ts...>::value ? sizeof(H) : SkMaxSizeOf<Ts...>:
:value; |
30 }; | 31 }; |
31 | 32 |
32 class SkFindAndPlaceGlyph { | 33 class SkFindAndPlaceGlyph { |
33 public: | 34 public: |
34 template<typename ProcessOneGlyph> | 35 template<typename ProcessOneGlyph> |
35 static void ProcessText(const char text[], size_t byteLength, SkPoint offset
, const | 36 static void ProcessText( |
36 SkMatrix& matrix, SkPaint::Align textAlignment, SkDrawCacheProc& glyphCacheP
roc, | 37 SkPaint::TextEncoding, const char text[], size_t byteLength, |
37 SkGlyphCache* cache, ProcessOneGlyph&& processOneGly
ph); | 38 SkPoint offset, const SkMatrix& matrix, SkPaint::Align textAlignment, |
| 39 SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph); |
38 // ProcessPosText handles all cases for finding and positioning glyphs. It h
as a very large | 40 // ProcessPosText handles all cases for finding and positioning glyphs. It h
as a very large |
39 // multiplicity. It figures out the glyph, position and rounding and pass th
ose parameters to | 41 // multiplicity. It figures out the glyph, position and rounding and pass th
ose parameters to |
40 // processOneGlyph. | 42 // processOneGlyph. |
41 // | 43 // |
42 // The routine processOneGlyph passed in by the client has the following sig
nature: | 44 // The routine processOneGlyph passed in by the client has the following sig
nature: |
43 // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding); | 45 // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding); |
44 // | 46 // |
45 // * Sub-pixel positioning (2) - use sub-pixel positioning. | 47 // * Sub-pixel positioning (2) - use sub-pixel positioning. |
46 // * Text alignment (3) - text alignment with respect to the glyph's width. | 48 // * Text alignment (3) - text alignment with respect to the glyph's width. |
47 // * Matrix type (3) - special cases for translation and X-coordinate scalin
g. | 49 // * Matrix type (3) - special cases for translation and X-coordinate scalin
g. |
48 // * Components per position (2) - the positions vector can have a common Y
with different | 50 // * Components per position (2) - the positions vector can have a common Y
with different |
49 // Xs, or XY-pairs. | 51 // Xs, or XY-pairs. |
50 // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel p
ositioning, round | 52 // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel p
ositioning, round |
51 // to a whole coordinate instead of using sub-pixel positioning. | 53 // to a whole coordinate instead of using sub-pixel positioning. |
52 // The number of variations is 108 for sub-pixel and 36 for full-pixel. | 54 // The number of variations is 108 for sub-pixel and 36 for full-pixel. |
53 // This routine handles all of them using inline polymorphic variable (no he
ap allocation). | 55 // This routine handles all of them using inline polymorphic variable (no he
ap allocation). |
54 template<typename ProcessOneGlyph> | 56 template<typename ProcessOneGlyph> |
55 static void ProcessPosText(const char text[], size_t byteLength, | 57 static void ProcessPosText( |
56 SkPoint offset, const SkMatrix& matrix, | 58 SkPaint::TextEncoding, const char text[], size_t byteLength, |
57 const SkScalar pos[], int scalarsPerPosition, | 59 SkPoint offset, const SkMatrix& matrix, const SkScalar pos[], int scalar
sPerPosition, |
58 SkPaint::Align textAlignment, SkDrawCacheProc& gl
yphCacheProc, | 60 SkPaint::Align textAlignment, |
59 SkGlyphCache* cache, ProcessOneGlyph&& processOne
Glyph); | 61 SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph); |
60 | 62 |
61 private: | 63 private: |
62 // UntaggedVariant is a pile of memory that can hold one of the Ts. It provi
des a way | 64 // UntaggedVariant is a pile of memory that can hold one of the Ts. It provi
des a way |
63 // to initialize that memory in a typesafe way. | 65 // to initialize that memory in a typesafe way. |
64 template<typename... Ts> | 66 template<typename... Ts> |
65 class UntaggedVariant { | 67 class UntaggedVariant { |
66 public: | 68 public: |
67 UntaggedVariant() { } | 69 UntaggedVariant() { } |
68 | 70 |
69 ~UntaggedVariant() { } | 71 ~UntaggedVariant() { } |
(...skipping 29 matching lines...) Expand all Loading... |
99 } | 101 } |
100 ~PolymorphicVariant() { get()->~Base(); } | 102 ~PolymorphicVariant() { get()->~Base(); } |
101 Base* get() const { return reinterpret_cast<Base*>(&fVariants); } | 103 Base* get() const { return reinterpret_cast<Base*>(&fVariants); } |
102 Base* operator->() const { return get(); } | 104 Base* operator->() const { return get(); } |
103 Base& operator*() const { return *get(); } | 105 Base& operator*() const { return *get(); } |
104 | 106 |
105 private: | 107 private: |
106 mutable Variants fVariants; | 108 mutable Variants fVariants; |
107 }; | 109 }; |
108 | 110 |
| 111 // GlyphFinderInterface is the polymorphic base for classes that parse a str
eam of chars into |
| 112 // the right UniChar (or GlyphID) and lookup up the glyph on the cache. The
concrete |
| 113 // implementations are: Utf8GlyphFinder, Utf16GlyphFinder, Utf32GlyphFinder, |
| 114 // and GlyphIdGlyphFinder. |
| 115 class GlyphFinderInterface { |
| 116 public: |
| 117 virtual ~GlyphFinderInterface() {} |
| 118 virtual const SkGlyph& lookupGlyph(const char** text) = 0; |
| 119 virtual const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFix
ed y) = 0; |
| 120 }; |
| 121 |
| 122 class UtfNGlyphFinder : public GlyphFinderInterface { |
| 123 public: |
| 124 UtfNGlyphFinder(SkGlyphCache* cache) : fCache(cache) { SkASSERT(cache !=
nullptr); } |
| 125 |
| 126 const SkGlyph& lookupGlyph(const char** text) override { |
| 127 SkASSERT(text != nullptr); |
| 128 return fCache->getUnicharMetrics(nextUnichar(text)); |
| 129 } |
| 130 const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) ov
erride { |
| 131 SkASSERT(text != nullptr); |
| 132 return fCache->getUnicharMetrics(nextUnichar(text), x, y); |
| 133 } |
| 134 |
| 135 private: |
| 136 virtual SkUnichar nextUnichar(const char** text) = 0; |
| 137 SkGlyphCache* fCache; |
| 138 }; |
| 139 |
| 140 class Utf8GlyphFinder final : public UtfNGlyphFinder { |
| 141 public: |
| 142 Utf8GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { } |
| 143 |
| 144 private: |
| 145 SkUnichar nextUnichar(const char** text) override { return SkUTF8_NextUn
ichar(text); } |
| 146 }; |
| 147 |
| 148 class Utf16GlyphFinder final : public UtfNGlyphFinder { |
| 149 public: |
| 150 Utf16GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { } |
| 151 |
| 152 private: |
| 153 SkUnichar nextUnichar(const char** text) override { |
| 154 return SkUTF16_NextUnichar((const uint16_t**)text); |
| 155 } |
| 156 }; |
| 157 |
| 158 class Utf32GlyphFinder final : public UtfNGlyphFinder { |
| 159 public: |
| 160 Utf32GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { } |
| 161 |
| 162 private: |
| 163 SkUnichar nextUnichar(const char** text) override { |
| 164 const int32_t* ptr = *(const int32_t**)text; |
| 165 SkUnichar uni = *ptr++; |
| 166 *text = (const char*)ptr; |
| 167 return uni; |
| 168 } |
| 169 }; |
| 170 |
| 171 class GlyphIdGlyphFinder final : public GlyphFinderInterface { |
| 172 public: |
| 173 GlyphIdGlyphFinder(SkGlyphCache* cache) : fCache(cache) { SkASSERT(cache
!= nullptr); } |
| 174 |
| 175 const SkGlyph& lookupGlyph(const char** text) override { |
| 176 return fCache->getGlyphIDMetrics(nextGlyphId(text)); |
| 177 } |
| 178 const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) ov
erride { |
| 179 return fCache->getGlyphIDMetrics(nextGlyphId(text), x, y); |
| 180 } |
| 181 |
| 182 private: |
| 183 uint16_t nextGlyphId(const char** text) { |
| 184 SkASSERT(text != nullptr); |
| 185 |
| 186 const uint16_t* ptr = *(const uint16_t**)text; |
| 187 uint16_t glyphID = *ptr; |
| 188 ptr += 1; |
| 189 *text = (const char*)ptr; |
| 190 return glyphID; |
| 191 } |
| 192 SkGlyphCache* fCache; |
| 193 }; |
| 194 |
| 195 typedef PolymorphicVariant< |
| 196 GlyphFinderInterface, |
| 197 Utf8GlyphFinder, |
| 198 Utf16GlyphFinder, |
| 199 Utf32GlyphFinder, |
| 200 GlyphIdGlyphFinder> LookupGlyphVariant; |
| 201 |
| 202 class LookupGlyph : public LookupGlyphVariant { |
| 203 public: |
| 204 LookupGlyph(SkPaint::TextEncoding encoding, SkGlyphCache* cache) |
| 205 : LookupGlyphVariant( |
| 206 [&](LookupGlyphVariant::Variants* to_init) { |
| 207 switch(encoding) { |
| 208 case SkPaint::kUTF8_TextEncoding: |
| 209 to_init->initialize<Utf8GlyphFinder>(cache); |
| 210 break; |
| 211 case SkPaint::kUTF16_TextEncoding: |
| 212 to_init->initialize<Utf16GlyphFinder>(cache); |
| 213 break; |
| 214 case SkPaint::kUTF32_TextEncoding: |
| 215 to_init->initialize<Utf32GlyphFinder>(cache); |
| 216 break; |
| 217 case SkPaint::kGlyphID_TextEncoding: |
| 218 to_init->initialize<GlyphIdGlyphFinder>(cache); |
| 219 break; |
| 220 } |
| 221 } |
| 222 ) { } |
| 223 }; |
| 224 |
109 // PositionReaderInterface reads a point from the pos vector. | 225 // PositionReaderInterface reads a point from the pos vector. |
110 // * HorizontalPositions - assumes a common Y for many X values. | 226 // * HorizontalPositions - assumes a common Y for many X values. |
111 // * ArbitraryPositions - a list of (X,Y) pairs. | 227 // * ArbitraryPositions - a list of (X,Y) pairs. |
112 class PositionReaderInterface { | 228 class PositionReaderInterface { |
113 public: | 229 public: |
114 virtual ~PositionReaderInterface() { } | 230 virtual ~PositionReaderInterface() { } |
115 virtual SkPoint nextPoint() = 0; | 231 virtual SkPoint nextPoint() = 0; |
116 }; | 232 }; |
117 | 233 |
118 class HorizontalPositions final : public PositionReaderInterface { | 234 class HorizontalPositions final : public PositionReaderInterface { |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 }; | 402 }; |
287 }; | 403 }; |
288 | 404 |
289 // GlyphFindAndPlaceSubpixel handles finding and placing glyphs when sub-pix
el positioning is | 405 // GlyphFindAndPlaceSubpixel handles finding and placing glyphs when sub-pix
el positioning is |
290 // requested. After it has found and placed the glyph it calls the templated
function | 406 // requested. After it has found and placed the glyph it calls the templated
function |
291 // ProcessOneGlyph in order to actually perform an action. | 407 // ProcessOneGlyph in order to actually perform an action. |
292 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, | 408 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, |
293 SkAxisAlignment kAxisAlignment> | 409 SkAxisAlignment kAxisAlignment> |
294 class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface<Pr
ocessOneGlyph> { | 410 class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface<Pr
ocessOneGlyph> { |
295 public: | 411 public: |
296 GlyphFindAndPlaceSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCach
eProc) | 412 GlyphFindAndPlaceSubpixel(LookupGlyph& glyphFinder) |
297 : fCache(cache) | 413 : fGlyphFinder(glyphFinder) { } |
298 , fGlyphCacheProc(glyphCacheProc) { } | |
299 | 414 |
300 SkPoint findAndPositionGlyph( | 415 SkPoint findAndPositionGlyph( |
301 const char** text, SkPoint position, ProcessOneGlyph&& processOneGly
ph) override { | 416 const char** text, SkPoint position, ProcessOneGlyph&& processOneGly
ph) override { |
302 SkPoint finalPosition = position; | 417 SkPoint finalPosition = position; |
303 if (kTextAlignment != SkPaint::kLeft_Align) { | 418 if (kTextAlignment != SkPaint::kLeft_Align) { |
304 // Get the width of an un-sub-pixel positioned glyph for calcula
ting the | 419 // Get the width of an un-sub-pixel positioned glyph for calcula
ting the |
305 // alignment. This is not needed for kLeftAlign because its adju
stment is | 420 // alignment. This is not needed for kLeftAlign because its adju
stment is |
306 // always {0, 0}. | 421 // always {0, 0}. |
307 const char* tempText = *text; | 422 const char* tempText = *text; |
308 const SkGlyph &metricGlyph = fGlyphCacheProc(fCache, &tempText,
0, 0); | 423 const SkGlyph &metricGlyph = fGlyphFinder->lookupGlyph(&tempText
); |
309 | 424 |
310 if (metricGlyph.fWidth <= 0) { | 425 if (metricGlyph.fWidth <= 0) { |
311 // Exiting early, be sure to update text pointer. | 426 // Exiting early, be sure to update text pointer. |
312 *text = tempText; | 427 *text = tempText; |
313 return finalPosition + SkPoint{SkFixedToScalar(metricGlyph.f
AdvanceX), | 428 return finalPosition + SkPoint{SkFixedToScalar(metricGlyph.f
AdvanceX), |
314 SkFixedToScalar(metricGlyph.f
AdvanceY)}; | 429 SkFixedToScalar(metricGlyph.f
AdvanceY)}; |
315 } | 430 } |
316 | 431 |
317 // Adjust the final position by the alignment adjustment. | 432 // Adjust the final position by the alignment adjustment. |
318 finalPosition -= TextAlignmentAdjustment(kTextAlignment, metricG
lyph); | 433 finalPosition -= TextAlignmentAdjustment(kTextAlignment, metricG
lyph); |
319 } | 434 } |
320 | 435 |
321 // Find the glyph. | 436 // Find the glyph. |
322 SkIPoint lookupPosition = SubpixelAlignment(kAxisAlignment, finalPos
ition); | 437 SkIPoint lookupPosition = SubpixelAlignment(kAxisAlignment, finalPos
ition); |
323 const SkGlyph& renderGlyph = | 438 const SkGlyph& renderGlyph = |
324 fGlyphCacheProc(fCache, text, lookupPosition.fX, lookupPosition.
fY); | 439 fGlyphFinder->lookupGlyphXY(text, lookupPosition.fX, lookupPosit
ion.fY); |
325 | 440 |
326 // If the glyph has no width (no pixels) then don't bother processin
g it. | 441 // If the glyph has no width (no pixels) then don't bother processin
g it. |
327 if (renderGlyph.fWidth > 0) { | 442 if (renderGlyph.fWidth > 0) { |
328 processOneGlyph(renderGlyph, finalPosition, | 443 processOneGlyph(renderGlyph, finalPosition, |
329 SubpixelPositionRounding(kAxisAlignment)); | 444 SubpixelPositionRounding(kAxisAlignment)); |
330 } | 445 } |
331 return finalPosition + SkPoint{SkFixedToScalar(renderGlyph.fAdvanceX
), | 446 return finalPosition + SkPoint{SkFixedToScalar(renderGlyph.fAdvanceX
), |
332 SkFixedToScalar(renderGlyph.fAdvanceY
)}; | 447 SkFixedToScalar(renderGlyph.fAdvanceY
)}; |
333 } | 448 } |
334 | 449 |
335 private: | 450 private: |
336 SkGlyphCache* const fCache; | 451 LookupGlyph& fGlyphFinder; |
337 SkDrawCacheProc fGlyphCacheProc; | |
338 }; | 452 }; |
339 | 453 |
340 enum SelectKerning { | 454 enum SelectKerning { |
341 kNoKerning = false, | 455 kNoKerning = false, |
342 kUseKerning = true | 456 kUseKerning = true |
343 }; | 457 }; |
344 | 458 |
345 // GlyphFindAndPlaceFullPixel handles finding and placing glyphs when no sub
-pixel | 459 // GlyphFindAndPlaceFullPixel handles finding and placing glyphs when no sub
-pixel |
346 // positioning is requested. The kUseKerning argument should be true for dra
wText, and false | 460 // positioning is requested. The kUseKerning argument should be true for dra
wText, and false |
347 // for drawPosText. | 461 // for drawPosText. |
348 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SelectKern
ing kUseKerning> | 462 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SelectKern
ing kUseKerning> |
349 class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<P
rocessOneGlyph> { | 463 class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<P
rocessOneGlyph> { |
350 public: | 464 public: |
351 GlyphFindAndPlaceFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCac
heProc) | 465 GlyphFindAndPlaceFullPixel(LookupGlyph& glyphFinder) |
352 : fCache(cache), fGlyphCacheProc(glyphCacheProc) { | 466 : fGlyphFinder(glyphFinder) { |
353 // Kerning can only be used with SkPaint::kLeft_Align | 467 // Kerning can only be used with SkPaint::kLeft_Align |
354 static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment
, | 468 static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment
, |
355 "Kerning can only be used with left aligned text."); | 469 "Kerning can only be used with left aligned text."); |
356 } | 470 } |
357 | 471 |
358 SkPoint findAndPositionGlyph( | 472 SkPoint findAndPositionGlyph( |
359 const char** text, SkPoint position, ProcessOneGlyph&& processOneGly
ph) override { | 473 const char** text, SkPoint position, ProcessOneGlyph&& processOneGly
ph) override { |
360 SkPoint finalPosition = position; | 474 SkPoint finalPosition = position; |
361 const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0); | 475 const SkGlyph& glyph = fGlyphFinder->lookupGlyph(text); |
362 if (kUseKerning) { | 476 if (kUseKerning) { |
363 finalPosition += {SkFixedToScalar(fAutoKern.adjust(glyph)), 0.0f
}; | 477 finalPosition += {SkFixedToScalar(fAutoKern.adjust(glyph)), 0.0f
}; |
364 } | 478 } |
365 if (glyph.fWidth > 0) { | 479 if (glyph.fWidth > 0) { |
366 finalPosition -= TextAlignmentAdjustment(kTextAlignment, glyph); | 480 finalPosition -= TextAlignmentAdjustment(kTextAlignment, glyph); |
367 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarH
alf}); | 481 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarH
alf}); |
368 } | 482 } |
369 return finalPosition + SkPoint{SkFixedToScalar(glyph.fAdvanceX), | 483 return finalPosition + SkPoint{SkFixedToScalar(glyph.fAdvanceX), |
370 SkFixedToScalar(glyph.fAdvanceY)}; | 484 SkFixedToScalar(glyph.fAdvanceY)}; |
371 } | 485 } |
372 | 486 |
373 private: | 487 private: |
374 SkGlyphCache* const fCache; | 488 LookupGlyph& fGlyphFinder; |
375 SkDrawCacheProc fGlyphCacheProc; | 489 |
376 SkAutoKern fAutoKern; | 490 SkAutoKern fAutoKern; |
377 }; | 491 }; |
378 | 492 |
379 // GlyphFindAndPlace is a large variant that encapsulates the multiple types
of finding and | 493 // GlyphFindAndPlace is a large variant that encapsulates the multiple types
of finding and |
380 // placing a glyph. There are three factors that go into the different facto
rs. | 494 // placing a glyph. There are three factors that go into the different facto
rs. |
381 // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel
positioning. | 495 // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel
positioning. |
382 // * Text alignment - indicates if the glyph should be placed to the right,
centered or left | 496 // * Text alignment - indicates if the glyph should be placed to the right,
centered or left |
383 // of a given position. | 497 // of a given position. |
384 // * Axis alignment - indicates if the glyphs final sub-pixel position shoul
d be rounded to a | 498 // * Axis alignment - indicates if the glyphs final sub-pixel position shoul
d be rounded to a |
385 // whole pixel if the glyph is aligned with an axis. This is only used for
sub-pixel | 499 // whole pixel if the glyph is aligned with an axis. This is only used for
sub-pixel |
(...skipping 16 matching lines...) Expand all Loading... |
402 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNoK
erning>, | 516 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNoK
erning>, |
403 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kRight_Align, kNoK
erning> | 517 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kRight_Align, kNoK
erning> |
404 >; | 518 >; |
405 | 519 |
406 // InitSubpixel is a helper function for initializing all the variants of | 520 // InitSubpixel is a helper function for initializing all the variants of |
407 // GlyphFindAndPlaceSubpixel. | 521 // GlyphFindAndPlaceSubpixel. |
408 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment> | 522 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment> |
409 static void InitSubpixel( | 523 static void InitSubpixel( |
410 typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init, | 524 typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init, |
411 SkAxisAlignment axisAlignment, | 525 SkAxisAlignment axisAlignment, |
412 SkGlyphCache* cache, | 526 LookupGlyph& glyphFinder) { |
413 SkDrawCacheProc glyphCacheProc) { | |
414 switch (axisAlignment) { | 527 switch (axisAlignment) { |
415 case kX_SkAxisAlignment: | 528 case kX_SkAxisAlignment: |
416 to_init->template initialize<GlyphFindAndPlaceSubpixel< | 529 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
417 ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>( | 530 ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>(glyphF
inder); |
418 cache, glyphCacheProc); | |
419 break; | 531 break; |
420 case kNone_SkAxisAlignment: | 532 case kNone_SkAxisAlignment: |
421 to_init->template initialize<GlyphFindAndPlaceSubpixel< | 533 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
422 ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>( | 534 ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>(gly
phFinder); |
423 cache, glyphCacheProc); | |
424 break; | 535 break; |
425 case kY_SkAxisAlignment: | 536 case kY_SkAxisAlignment: |
426 to_init->template initialize<GlyphFindAndPlaceSubpixel< | 537 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
427 ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>( | 538 ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>(glyphF
inder); |
428 cache, glyphCacheProc); | |
429 break; | 539 break; |
430 } | 540 } |
431 } | 541 } |
432 | 542 |
433 static SkPoint MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCachePr
oc, | 543 static SkPoint MeasureText(LookupGlyph& glyphFinder, const char text[], size
_t byteLength) { |
434 const char text[], size_t byteLength) { | |
435 SkFixed x = 0, y = 0; | 544 SkFixed x = 0, y = 0; |
436 const char* stop = text + byteLength; | 545 const char* stop = text + byteLength; |
437 | 546 |
438 SkAutoKern autokern; | 547 SkAutoKern autokern; |
439 | 548 |
440 while (text < stop) { | 549 while (text < stop) { |
441 // don't need x, y here, since all subpixel variants will have the | 550 // don't need x, y here, since all subpixel variants will have the |
442 // same advance | 551 // same advance |
443 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | 552 const SkGlyph& glyph = glyphFinder->lookupGlyph(&text); |
444 | 553 |
445 x += autokern.adjust(glyph) + glyph.fAdvanceX; | 554 x += autokern.adjust(glyph) + glyph.fAdvanceX; |
446 y += glyph.fAdvanceY; | 555 y += glyph.fAdvanceY; |
447 } | 556 } |
448 SkASSERT(text == stop); | 557 SkASSERT(text == stop); |
449 return {SkFixedToScalar(x), SkFixedToScalar(y)}; | 558 return {SkFixedToScalar(x), SkFixedToScalar(y)}; |
450 } | 559 } |
451 }; | 560 }; |
452 | 561 |
453 template<typename ProcessOneGlyph> | 562 template<typename ProcessOneGlyph> |
454 inline void SkFindAndPlaceGlyph::ProcessPosText( | 563 inline void SkFindAndPlaceGlyph::ProcessPosText( |
455 const char text[], size_t byteLength, SkPoint offset, const SkMatrix& matrix
, | 564 SkPaint::TextEncoding textEncoding, const char text[], size_t byteLength, |
456 const SkScalar pos[], int scalarsPerPosition, SkPaint::Align textAlignment, | 565 SkPoint offset, const SkMatrix& matrix, const SkScalar pos[], int scalarsPer
Position, |
457 SkDrawCacheProc& glyphCacheProc, SkGlyphCache* cache, ProcessOneGlyph&& proc
essOneGlyph) { | 566 SkPaint::Align textAlignment, |
| 567 SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) { |
458 | 568 |
459 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix); | 569 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix); |
460 uint32_t mtype = matrix.getType(); | 570 uint32_t mtype = matrix.getType(); |
461 | 571 |
| 572 LookupGlyph glyphFinder(textEncoding, cache); |
| 573 |
462 // Specialized code for handling the most common case for blink. The while l
oop is totally | 574 // Specialized code for handling the most common case for blink. The while l
oop is totally |
463 // de-virtualized. | 575 // de-virtualized. |
464 if (scalarsPerPosition == 1 | 576 if (scalarsPerPosition == 1 |
465 && textAlignment == SkPaint::kLeft_Align | 577 && textAlignment == SkPaint::kLeft_Align |
466 && axisAlignment == kX_SkAxisAlignment | 578 && axisAlignment == kX_SkAxisAlignment |
467 && cache->isSubpixel() | 579 && cache->isSubpixel() |
468 && mtype <= SkMatrix::kTranslate_Mask) { | 580 && mtype <= SkMatrix::kTranslate_Mask) { |
469 typedef GlyphFindAndPlaceSubpixel< | 581 typedef GlyphFindAndPlaceSubpixel< |
470 ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positione
r; | 582 ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positione
r; |
471 HorizontalPositions positions{pos}; | 583 HorizontalPositions positions{pos}; |
472 TranslationMapper mapper{matrix, offset}; | 584 TranslationMapper mapper{matrix, offset}; |
473 Positioner positioner(cache, glyphCacheProc); | 585 Positioner positioner(glyphFinder); |
474 const char* cursor = text; | 586 const char* cursor = text; |
475 const char* stop = text + byteLength; | 587 const char* stop = text + byteLength; |
476 while (cursor < stop) { | 588 while (cursor < stop) { |
477 SkPoint mappedPoint = mapper.TranslationMapper::map( | 589 SkPoint mappedPoint = mapper.TranslationMapper::map( |
478 positions.HorizontalPositions::nextPoint()); | 590 positions.HorizontalPositions::nextPoint()); |
479 positioner.Positioner::findAndPositionGlyph( | 591 positioner.Positioner::findAndPositionGlyph( |
480 &cursor, mappedPoint, skstd::forward<ProcessOneGlyph>(processOne
Glyph)); | 592 &cursor, mappedPoint, skstd::forward<ProcessOneGlyph>(processOne
Glyph)); |
481 } | 593 } |
482 return; | 594 return; |
483 } | 595 } |
(...skipping 20 matching lines...) Expand all Loading... |
504 } | 616 } |
505 } | 617 } |
506 }; | 618 }; |
507 | 619 |
508 GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{ | 620 GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{ |
509 [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) { | 621 [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) { |
510 if (cache->isSubpixel()) { | 622 if (cache->isSubpixel()) { |
511 switch (textAlignment) { | 623 switch (textAlignment) { |
512 case SkPaint::kLeft_Align: | 624 case SkPaint::kLeft_Align: |
513 InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>( | 625 InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>( |
514 to_init, axisAlignment, cache, glyphCacheProc); | 626 to_init, axisAlignment, glyphFinder); |
515 break; | 627 break; |
516 case SkPaint::kCenter_Align: | 628 case SkPaint::kCenter_Align: |
517 InitSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align>( | 629 InitSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align>( |
518 to_init, axisAlignment, cache, glyphCacheProc); | 630 to_init, axisAlignment, glyphFinder); |
519 break; | 631 break; |
520 case SkPaint::kRight_Align: | 632 case SkPaint::kRight_Align: |
521 InitSubpixel<ProcessOneGlyph, SkPaint::kRight_Align>( | 633 InitSubpixel<ProcessOneGlyph, SkPaint::kRight_Align>( |
522 to_init, axisAlignment, cache, glyphCacheProc); | 634 to_init, axisAlignment, glyphFinder); |
523 break; | 635 break; |
524 } | 636 } |
525 } else { | 637 } else { |
526 switch (textAlignment) { | 638 switch (textAlignment) { |
527 case SkPaint::kLeft_Align: | 639 case SkPaint::kLeft_Align: |
528 to_init->template initialize< | 640 to_init->template initialize< |
529 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, | 641 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
530 SkPaint::kLeft_Align, kNoKerning>>(cache, glyphCache
Proc); | 642 SkPaint::kLeft_Align, kNoKerning>>(glyphFinder); |
531 break; | 643 break; |
532 case SkPaint::kCenter_Align: | 644 case SkPaint::kCenter_Align: |
533 to_init->template initialize< | 645 to_init->template initialize< |
534 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, | 646 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
535 SkPaint::kCenter_Align, kNoKerning>>(cache, glyphCac
heProc); | 647 SkPaint::kCenter_Align, kNoKerning>>(glyphFinder); |
536 break; | 648 break; |
537 case SkPaint::kRight_Align: | 649 case SkPaint::kRight_Align: |
538 to_init->template initialize< | 650 to_init->template initialize< |
539 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, | 651 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
540 SkPaint::kRight_Align, kNoKerning>>(cache, glyphCach
eProc); | 652 SkPaint::kRight_Align, kNoKerning>>(glyphFinder); |
541 break; | 653 break; |
542 } | 654 } |
543 } | 655 } |
544 } | 656 } |
545 }; | 657 }; |
546 | 658 |
547 const char* stop = text + byteLength; | 659 const char* stop = text + byteLength; |
548 while (text < stop) { | 660 while (text < stop) { |
549 SkPoint mappedPoint = mapper->map(positionReader->nextPoint()); | 661 SkPoint mappedPoint = mapper->map(positionReader->nextPoint()); |
550 findAndPosition->findAndPositionGlyph( | 662 findAndPosition->findAndPositionGlyph( |
551 &text, mappedPoint, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); | 663 &text, mappedPoint, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); |
552 } | 664 } |
553 } | 665 } |
554 | 666 |
555 template<typename ProcessOneGlyph> | 667 template<typename ProcessOneGlyph> |
556 inline void SkFindAndPlaceGlyph::ProcessText( | 668 inline void SkFindAndPlaceGlyph::ProcessText( |
557 const char text[], size_t byteLength, SkPoint offset, const SkMatrix& matrix
, | 669 SkPaint::TextEncoding textEncoding, const char text[], size_t byteLength, |
558 SkPaint::Align textAlignment, SkDrawCacheProc& glyphCacheProc, SkGlyphCache*
cache, | 670 SkPoint offset, const SkMatrix& matrix, SkPaint::Align textAlignment, |
559 ProcessOneGlyph&& processOneGlyph) { | 671 SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) { |
560 | 672 |
561 // transform the starting point | 673 // transform the starting point |
562 matrix.mapPoints(&offset, 1); | 674 matrix.mapPoints(&offset, 1); |
563 | 675 |
| 676 LookupGlyph glyphFinder(textEncoding, cache); |
| 677 |
564 // need to measure first | 678 // need to measure first |
565 if (textAlignment != SkPaint::kLeft_Align) { | 679 if (textAlignment != SkPaint::kLeft_Align) { |
566 SkVector stop = MeasureText(cache, glyphCacheProc, text, byteLength); | 680 SkVector stop = MeasureText(glyphFinder, text, byteLength); |
567 | 681 |
568 if (textAlignment == SkPaint::kCenter_Align) { | 682 if (textAlignment == SkPaint::kCenter_Align) { |
569 stop *= SK_ScalarHalf; | 683 stop *= SK_ScalarHalf; |
570 } | 684 } |
571 offset -= stop; | 685 offset -= stop; |
572 } | 686 } |
573 | 687 |
574 GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{ | 688 GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{ |
575 [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) { | 689 [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) { |
576 if (cache->isSubpixel()) { | 690 if (cache->isSubpixel()) { |
577 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(m
atrix); | 691 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(m
atrix); |
578 InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>( | 692 InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>( |
579 to_init, axisAlignment, cache, glyphCacheProc); | 693 to_init, axisAlignment, glyphFinder); |
580 } else { | 694 } else { |
581 to_init->template initialize< | 695 to_init->template initialize< |
582 GlyphFindAndPlaceFullPixel< | 696 GlyphFindAndPlaceFullPixel< |
583 ProcessOneGlyph, SkPaint::kLeft_Align, kUseKerning>>( | 697 ProcessOneGlyph, SkPaint::kLeft_Align, kUseKerning>>(gly
phFinder); |
584 cache, glyphCacheProc); | |
585 } | 698 } |
586 } | 699 } |
587 }; | 700 }; |
588 | 701 |
589 const char* stop = text + byteLength; | 702 const char* stop = text + byteLength; |
590 SkPoint current = offset; | 703 SkPoint current = offset; |
591 while (text < stop) { | 704 while (text < stop) { |
592 current = | 705 current = |
593 findAndPosition->findAndPositionGlyph( | 706 findAndPosition->findAndPositionGlyph( |
594 &text, current, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); | 707 &text, current, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); |
595 | 708 |
596 } | 709 } |
597 } | 710 } |
598 | 711 |
599 #endif // SkFindAndPositionGlyph_DEFINED | 712 #endif // SkFindAndPositionGlyph_DEFINED |
OLD | NEW |