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 |