| 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 |