| 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 "SkGlyph.h" | 12 #include "SkGlyph.h" |
| 12 #include "SkGlyphCache.h" | 13 #include "SkGlyphCache.h" |
| 13 #include "SkPaint.h" | 14 #include "SkPaint.h" |
| 14 #include "SkTemplates.h" | 15 #include "SkTemplates.h" |
| 15 | 16 |
| 16 // Calculate a type with the same size as the max of all the Ts. | 17 // 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 // This must be top level because the is no specialization of inner classes. |
| 18 template<typename... Ts> struct SkMaxSizeOf; | 19 template<typename... Ts> struct SkMaxSizeOf; |
| 19 | 20 |
| 20 template<> | 21 template<> |
| 21 struct SkMaxSizeOf<> { | 22 struct SkMaxSizeOf<> { |
| 22 static const size_t value = 0; | 23 static const size_t value = 0; |
| 23 }; | 24 }; |
| 24 | 25 |
| 25 template<typename H, typename... Ts> | 26 template<typename H, typename... Ts> |
| 26 struct SkMaxSizeOf<H, Ts...> { | 27 struct SkMaxSizeOf<H, Ts...> { |
| 27 static const size_t value = | 28 static const size_t value = |
| 28 sizeof(H) >= SkMaxSizeOf<Ts...>::value ? sizeof(H) : SkMaxSizeOf<Ts...>:
:value; | 29 sizeof(H) >= SkMaxSizeOf<Ts...>::value ? sizeof(H) : SkMaxSizeOf<Ts...>:
:value; |
| 29 }; | 30 }; |
| 30 | 31 |
| 31 class SkFindAndPlaceGlyph { | 32 class SkFindAndPlaceGlyph { |
| 32 public: | 33 public: |
| 34 template<typename ProcessOneGlyph> |
| 35 static void ProcessText(const char text[], size_t byteLength, SkPoint offset
, const |
| 36 SkMatrix& matrix, SkPaint::Align textAlignment, SkDrawCacheProc& glyphCacheP
roc, |
| 37 SkGlyphCache* cache, ProcessOneGlyph&& processOneGly
ph); |
| 33 // ProcessPosText handles all cases for finding and positioning glyphs. It h
as a very large | 38 // 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 | 39 // multiplicity. It figures out the glyph, position and rounding and pass th
ose parameters to |
| 35 // processOneGlyph. | 40 // processOneGlyph. |
| 36 // | 41 // |
| 37 // The routine processOneGlyph passed in by the client has the following sig
nature: | 42 // The routine processOneGlyph passed in by the client has the following sig
nature: |
| 38 // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding); | 43 // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding); |
| 39 // | 44 // |
| 40 // * Sub-pixel positioning (2) - use sub-pixel positioning. | 45 // * Sub-pixel positioning (2) - use sub-pixel positioning. |
| 41 // * Text alignment (3) - text alignment with respect to the glyph's width. | 46 // * 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. | 47 // * 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 | 48 // * Components per position (2) - the positions vector can have a common Y
with different |
| 44 // Xs, or XY-pairs. | 49 // Xs, or XY-pairs. |
| 45 // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel p
ositioning, round | 50 // * 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. | 51 // 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. | 52 // 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). | 53 // This routine handles all of them using inline polymorphic variable (no he
ap allocation). |
| 49 template<typename ProcessOneGlyph> | 54 template<typename ProcessOneGlyph> |
| 50 static void ProcessPosText(const char text[], size_t byteLength, | 55 static void ProcessPosText(const char text[], size_t byteLength, |
| 51 const SkPoint& offset, const SkMatrix& matrix, | 56 SkPoint offset, const SkMatrix& matrix, |
| 52 const SkScalar pos[], int scalarsPerPosition, | 57 const SkScalar pos[], int scalarsPerPosition, |
| 53 SkPaint::Align textAlignment, SkDrawCacheProc& gl
yphCacheProc, | 58 SkPaint::Align textAlignment, SkDrawCacheProc& gl
yphCacheProc, |
| 54 SkGlyphCache* cache, ProcessOneGlyph&& processOne
Glyph); | 59 SkGlyphCache* cache, ProcessOneGlyph&& processOne
Glyph); |
| 55 | 60 |
| 56 private: | 61 private: |
| 57 // UntaggedVariant is a pile of memory that can hold one of the Ts. It provi
des a way | 62 // UntaggedVariant is a pile of memory that can hold one of the Ts. It provi
des a way |
| 58 // to initialize that memory in a typesafe way. | 63 // to initialize that memory in a typesafe way. |
| 59 template<typename... Ts> | 64 template<typename... Ts> |
| 60 class UntaggedVariant { | 65 class UntaggedVariant { |
| 61 public: | 66 public: |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 return to_return; | 140 return to_return; |
| 136 } | 141 } |
| 137 | 142 |
| 138 private: | 143 private: |
| 139 const SkScalar* fPositions; | 144 const SkScalar* fPositions; |
| 140 }; | 145 }; |
| 141 | 146 |
| 142 typedef PolymorphicVariant<PositionReaderInterface, HorizontalPositions, Arb
itraryPositions> | 147 typedef PolymorphicVariant<PositionReaderInterface, HorizontalPositions, Arb
itraryPositions> |
| 143 PositionReader; | 148 PositionReader; |
| 144 | 149 |
| 145 // MapperInterface given a point map it through the matrix. There are severa
l shortcut variants. | 150 // MapperInterface given a point map it through the matrix. There are severa
l shortcut |
| 151 // variants. |
| 146 // * TranslationMapper - assumes a translation only matrix. | 152 // * TranslationMapper - assumes a translation only matrix. |
| 147 // * XScaleMapper - assumes an X scaling and a translation. | 153 // * XScaleMapper - assumes an X scaling and a translation. |
| 148 // * GeneralMapper - Does all other matricies. | 154 // * GeneralMapper - Does all other matricies. |
| 149 class MapperInterface { | 155 class MapperInterface { |
| 150 public: | 156 public: |
| 151 virtual ~MapperInterface() { } | 157 virtual ~MapperInterface() { } |
| 152 | 158 |
| 153 virtual SkPoint map(SkPoint position) const = 0; | 159 virtual SkPoint map(SkPoint position) const = 0; |
| 154 }; | 160 }; |
| 155 | 161 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 | 200 |
| 195 private: | 201 private: |
| 196 const SkPoint fOrigin; | 202 const SkPoint fOrigin; |
| 197 const SkMatrix& fMatrix; | 203 const SkMatrix& fMatrix; |
| 198 const SkMatrix::MapXYProc fMapProc; | 204 const SkMatrix::MapXYProc fMapProc; |
| 199 }; | 205 }; |
| 200 | 206 |
| 201 typedef PolymorphicVariant< | 207 typedef PolymorphicVariant< |
| 202 MapperInterface, TranslationMapper, XScaleMapper, GeneralMapper> Mapper; | 208 MapperInterface, TranslationMapper, XScaleMapper, GeneralMapper> Mapper; |
| 203 | 209 |
| 204 // Text alignment handles shifting the glyph based on its width. | 210 // TextAlignmentAdjustment handles shifting the glyph based on its width. |
| 205 static SkPoint TextAlignmentAdjustment(SkPaint::Align textAlignment, const S
kGlyph& glyph) { | 211 static SkPoint TextAlignmentAdjustment(SkPaint::Align textAlignment, const S
kGlyph& glyph) { |
| 206 switch (textAlignment) { | 212 switch (textAlignment) { |
| 207 case SkPaint::kLeft_Align: | 213 case SkPaint::kLeft_Align: |
| 208 return {0.0f, 0.0f}; | 214 return {0.0f, 0.0f}; |
| 209 case SkPaint::kCenter_Align: | 215 case SkPaint::kCenter_Align: |
| 210 return {SkFixedToScalar(glyph.fAdvanceX >> 1), | 216 return {SkFixedToScalar(glyph.fAdvanceX >> 1), |
| 211 SkFixedToScalar(glyph.fAdvanceY >> 1)}; | 217 SkFixedToScalar(glyph.fAdvanceY >> 1)}; |
| 212 case SkPaint::kRight_Align: | 218 case SkPaint::kRight_Align: |
| 213 return {SkFixedToScalar(glyph.fAdvanceX), | 219 return {SkFixedToScalar(glyph.fAdvanceX), |
| 214 SkFixedToScalar(glyph.fAdvanceY)}; | 220 SkFixedToScalar(glyph.fAdvanceY)}; |
| 215 } | 221 } |
| 216 // Even though the entire enum is covered above, MVSC doesn't think so.
Make it happy. | 222 // Even though the entire enum is covered above, MVSC doesn't think so.
Make it happy. |
| 217 SkFAIL("Should never get here."); | 223 SkFAIL("Should never get here."); |
| 218 return {0.0f, 0.0f}; | 224 return {0.0f, 0.0f}; |
| 219 } | 225 } |
| 220 | 226 |
| 221 // The "call" to SkFixedToScalar is actually a macro. It's macros all the wa
y down. | 227 // The "call" to SkFixedToScalar is actually a macro. It's macros all the wa
y down. |
| 222 // Needs to be a macro because you can't have a const float unless you make
it constexpr. | 228 // Needs to be a macro because you can't have a const float unless you make
it constexpr. |
| 223 #define kSubpixelRounding (SkFixedToScalar(SkGlyph::kSubpixelRound)) | 229 #define kSubpixelRounding (SkFixedToScalar(SkGlyph::kSubpixelRound)) |
| 224 | 230 |
| 225 // Functions for handling sub-pixel aligned positions. | 231 // The SubpixelPositionRounding function returns a point suitable for roundi
ng a sub-pixel |
| 226 // The subpixel_position_rounding function returns a point suitable for roun
ding a sub-pixel | |
| 227 // positioned glyph. | 232 // positioned glyph. |
| 228 static SkPoint SubpixelPositionRounding(SkAxisAlignment axisAlignment) { | 233 static SkPoint SubpixelPositionRounding(SkAxisAlignment axisAlignment) { |
| 229 switch (axisAlignment) { | 234 switch (axisAlignment) { |
| 230 case kX_SkAxisAlignment: | 235 case kX_SkAxisAlignment: |
| 231 return {SkFixedToScalar(SkGlyph::kSubpixelRound), SK_ScalarHalf}
; | 236 return {SkFixedToScalar(SkGlyph::kSubpixelRound), SK_ScalarHalf}
; |
| 232 case kY_SkAxisAlignment: | 237 case kY_SkAxisAlignment: |
| 233 return {SK_ScalarHalf, kSubpixelRounding}; | 238 return {SK_ScalarHalf, kSubpixelRounding}; |
| 234 case kNone_SkAxisAlignment: | 239 case kNone_SkAxisAlignment: |
| 235 return {kSubpixelRounding, kSubpixelRounding}; | 240 return {kSubpixelRounding, kSubpixelRounding}; |
| 236 } | 241 } |
| 237 SkFAIL("Should not get here."); | 242 SkFAIL("Should not get here."); |
| 238 return {0.0f, 0.0f}; | 243 return {0.0f, 0.0f}; |
| 239 } | 244 } |
| 240 | 245 |
| 241 // The subpixel_position_alignment function produces a suitable position for
the glyph cache to | 246 // The SubpixelAlignment function produces a suitable position for the glyph
cache to |
| 242 // produce the correct sub-pixel alignment. If a position is aligned with an
axis a shortcut | 247 // produce the correct sub-pixel alignment. If a position is aligned with an
axis a shortcut |
| 243 // of 0 is used for the sub-pixel position. | 248 // of 0 is used for the sub-pixel position. |
| 244 static SkIPoint SubpixelAlignment(SkAxisAlignment axisAlignment, SkPoint pos
ition) { | 249 static SkIPoint SubpixelAlignment(SkAxisAlignment axisAlignment, SkPoint pos
ition) { |
| 245 switch (axisAlignment) { | 250 switch (axisAlignment) { |
| 246 case kX_SkAxisAlignment: | 251 case kX_SkAxisAlignment: |
| 247 return {SkScalarToFixed(position.fX + kSubpixelRounding), 0}; | 252 return {SkScalarToFixed(position.fX + kSubpixelRounding), 0}; |
| 248 case kY_SkAxisAlignment: | 253 case kY_SkAxisAlignment: |
| 249 return {0, SkScalarToFixed(position.fY + kSubpixelRounding)}; | 254 return {0, SkScalarToFixed(position.fY + kSubpixelRounding)}; |
| 250 case kNone_SkAxisAlignment: | 255 case kNone_SkAxisAlignment: |
| 251 return {SkScalarToFixed(position.fX + kSubpixelRounding), | 256 return {SkScalarToFixed(position.fX + kSubpixelRounding), |
| 252 SkScalarToFixed(position.fY + kSubpixelRounding)}; | 257 SkScalarToFixed(position.fY + kSubpixelRounding)}; |
| 253 } | 258 } |
| 254 SkFAIL("Should not get here."); | 259 SkFAIL("Should not get here."); |
| 255 return {0, 0}; | 260 return {0, 0}; |
| 256 } | 261 } |
| 257 | 262 |
| 258 #undef kSubpixelRounding | 263 #undef kSubpixelRounding |
| 259 | 264 |
| 260 // GlyphFindAndPlaceInterface given the text and position finds the correct
glyph and does | 265 // GlyphFindAndPlaceInterface given the text and position finds the correct
glyph and does |
| 261 // glyph specific position adjustment. The findAndPositionGlyph method takes
text and | 266 // glyph specific position adjustment. The findAndPositionGlyph method takes
text and |
| 262 // position and calls processOneGlyph with the correct glyph, final position
and rounding | 267 // position and calls processOneGlyph with the correct glyph, final position
and rounding |
| 263 // terms. The final position is not rounded yet and is the responsibility of
processOneGlyph. | 268 // terms. The final position is not rounded yet and is the responsibility of
processOneGlyph. |
| 264 template<typename ProcessOneGlyph> | 269 template<typename ProcessOneGlyph> |
| 265 class GlyphFindAndPlaceInterface : SkNoncopyable { | 270 class GlyphFindAndPlaceInterface : SkNoncopyable { |
| 266 public: | 271 public: |
| 267 virtual ~GlyphFindAndPlaceInterface() { }; | 272 virtual ~GlyphFindAndPlaceInterface() { }; |
| 268 | 273 |
| 274 // findAndPositionGlyph calculates the position of the glyph, finds the
glyph, and |
| 275 // returns the position of where the next glyph will be using the glyph'
s advance and |
| 276 // possibly kerning. The returned position is used by drawText, but igno
red by drawPosText. |
| 277 // The compiler should prune all this calculation if the return value is
not used. |
| 278 // |
| 269 // This should be a pure virtual, but some versions of GCC <= 4.8 have a
bug that causes a | 279 // This should be a pure virtual, but some versions of GCC <= 4.8 have a
bug that causes a |
| 270 // compile error. | 280 // compile error. |
| 271 // See GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60277 | 281 // See GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60277 |
| 272 virtual void findAndPositionGlyph(const char** text, SkPoint position, | 282 virtual SkPoint findAndPositionGlyph( |
| 273 ProcessOneGlyph&& processOneGlyph) { }
; | 283 const char** text, SkPoint position, ProcessOneGlyph&& processOneGly
ph) { |
| 284 SkFAIL("Should never get here."); |
| 285 return {0.0f, 0.0f}; |
| 286 }; |
| 274 }; | 287 }; |
| 275 | 288 |
| 276 // GlyphFindAndPlaceSubpixel handles finding and placing glyphs when sub-pix
el positioning is | 289 // GlyphFindAndPlaceSubpixel handles finding and placing glyphs when sub-pix
el positioning is |
| 277 // requested. After it has found and placed the glyph it calls the templated
function | 290 // requested. After it has found and placed the glyph it calls the templated
function |
| 278 // ProcessOneGlyph in order to actually perform an action. | 291 // ProcessOneGlyph in order to actually perform an action. |
| 279 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SkAxisAlig
nment kAxisAlignment> | 292 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, |
| 293 SkAxisAlignment kAxisAlignment> |
| 280 class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface<Pr
ocessOneGlyph> { | 294 class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface<Pr
ocessOneGlyph> { |
| 281 public: | 295 public: |
| 282 GlyphFindAndPlaceSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCach
eProc) | 296 GlyphFindAndPlaceSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCach
eProc) |
| 283 : fCache(cache), fGlyphCacheProc(glyphCacheProc) { | 297 : fCache(cache) |
| 284 } | 298 , fGlyphCacheProc(glyphCacheProc) { } |
| 285 | 299 |
| 286 void findAndPositionGlyph(const char** text, SkPoint position, | 300 SkPoint findAndPositionGlyph( |
| 287 ProcessOneGlyph&& processOneGlyph) override { | 301 const char** text, SkPoint position, ProcessOneGlyph&& processOneGly
ph) override { |
| 288 SkPoint finalPosition = position; | 302 SkPoint finalPosition = position; |
| 289 if (kTextAlignment != SkPaint::kLeft_Align) { | 303 if (kTextAlignment != SkPaint::kLeft_Align) { |
| 290 // Get the width of an un-sub-pixel positioned glyph for calcula
ting the alignment. | 304 // Get the width of an un-sub-pixel positioned glyph for calcula
ting the |
| 291 // This is not needed for kLeftAlign because its adjustment is a
lways {0, 0}. | 305 // alignment. This is not needed for kLeftAlign because its adju
stment is |
| 306 // always {0, 0}. |
| 292 const char* tempText = *text; | 307 const char* tempText = *text; |
| 293 const SkGlyph &metricGlyph = fGlyphCacheProc(fCache, &tempText,
0, 0); | 308 const SkGlyph &metricGlyph = fGlyphCacheProc(fCache, &tempText,
0, 0); |
| 294 | 309 |
| 295 if (metricGlyph.fWidth <= 0) { | 310 if (metricGlyph.fWidth <= 0) { |
| 296 // Exiting early, be sure to update text pointer. | 311 // Exiting early, be sure to update text pointer. |
| 297 *text = tempText; | 312 *text = tempText; |
| 298 return; | 313 return finalPosition + SkPoint{SkFixedToScalar(metricGlyph.f
AdvanceX), |
| 314 SkFixedToScalar(metricGlyph.f
AdvanceY)}; |
| 299 } | 315 } |
| 300 | 316 |
| 301 // Adjust the final position by the alignment adjustment. | 317 // Adjust the final position by the alignment adjustment. |
| 302 finalPosition -= TextAlignmentAdjustment(kTextAlignment, metricG
lyph); | 318 finalPosition -= TextAlignmentAdjustment(kTextAlignment, metricG
lyph); |
| 303 } | 319 } |
| 304 | 320 |
| 305 // Find the glyph. | 321 // Find the glyph. |
| 306 SkIPoint lookupPosition = SubpixelAlignment(kAxisAlignment, finalPos
ition); | 322 SkIPoint lookupPosition = SubpixelAlignment(kAxisAlignment, finalPos
ition); |
| 307 const SkGlyph& renderGlyph = fGlyphCacheProc( | 323 const SkGlyph& renderGlyph = |
| 308 fCache, text, lookupPosition.fX, lookupPosition.fY); | 324 fGlyphCacheProc(fCache, text, lookupPosition.fX, lookupPosition.
fY); |
| 309 | 325 |
| 310 // If the glyph has no width (no pixels) then don't bother processin
g it. | 326 // If the glyph has no width (no pixels) then don't bother processin
g it. |
| 311 if (renderGlyph.fWidth > 0) { | 327 if (renderGlyph.fWidth > 0) { |
| 312 processOneGlyph(renderGlyph, finalPosition, | 328 processOneGlyph(renderGlyph, finalPosition, |
| 313 SubpixelPositionRounding(kAxisAlignment)); | 329 SubpixelPositionRounding(kAxisAlignment)); |
| 314 } | 330 } |
| 331 return finalPosition + SkPoint{SkFixedToScalar(renderGlyph.fAdvanceX
), |
| 332 SkFixedToScalar(renderGlyph.fAdvanceY
)}; |
| 315 } | 333 } |
| 316 | 334 |
| 317 private: | 335 private: |
| 318 SkGlyphCache* const fCache; | 336 SkGlyphCache* const fCache; |
| 319 SkDrawCacheProc fGlyphCacheProc; | 337 SkDrawCacheProc fGlyphCacheProc; |
| 320 }; | 338 }; |
| 321 | 339 |
| 340 enum SelectKerning { |
| 341 kNoKerning = false, |
| 342 kUseKerning = true |
| 343 }; |
| 344 |
| 322 // GlyphFindAndPlaceFullPixel handles finding and placing glyphs when no sub
-pixel | 345 // GlyphFindAndPlaceFullPixel handles finding and placing glyphs when no sub
-pixel |
| 323 // positioning is requested. | 346 // positioning is requested. The kUseKerning argument should be true for dra
wText, and false |
| 324 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment> | 347 // for drawPosText. |
| 348 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SelectKern
ing kUseKerning> |
| 325 class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<P
rocessOneGlyph> { | 349 class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<P
rocessOneGlyph> { |
| 326 public: | 350 public: |
| 327 GlyphFindAndPlaceFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCac
heProc) | 351 GlyphFindAndPlaceFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCac
heProc) |
| 328 : fCache(cache), fGlyphCacheProc(glyphCacheProc) { } | 352 : fCache(cache), fGlyphCacheProc(glyphCacheProc) { |
| 353 // Kerning can only be used with SkPaint::kLeft_Align |
| 354 static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment
, |
| 355 "Kerning can only be used with left aligned text."); |
| 356 } |
| 329 | 357 |
| 330 void findAndPositionGlyph(const char** text, SkPoint position, | 358 SkPoint findAndPositionGlyph( |
| 331 ProcessOneGlyph&& processOneGlyph) override { | 359 const char** text, SkPoint position, ProcessOneGlyph&& processOneGly
ph) override { |
| 332 SkPoint finalPosition = position; | 360 SkPoint finalPosition = position; |
| 333 const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0); | 361 const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0); |
| 334 if (glyph.fWidth <= 0) { | 362 if (kUseKerning) { |
| 335 return; | 363 finalPosition += {SkFixedToScalar(fAutoKern.adjust(glyph)), 0.0f
}; |
| 336 } | 364 } |
| 337 finalPosition -= TextAlignmentAdjustment(kTextAlignment, glyph); | 365 if (glyph.fWidth > 0) { |
| 338 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf}
); | 366 finalPosition -= TextAlignmentAdjustment(kTextAlignment, glyph); |
| 367 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarH
alf}); |
| 368 } |
| 369 return finalPosition + SkPoint{SkFixedToScalar(glyph.fAdvanceX), |
| 370 SkFixedToScalar(glyph.fAdvanceY)}; |
| 339 } | 371 } |
| 340 | 372 |
| 341 private: | 373 private: |
| 342 SkGlyphCache* const fCache; | 374 SkGlyphCache* const fCache; |
| 343 SkDrawCacheProc fGlyphCacheProc; | 375 SkDrawCacheProc fGlyphCacheProc; |
| 376 SkAutoKern fAutoKern; |
| 344 }; | 377 }; |
| 345 | 378 |
| 346 // GlyphFindAndPlace is a large variant that encapsulates the multiple types
of finding and | 379 // GlyphFindAndPlace is a large variant that encapsulates the multiple types
of finding and |
| 347 // placing a glyph. There are three factors that go into the different facto
rs. | 380 // placing a glyph. There are three factors that go into the different facto
rs. |
| 348 // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel
positioning. | 381 // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel
positioning. |
| 349 // * Text alignment - indicates if the glyph should be placed to the right,
centered or left | 382 // * Text alignment - indicates if the glyph should be placed to the right,
centered or left |
| 350 // of a given position. | 383 // of a given position. |
| 351 // * Axis alignment - indicates if the glyphs final sub-pixel position shoul
d be rounded to a | 384 // * Axis alignment - indicates if the glyphs final sub-pixel position shoul
d be rounded to a |
| 352 // whole pixel if the glyph is aligned with an axis. This is only used for
sub-pixel | 385 // whole pixel if the glyph is aligned with an axis. This is only used for
sub-pixel |
| 353 // positioning and allows the baseline to look crisp. | 386 // positioning and allows the baseline to look crisp. |
| 354 template<typename ProcessOneGlyph> | 387 template<typename ProcessOneGlyph> |
| 355 using GlyphFindAndPlace = PolymorphicVariant< | 388 using GlyphFindAndPlace = PolymorphicVariant< |
| 356 GlyphFindAndPlaceInterface<ProcessOneGlyph>, | 389 GlyphFindAndPlaceInterface<ProcessOneGlyph>, |
| 357 // Subpixel | 390 // Subpixel |
| 358 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kNon
e_SkAxisAlignment>, | 391 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kNon
e_SkAxisAlignment>, |
| 359 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kX_S
kAxisAlignment >, | 392 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kX_S
kAxisAlignment >, |
| 360 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kY_S
kAxisAlignment >, | 393 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kY_S
kAxisAlignment >, |
| 361 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNon
e_SkAxisAlignment>, | 394 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNon
e_SkAxisAlignment>, |
| 362 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kX_S
kAxisAlignment >, | 395 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kX_S
kAxisAlignment >, |
| 363 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kY_S
kAxisAlignment >, | 396 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kY_S
kAxisAlignment >, |
| 364 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kNon
e_SkAxisAlignment>, | 397 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kNon
e_SkAxisAlignment>, |
| 365 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kX_S
kAxisAlignment >, | 398 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kX_S
kAxisAlignment >, |
| 366 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kY_S
kAxisAlignment >, | 399 GlyphFindAndPlaceSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kY_S
kAxisAlignment >, |
| 367 // Full pixel | 400 // Full pixel |
| 368 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align >, | 401 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align, kNoK
erning>, |
| 369 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align>, | 402 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNoK
erning>, |
| 370 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kRight_Align > | 403 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kRight_Align, kNoK
erning> |
| 371 >; | 404 >; |
| 372 | 405 |
| 373 // InitSubpixel is a helper function for initializing all the variants of | 406 // InitSubpixel is a helper function for initializing all the variants of |
| 374 // GlyphFindAndPlaceSubpixel. | 407 // GlyphFindAndPlaceSubpixel. |
| 375 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment> | 408 template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment> |
| 376 static void InitSubpixel( | 409 static void InitSubpixel( |
| 377 typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init, | 410 typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init, |
| 378 SkAxisAlignment axisAlignment, | 411 SkAxisAlignment axisAlignment, |
| 379 SkGlyphCache* cache, | 412 SkGlyphCache* cache, |
| 380 SkDrawCacheProc glyphCacheProc) { | 413 SkDrawCacheProc glyphCacheProc) { |
| 381 switch (axisAlignment) { | 414 switch (axisAlignment) { |
| 382 case kX_SkAxisAlignment: | 415 case kX_SkAxisAlignment: |
| 383 to_init->template initialize<GlyphFindAndPlaceSubpixel< | 416 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
| 384 ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>( | 417 ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>( |
| 385 cache, glyphCacheProc); | 418 cache, glyphCacheProc); |
| 386 break; | 419 break; |
| 387 case kNone_SkAxisAlignment: | 420 case kNone_SkAxisAlignment: |
| 388 to_init->template initialize<GlyphFindAndPlaceSubpixel< | 421 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
| 389 ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>( | 422 ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>( |
| 390 cache, glyphCacheProc); | 423 cache, glyphCacheProc); |
| 391 break; | 424 break; |
| 392 case kY_SkAxisAlignment: | 425 case kY_SkAxisAlignment: |
| 393 to_init->template initialize<GlyphFindAndPlaceSubpixel< | 426 to_init->template initialize<GlyphFindAndPlaceSubpixel< |
| 394 ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>( | 427 ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>( |
| 395 cache, glyphCacheProc); | 428 cache, glyphCacheProc); |
| 396 break; | 429 break; |
| 397 } | 430 } |
| 398 } | 431 } |
| 432 |
| 433 static SkPoint MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCachePr
oc, |
| 434 const char text[], size_t byteLength) { |
| 435 SkFixed x = 0, y = 0; |
| 436 const char* stop = text + byteLength; |
| 437 |
| 438 SkAutoKern autokern; |
| 439 |
| 440 while (text < stop) { |
| 441 // don't need x, y here, since all subpixel variants will have the |
| 442 // same advance |
| 443 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 444 |
| 445 x += autokern.adjust(glyph) + glyph.fAdvanceX; |
| 446 y += glyph.fAdvanceY; |
| 447 } |
| 448 SkASSERT(text == stop); |
| 449 return {SkFixedToScalar(x), SkFixedToScalar(y)}; |
| 450 } |
| 399 }; | 451 }; |
| 400 | 452 |
| 401 template<typename ProcessOneGlyph> | 453 template<typename ProcessOneGlyph> |
| 402 inline void SkFindAndPlaceGlyph::ProcessPosText( | 454 inline void SkFindAndPlaceGlyph::ProcessPosText( |
| 403 const char text[], size_t byteLength, const SkPoint& offset, const SkMatrix&
matrix, | 455 const char text[], size_t byteLength, SkPoint offset, const SkMatrix& matrix
, |
| 404 const SkScalar pos[], int scalarsPerPosition, SkPaint::Align textAlignment, | 456 const SkScalar pos[], int scalarsPerPosition, SkPaint::Align textAlignment, |
| 405 SkDrawCacheProc& glyphCacheProc, SkGlyphCache* cache, ProcessOneGlyph&& proc
essOneGlyph) { | 457 SkDrawCacheProc& glyphCacheProc, SkGlyphCache* cache, ProcessOneGlyph&& proc
essOneGlyph) { |
| 406 | 458 |
| 407 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix); | 459 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix); |
| 408 uint32_t mtype = matrix.getType(); | 460 uint32_t mtype = matrix.getType(); |
| 409 | 461 |
| 410 // Specialized code for handling the most common case for blink. The while l
oop is totally | 462 // Specialized code for handling the most common case for blink. The while l
oop is totally |
| 411 // de-virtualized. | 463 // de-virtualized. |
| 412 if (scalarsPerPosition == 1 | 464 if (scalarsPerPosition == 1 |
| 413 && textAlignment == SkPaint::kLeft_Align | 465 && textAlignment == SkPaint::kLeft_Align |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 case SkPaint::kRight_Align: | 520 case SkPaint::kRight_Align: |
| 469 InitSubpixel<ProcessOneGlyph, SkPaint::kRight_Align>( | 521 InitSubpixel<ProcessOneGlyph, SkPaint::kRight_Align>( |
| 470 to_init, axisAlignment, cache, glyphCacheProc); | 522 to_init, axisAlignment, cache, glyphCacheProc); |
| 471 break; | 523 break; |
| 472 } | 524 } |
| 473 } else { | 525 } else { |
| 474 switch (textAlignment) { | 526 switch (textAlignment) { |
| 475 case SkPaint::kLeft_Align: | 527 case SkPaint::kLeft_Align: |
| 476 to_init->template initialize< | 528 to_init->template initialize< |
| 477 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, | 529 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
| 478 SkPaint::kLeft_Align>>(cache, glyphCacheProc); | 530 SkPaint::kLeft_Align, kNoKerning>>(cache, glyphCache
Proc); |
| 479 break; | 531 break; |
| 480 case SkPaint::kCenter_Align: | 532 case SkPaint::kCenter_Align: |
| 481 to_init->template initialize< | 533 to_init->template initialize< |
| 482 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, | 534 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
| 483 SkPaint::kCenter_Align>>(cache, glyphCacheProc); | 535 SkPaint::kCenter_Align, kNoKerning>>(cache, glyphCac
heProc); |
| 484 break; | 536 break; |
| 485 case SkPaint::kRight_Align: | 537 case SkPaint::kRight_Align: |
| 486 to_init->template initialize< | 538 to_init->template initialize< |
| 487 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, | 539 GlyphFindAndPlaceFullPixel<ProcessOneGlyph, |
| 488 SkPaint::kRight_Align>>(cache, glyphCacheProc); | 540 SkPaint::kRight_Align, kNoKerning>>(cache, glyphCach
eProc); |
| 489 break; | 541 break; |
| 490 } | 542 } |
| 491 } | 543 } |
| 492 } | 544 } |
| 493 }; | 545 }; |
| 494 | 546 |
| 495 const char* stop = text + byteLength; | 547 const char* stop = text + byteLength; |
| 496 while (text < stop) { | 548 while (text < stop) { |
| 497 SkPoint mappedPoint = mapper->map(positionReader->nextPoint()); | 549 SkPoint mappedPoint = mapper->map(positionReader->nextPoint()); |
| 498 findAndPosition->findAndPositionGlyph( | 550 findAndPosition->findAndPositionGlyph( |
| 499 &text, mappedPoint, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); | 551 &text, mappedPoint, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); |
| 500 } | 552 } |
| 501 } | 553 } |
| 502 | 554 |
| 555 template<typename ProcessOneGlyph> |
| 556 inline void SkFindAndPlaceGlyph::ProcessText( |
| 557 const char text[], size_t byteLength, SkPoint offset, const SkMatrix& matrix
, |
| 558 SkPaint::Align textAlignment, SkDrawCacheProc& glyphCacheProc, SkGlyphCache*
cache, |
| 559 ProcessOneGlyph&& processOneGlyph) { |
| 560 |
| 561 // transform the starting point |
| 562 matrix.mapPoints(&offset, 1); |
| 563 |
| 564 // need to measure first |
| 565 if (textAlignment != SkPaint::kLeft_Align) { |
| 566 SkVector stop = MeasureText(cache, glyphCacheProc, text, byteLength); |
| 567 |
| 568 if (textAlignment == SkPaint::kCenter_Align) { |
| 569 stop *= SK_ScalarHalf; |
| 570 } |
| 571 offset -= stop; |
| 572 } |
| 573 |
| 574 GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{ |
| 575 [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) { |
| 576 if (cache->isSubpixel()) { |
| 577 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(m
atrix); |
| 578 InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>( |
| 579 to_init, axisAlignment, cache, glyphCacheProc); |
| 580 } else { |
| 581 to_init->template initialize< |
| 582 GlyphFindAndPlaceFullPixel< |
| 583 ProcessOneGlyph, SkPaint::kLeft_Align, kUseKerning>>( |
| 584 cache, glyphCacheProc); |
| 585 } |
| 586 } |
| 587 }; |
| 588 |
| 589 const char* stop = text + byteLength; |
| 590 SkPoint current = offset; |
| 591 while (text < stop) { |
| 592 current = |
| 593 findAndPosition->findAndPositionGlyph( |
| 594 &text, current, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); |
| 595 |
| 596 } |
| 597 } |
| 598 |
| 503 #endif // SkFindAndPositionGlyph_DEFINED | 599 #endif // SkFindAndPositionGlyph_DEFINED |
| OLD | NEW |