OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2015 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #ifndef SkFindAndPositionGlyph_DEFINED |
| 9 #define SkFindAndPositionGlyph_DEFINED |
| 10 |
| 11 #include "SkGlyph.h" |
| 12 #include "SkGlyphCache.h" |
| 13 #include "SkPaint.h" |
| 14 #include "SkTemplates.h" |
| 15 |
| 16 // Calculate a type with the same size as the max of all the Ts. |
| 17 // This must be top level because the is no specialization of inner classes. |
| 18 template<typename... Ts> struct SkMaxSizeOf; |
| 19 |
| 20 template<> |
| 21 struct SkMaxSizeOf<> { |
| 22 static const size_t value = 0; |
| 23 }; |
| 24 |
| 25 template<typename H, typename... Ts> |
| 26 struct SkMaxSizeOf<H, Ts...> { |
| 27 static const size_t value = |
| 28 sizeof(H) >= SkMaxSizeOf<Ts...>::value ? sizeof(H) : SkMaxSizeOf<Ts...>:
:value; |
| 29 }; |
| 30 |
| 31 class SkFindAndPlaceGlyph { |
| 32 public: |
| 33 // ProcessPosText handles all cases for finding and positioning glyphs. It h
as a very large |
| 34 // multiplicity. It figures out the glyph, position and rounding and pass th
ose parameters to |
| 35 // processOneGlyph. |
| 36 // |
| 37 // The routine processOneGlyph passed in by the client has the following sig
nature: |
| 38 // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding); |
| 39 // |
| 40 // * Sub-pixel positioning (2) - use sub-pixel positioning. |
| 41 // * Text alignment (3) - text alignment with respect to the glyph's width. |
| 42 // * Matrix type (3) - special cases for translation and X-coordinate scalin
g. |
| 43 // * Components per position (2) - the positions vector can have a common Y
with different |
| 44 // Xs, or XY-pairs. |
| 45 // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel p
ositioning, round |
| 46 // to a whole coordinate instead of using sub-pixel positioning. |
| 47 // The number of variations is 108 for sub-pixel and 36 for full-pixel. |
| 48 // This routine handles all of them using inline polymorphic variable (no he
ap allocation). |
| 49 template<typename ProcessOneGlyph> |
| 50 static void ProcessPosText(const char text[], size_t byteLength, |
| 51 const SkPoint& offset, const SkMatrix& matrix, |
| 52 const SkScalar pos[], int scalarsPerPosition, |
| 53 SkPaint::Align textAlignment, SkDrawCacheProc& gl
yphCacheProc, |
| 54 SkGlyphCache* cache, ProcessOneGlyph&& processOne
Glyph); |
| 55 |
| 56 // SpecializedProcessPosText is a version of ProcessPosText that de-virtuali
zes the |
| 57 // different components used. It returns true if it can handle the situation
, otherwise it |
| 58 // returns false. This allows greater inlining freedom to the compiler. Curr
ently, there is |
| 59 // only one specialized variant: sub-pixel position, left-aligned, x-axis-al
igned, |
| 60 // translation, and one scalar per position entry. |
| 61 // * This is by far the most common type of text Blink draws. |
| 62 template<typename ProcessOneGlyph> |
| 63 static bool SpecializedProcessPosText(const char* const text, size_t byteLen
gth, |
| 64 const SkPoint& offset, const SkMatrix&
matrix, |
| 65 const SkScalar pos[], int scalarsPerPo
sition, |
| 66 SkPaint::Align textAlignment, |
| 67 SkDrawCacheProc& glyphCacheProc, |
| 68 SkGlyphCache* cache, |
| 69 ProcessOneGlyph&& processOneGlyph); |
| 70 |
| 71 private: |
| 72 // UntaggedVariant is a pile of memory that can hold one of the Ts. It provi
des a way |
| 73 // to initialize that memory in a typesafe way. |
| 74 template<typename... Ts> |
| 75 class UntaggedVariant { |
| 76 public: |
| 77 UntaggedVariant() { } |
| 78 |
| 79 ~UntaggedVariant() { } |
| 80 UntaggedVariant(const UntaggedVariant&) = delete; |
| 81 UntaggedVariant& operator=(const UntaggedVariant&) = delete; |
| 82 UntaggedVariant(UntaggedVariant&&) = delete; |
| 83 UntaggedVariant& operator=(UntaggedVariant&&) = delete; |
| 84 |
| 85 template<typename Variant, typename... Args> |
| 86 void initialize(Args&&... args) { |
| 87 SkASSERT(sizeof(Variant) <= sizeof(fSpace)); |
| 88 #if defined(_MSC_VER) && _MSC_VER < 1900 |
| 89 #define alignof __alignof |
| 90 #endif |
| 91 SkASSERT(alignof(Variant) <= alignof(Space)); |
| 92 new(&fSpace) Variant(skstd::forward<Args>(args)...); |
| 93 } |
| 94 |
| 95 private: |
| 96 typedef SkAlignedSStorage<SkMaxSizeOf<Ts...>::value> Space; |
| 97 Space fSpace; |
| 98 }; |
| 99 |
| 100 // PolymorphicVariant holds subclasses of Base without slicing. Ts must be s
ubclasses of Base. |
| 101 template<typename Base, typename... Ts> |
| 102 class PolymorphicVariant { |
| 103 public: |
| 104 typedef UntaggedVariant<Ts...> Variants; |
| 105 |
| 106 template<typename Initializer> |
| 107 PolymorphicVariant(Initializer&& initializer) { |
| 108 initializer(&fVariants); |
| 109 } |
| 110 ~PolymorphicVariant() { get()->~Base(); } |
| 111 Base* get() const { return reinterpret_cast<Base*>(&fVariants); } |
| 112 Base* operator->() const { return get(); } |
| 113 Base& operator*() const { return *get(); } |
| 114 |
| 115 private: |
| 116 mutable Variants fVariants; |
| 117 }; |
| 118 |
| 119 // PositionReaderInterface reads a point from the pos vector. |
| 120 // * HorizontalPositions - assumes a common Y for many X values. |
| 121 // * ArbitraryPositions - a list of (X,Y) pairs. |
| 122 class PositionReaderInterface { |
| 123 public: |
| 124 virtual ~PositionReaderInterface() { } |
| 125 virtual SkPoint nextPoint() = 0; |
| 126 }; |
| 127 |
| 128 class HorizontalPositions final : public PositionReaderInterface { |
| 129 public: |
| 130 explicit HorizontalPositions(const SkScalar* positions) |
| 131 : fPositions(positions) { } |
| 132 |
| 133 SkPoint nextPoint() override { |
| 134 SkScalar x = *fPositions++; |
| 135 return {x, 0}; |
| 136 } |
| 137 |
| 138 private: |
| 139 const SkScalar* fPositions; |
| 140 }; |
| 141 |
| 142 class ArbitraryPositions final : public PositionReaderInterface { |
| 143 public: |
| 144 explicit ArbitraryPositions(const SkScalar* positions) |
| 145 : fPositions(positions) { } |
| 146 |
| 147 SkPoint nextPoint() override { |
| 148 SkPoint to_return{fPositions[0], fPositions[1]}; |
| 149 fPositions += 2; |
| 150 return to_return; |
| 151 } |
| 152 |
| 153 private: |
| 154 const SkScalar* fPositions; |
| 155 }; |
| 156 |
| 157 typedef PolymorphicVariant<PositionReaderInterface, HorizontalPositions, Arb
itraryPositions> |
| 158 PositionReader; |
| 159 |
| 160 // MapperInterface given a point map it through the matrix. There are severa
l shortcut variants. |
| 161 // * TranslationMapper - assumes a translation only matrix. |
| 162 // * XScaleMapper - assumes an X scaling and a translation. |
| 163 // * GeneralMapper - Does all other matricies. |
| 164 class MapperInterface { |
| 165 public: |
| 166 virtual ~MapperInterface() { } |
| 167 |
| 168 virtual SkPoint map(SkPoint position) const = 0; |
| 169 }; |
| 170 |
| 171 class TranslationMapper final : public MapperInterface { |
| 172 public: |
| 173 TranslationMapper(const SkMatrix& matrix, const SkPoint origin) |
| 174 : fTranslate(matrix.mapXY(origin.fX, origin.fY)) { } |
| 175 |
| 176 SkPoint map(SkPoint position) const override { |
| 177 return position + fTranslate; |
| 178 } |
| 179 |
| 180 private: |
| 181 const SkPoint fTranslate; |
| 182 }; |
| 183 |
| 184 class XScaleMapper final : public MapperInterface { |
| 185 public: |
| 186 XScaleMapper(const SkMatrix& matrix, const SkPoint origin) |
| 187 : fTranslate(matrix.mapXY(origin.fX, origin.fY)), fXScale(matrix.get
ScaleX()) { } |
| 188 |
| 189 SkPoint map(SkPoint position) const override { |
| 190 return {fXScale * position.fX + fTranslate.fX, fTranslate.fY}; |
| 191 } |
| 192 |
| 193 private: |
| 194 const SkPoint fTranslate; |
| 195 const SkScalar fXScale; |
| 196 }; |
| 197 |
| 198 // The caller must keep matrix alive while this class is used. |
| 199 class GeneralMapper final : public MapperInterface { |
| 200 public: |
| 201 GeneralMapper(const SkMatrix& matrix, const SkPoint origin) |
| 202 : fOrigin(origin), fMatrix(matrix), fMapProc(matrix.getMapXYProc())
{ } |
| 203 |
| 204 SkPoint map(SkPoint position) const override { |
| 205 SkPoint result; |
| 206 fMapProc(fMatrix, position.fX + fOrigin.fX, position.fY + fOrigin.fY
, &result); |
| 207 return result; |
| 208 } |
| 209 |
| 210 private: |
| 211 const SkPoint fOrigin; |
| 212 const SkMatrix& fMatrix; |
| 213 const SkMatrix::MapXYProc fMapProc; |
| 214 }; |
| 215 |
| 216 typedef PolymorphicVariant< |
| 217 MapperInterface, TranslationMapper, XScaleMapper, GeneralMapper> Mapper; |
| 218 |
| 219 // Text alignment handles shifting the glyph based on its width. |
| 220 static SkPoint TextAlignmentAdjustment(SkPaint::Align textAlignment, const S
kGlyph& glyph) { |
| 221 switch (textAlignment) { |
| 222 case SkPaint::kLeft_Align: |
| 223 return {0.0f, 0.0f}; |
| 224 case SkPaint::kCenter_Align: |
| 225 return {SkFixedToScalar(glyph.fAdvanceX >> 1), |
| 226 SkFixedToScalar(glyph.fAdvanceY >> 1)}; |
| 227 case SkPaint::kRight_Align: |
| 228 return {SkFixedToScalar(glyph.fAdvanceX), |
| 229 SkFixedToScalar(glyph.fAdvanceY)}; |
| 230 } |
| 231 // Even though the entire enum is covered above, MVSC doesn't think so.
Make it happy. |
| 232 SkFAIL("Should never get here."); |
| 233 return {0.0f, 0.0f}; |
| 234 } |
| 235 |
| 236 // The "call" to SkFixedToScalar is actually a macro. It's macros all the wa
y down. |
| 237 // Needs to be a macro because you can't have a const float unless you make
it constexpr. |
| 238 #define kSubpixelRounding (SkFixedToScalar(SkGlyph::kSubpixelRound)) |
| 239 |
| 240 // Functions for handling sub-pixel aligned positions. |
| 241 // The subpixel_position_rounding function returns a point suitable for roun
ding a sub-pixel |
| 242 // positioned glyph. |
| 243 static SkPoint SubpixelPositionRounding(SkAxisAlignment axisAlignment) { |
| 244 switch (axisAlignment) { |
| 245 case kX_SkAxisAlignment: |
| 246 return {SkFixedToScalar(SkGlyph::kSubpixelRound), SK_ScalarHalf}
; |
| 247 case kY_SkAxisAlignment: |
| 248 return {SK_ScalarHalf, kSubpixelRounding}; |
| 249 case kNone_SkAxisAlignment: |
| 250 return {kSubpixelRounding, kSubpixelRounding}; |
| 251 } |
| 252 SkFAIL("Should not get here."); |
| 253 return {0.0f, 0.0f}; |
| 254 } |
| 255 |
| 256 // The subpixel_position_alignment function produces a suitable position for
the glyph cache to |
| 257 // produce the correct sub-pixel alignment. If a position is aligned with an
axis a shortcut |
| 258 // of 0 is used for the sub-pixel position. |
| 259 static SkIPoint SubpixelAlignment(SkAxisAlignment axisAlignment, SkPoint pos
ition) { |
| 260 switch (axisAlignment) { |
| 261 case kX_SkAxisAlignment: |
| 262 return {SkScalarToFixed(position.fX + kSubpixelRounding), 0}; |
| 263 case kY_SkAxisAlignment: |
| 264 return {0, SkScalarToFixed(position.fY + kSubpixelRounding)}; |
| 265 case kNone_SkAxisAlignment: |
| 266 return {SkScalarToFixed(position.fX + kSubpixelRounding), |
| 267 SkScalarToFixed(position.fY + kSubpixelRounding)}; |
| 268 } |
| 269 SkFAIL("Should not get here."); |
| 270 return {0, 0}; |
| 271 } |
| 272 |
| 273 #undef kSubpixelRounding |
| 274 |
| 275 // GlyphFindAndPlaceInterface given the text and position finds the correct
glyph and does |
| 276 // glyph specific position adjustment. The findAndPositionGlyph method takes
text and |
| 277 // position and calls processOneGlyph with the correct glyph, final position
and rounding |
| 278 // terms. The final position is not rounded yet and is the responsibility of
processOneGlyph. |
| 279 template<typename ProcessOneGlyph> |
| 280 class GlyphFindAndPlaceInterface : SkNoncopyable { |
| 281 public: |
| 282 virtual ~GlyphFindAndPlaceInterface() { }; |
| 283 |
| 284 // This should be a pure virtual, but some versions of GCC <= 4.8 have a
bug that causes a |
| 285 // compile error. |
| 286 // See GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60277 |
| 287 virtual void findAndPositionGlyph(const char** text, SkPoint position, |
| 288 ProcessOneGlyph&& processOneGlyph) { }
; |
| 289 }; |
| 290 |
| 291 // GlyphFindAndPlaceSubpixel handles finding and placing glyphs when sub-pix
el positioning is |
| 292 // requested. After it has found and placed the glyph it calls the templated
function |
| 293 // ProcessOneGlyph in order to actually perform an action. |
| 294 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SkAxisAlig
nment kAxisAlignment> |
| 295 class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface<Pr
ocessOneGlyph> { |
| 296 public: |
| 297 GlyphFindAndPlaceSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCach
eProc) |
| 298 : fCache(cache), fGlyphCacheProc(glyphCacheProc) { |
| 299 } |
| 300 |
| 301 void findAndPositionGlyph(const char** text, SkPoint position, |
| 302 ProcessOneGlyph&& processOneGlyph) override { |
| 303 SkPoint finalPosition = position; |
| 304 if (kTextAlignment != SkPaint::kLeft_Align) { |
| 305 // Get the width of an un-sub-pixel positioned glyph for calcula
ting the alignment. |
| 306 // This is not needed for kLeftAlign because its adjustment is a
lways {0, 0}. |
| 307 const char* tempText = *text; |
| 308 const SkGlyph &metricGlyph = fGlyphCacheProc(fCache, &tempText,
0, 0); |
| 309 |
| 310 if (metricGlyph.fWidth <= 0) { |
| 311 return; |
| 312 } |
| 313 |
| 314 // Adjust the final position by the alignment adjustment. |
| 315 finalPosition -= TextAlignmentAdjustment(kTextAlignment, metricG
lyph); |
| 316 } |
| 317 |
| 318 // Find the glyph. |
| 319 SkIPoint lookupPosition = SubpixelAlignment(kAxisAlignment, finalPos
ition); |
| 320 const SkGlyph& renderGlyph = fGlyphCacheProc( |
| 321 fCache, text, lookupPosition.fX, lookupPosition.fY); |
| 322 |
| 323 // If the glyph has no width (no pixels) then don't bother processin
g it. |
| 324 if (renderGlyph.fWidth > 0) { |
| 325 processOneGlyph(renderGlyph, finalPosition, |
| 326 SubpixelPositionRounding(kAxisAlignment)); |
| 327 } |
| 328 } |
| 329 |
| 330 private: |
| 331 SkGlyphCache* const fCache; |
| 332 SkDrawCacheProc fGlyphCacheProc; |
| 333 }; |
| 334 |
| 335 // GlyphFindAndPlaceFullPixel handles finding and placing glyphs when no sub
-pixel |
| 336 // positioning is requested. |
| 337 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment> |
| 338 class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<P
rocessOneGlyph> { |
| 339 public: |
| 340 GlyphFindAndPlaceFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCac
heProc) |
| 341 : fCache(cache), fGlyphCacheProc(glyphCacheProc) { } |
| 342 |
| 343 void findAndPositionGlyph(const char** text, SkPoint position, |
| 344 ProcessOneGlyph&& processOneGlyph) override { |
| 345 SkPoint finalPosition = position; |
| 346 const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0); |
| 347 if (glyph.fWidth <= 0) { |
| 348 return; |
| 349 } |
| 350 finalPosition -= TextAlignmentAdjustment(kTextAlignment, glyph); |
| 351 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf}
); |
| 352 } |
| 353 |
| 354 private: |
| 355 SkGlyphCache* const fCache; |
| 356 SkDrawCacheProc fGlyphCacheProc; |
| 357 }; |
| 358 |
| 359 // GlyphFindAndPlace is a large variant that encapsulates the multiple types
of finding and |
| 360 // placing a glyph. There are three factors that go into the different facto
rs. |
| 361 // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel
positioning. |
| 362 // * Text alignment - indicates if the glyph should be placed to the right,
centered or left |
| 363 // of a given position. |
| 364 // * Axis alignment - indicates if the glyphs final sub-pixel position shoul
d be rounded to a |
| 365 // whole pixel if the glyph is aligned with an axis. This is only used for
sub-pixel |
| 366 // positioning and allows the baseline to look crisp. |
| 367 template<typename ProcessOneGlyph> |
| 368 using GlyphFindAndPlace = PolymorphicVariant< |
| 369 GlyphFindAndPlaceInterface<ProcessOneGlyph>, |
| 370 // Subpixel |
| 371 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kNon
e_SkAxisAlignment>, |
| 372 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kX_S
kAxisAlignment >, |
| 373 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kY_S
kAxisAlignment >, |
| 374 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNon
e_SkAxisAlignment>, |
| 375 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kX_S
kAxisAlignment >, |
| 376 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kY_S
kAxisAlignment >, |
| 377 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kNon
e_SkAxisAlignment>, |
| 378 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kX_S
kAxisAlignment >, |
| 379 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kY_S
kAxisAlignment >, |
| 380 // Full pixel |
| 381 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align >, |
| 382 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align>, |
| 383 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kRight_Align > |
| 384 >; |
| 385 |
| 386 // InitSubpixel is a helper function for initializing all the variants of |
| 387 // GlyphFindAndPlaceSubpixel. |
| 388 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment> |
| 389 static void InitSubpixel( |
| 390 typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init, |
| 391 SkAxisAlignment axisAlignment, |
| 392 SkGlyphCache* cache, |
| 393 SkDrawCacheProc glyphCacheProc) { |
| 394 switch (axisAlignment) { |
| 395 case kX_SkAxisAlignment: |
| 396 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
| 397 ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>( |
| 398 cache, glyphCacheProc); |
| 399 break; |
| 400 case kNone_SkAxisAlignment: |
| 401 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
| 402 ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>( |
| 403 cache, glyphCacheProc); |
| 404 break; |
| 405 case kY_SkAxisAlignment: |
| 406 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
| 407 ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>( |
| 408 cache, glyphCacheProc); |
| 409 break; |
| 410 } |
| 411 } |
| 412 }; |
| 413 |
| 414 template<typename ProcessOneGlyph> |
| 415 inline void SkFindAndPlaceGlyph::ProcessPosText( |
| 416 const char text[], size_t byteLength, const SkPoint& offset, const SkMatrix&
matrix, |
| 417 const SkScalar pos[], int scalarsPerPosition, SkPaint::Align textAlignment, |
| 418 SkDrawCacheProc& glyphCacheProc, SkGlyphCache* cache, ProcessOneGlyph&& proc
essOneGlyph) { |
| 419 |
| 420 PositionReader positionReader{ |
| 421 [&](PositionReader::Variants* to_init) { |
| 422 if (2 == scalarsPerPosition) { |
| 423 to_init->initialize<ArbitraryPositions>(pos); |
| 424 } else { |
| 425 to_init->initialize<HorizontalPositions>(pos); |
| 426 } |
| 427 } |
| 428 }; |
| 429 |
| 430 Mapper mapper{ |
| 431 [&](Mapper::Variants* to_init) { |
| 432 uint32_t mtype = matrix.getType(); |
| 433 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask) |
| 434 || scalarsPerPosition == 2) { |
| 435 to_init->initialize<GeneralMapper>(matrix, offset); |
| 436 } else if (mtype & SkMatrix::kScale_Mask) { |
| 437 to_init->initialize<XScaleMapper>(matrix, offset); |
| 438 } else { |
| 439 to_init->initialize<TranslationMapper>(matrix, offset); |
| 440 } |
| 441 } |
| 442 }; |
| 443 |
| 444 GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{ |
| 445 [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) { |
| 446 if (cache->isSubpixel()) { |
| 447 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(m
atrix); |
| 448 switch (textAlignment) { |
| 449 case SkPaint::kLeft_Align: |
| 450 InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>( |
| 451 to_init, axisAlignment, cache, glyphCacheProc); |
| 452 break; |
| 453 case SkPaint::kCenter_Align: |
| 454 InitSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align>( |
| 455 to_init, axisAlignment, cache, glyphCacheProc); |
| 456 break; |
| 457 case SkPaint::kRight_Align: |
| 458 InitSubpixel<ProcessOneGlyph, SkPaint::kRight_Align>( |
| 459 to_init, axisAlignment, cache, glyphCacheProc); |
| 460 break; |
| 461 } |
| 462 } else { |
| 463 switch (textAlignment) { |
| 464 case SkPaint::kLeft_Align: |
| 465 to_init->template initialize< |
| 466 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
| 467 SkPaint::kLeft_Align>>(cache, glyphCacheProc); |
| 468 break; |
| 469 case SkPaint::kCenter_Align: |
| 470 to_init->template initialize< |
| 471 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
| 472 SkPaint::kCenter_Align>>(cache, glyphCacheProc); |
| 473 break; |
| 474 case SkPaint::kRight_Align: |
| 475 to_init->template initialize< |
| 476 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
| 477 SkPaint::kRight_Align>>(cache, glyphCacheProc); |
| 478 break; |
| 479 } |
| 480 } |
| 481 } |
| 482 }; |
| 483 |
| 484 const char* stop = text + byteLength; |
| 485 while (text < stop) { |
| 486 SkPoint mappedPoint = mapper->map(positionReader->nextPoint()); |
| 487 findAndPosition->findAndPositionGlyph( |
| 488 &text, mappedPoint, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); |
| 489 } |
| 490 } |
| 491 |
| 492 template<typename ProcessOneGlyph> |
| 493 inline bool SkFindAndPlaceGlyph::SpecializedProcessPosText( |
| 494 const char* const text, size_t byteLength, const SkPoint& offset, const SkMa
trix& matrix, |
| 495 const SkScalar pos[], int scalarsPerPosition, SkPaint::Align textAlignment, |
| 496 SkDrawCacheProc& glyphCacheProc, SkGlyphCache* cache, ProcessOneGlyph&& proc
essOneGlyph) { |
| 497 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix); |
| 498 uint32_t mtype = matrix.getType(); |
| 499 if (scalarsPerPosition == 1 |
| 500 && textAlignment == SkPaint::kLeft_Align |
| 501 && axisAlignment == kX_SkAxisAlignment |
| 502 && cache->isSubpixel() |
| 503 && mtype <= SkMatrix::kTranslate_Mask) { |
| 504 typedef GlyphFindAndPlaceSubpixel< |
| 505 ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positioner; |
| 506 HorizontalPositions positions{pos}; |
| 507 TranslationMapper mapper{matrix, offset}; |
| 508 Positioner positioner(cache, glyphCacheProc); |
| 509 const char* cursor = text; |
| 510 const char* stop = text + byteLength; |
| 511 while (cursor < stop) { |
| 512 SkPoint mappedPoint = mapper.TranslationMapper::map( |
| 513 positions.HorizontalPositions::nextPoint()); |
| 514 positioner.Positioner::findAndPositionGlyph( |
| 515 &cursor, mappedPoint, skstd::forward<ProcessOneGlyph>(processOne
Glyph)); |
| 516 } |
| 517 return true; |
| 518 } |
| 519 return false; |
| 520 } |
| 521 |
| 522 |
| 523 #endif // SkFindAndPositionGlyph_DEFINED |
OLD | NEW |