Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: src/core/SkFindAndPlaceGlyph.h

Issue 1409123010: Extract glyph find and position code. (Closed) Base URL: https://skia.googlesource.com/skia.git@extract-glyph-position-code
Patch Set: undef the constant Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkDraw.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « src/core/SkDraw.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698