1 /*
2  * Copyright 2012 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 SkTextToPathIter_DEFINED
9 #define SkTextToPathIter_DEFINED
10 
11 #include "SkAutoKern.h"
12 #include "SkPaint.h"
13 
14 class SkGlyphCache;
15 
16 class SkTextBaseIter {
17 protected:
18     SkTextBaseIter(const char text[], size_t length, const SkPaint& paint,
19                    bool applyStrokeAndPathEffects);
20     ~SkTextBaseIter();
21 
22     SkGlyphCache*   fCache;
23     SkPaint         fPaint;
24     SkScalar        fScale;
25     SkFixed         fPrevAdvance;
26     const char*     fText;
27     const char*     fStop;
28     SkPaint::GlyphCacheProc fGlyphCacheProc;
29 
30     SkScalar        fXPos;      // accumulated xpos, returned in next
31     SkAutoKern      fAutoKern;
32     int             fXYIndex;   // cache for horizontal -vs- vertical text
33 };
34 
35 class SkTextToPathIter : SkTextBaseIter {
36 public:
SkTextToPathIter(const char text[],size_t length,const SkPaint & paint,bool applyStrokeAndPathEffects)37     SkTextToPathIter(const char text[], size_t length, const SkPaint& paint,
38                      bool applyStrokeAndPathEffects)
39                      : SkTextBaseIter(text, length, paint, applyStrokeAndPathEffects) {
40     }
41 
getPaint()42     const SkPaint&  getPaint() const { return fPaint; }
getPathScale()43     SkScalar        getPathScale() const { return fScale; }
44 
45     /**
46      *  Returns false when all of the text has been consumed
47      */
48     bool next(const SkPath** path, SkScalar* xpos);
49 };
50 
51 class SkTextInterceptsIter : SkTextBaseIter {
52 public:
53     enum class TextType {
54         kText,
55         kPosText
56     };
57 
SkTextInterceptsIter(const char text[],size_t length,const SkPaint & paint,const SkScalar bounds[2],SkScalar x,SkScalar y,TextType textType)58     SkTextInterceptsIter(const char text[], size_t length, const SkPaint& paint,
59                          const SkScalar bounds[2], SkScalar x, SkScalar y, TextType textType)
60                          : SkTextBaseIter(text, length, paint, false)
61                          , fTextType(textType) {
62         fBoundsBase[0] = bounds[0];
63         fBoundsBase[1] = bounds[1];
64         this->setPosition(x, y);
65     }
66 
67     /**
68      *  Returns false when all of the text has been consumed
69      */
70     bool next(SkScalar* array, int* count);
71 
setPosition(SkScalar x,SkScalar y)72     void setPosition(SkScalar x, SkScalar y) {
73         SkScalar xOffset = TextType::kText == fTextType && fXYIndex ? fXPos : 0;
74         if (TextType::kPosText == fTextType
75                 && fPaint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first
76             const char* text = fText;
77             const SkGlyph& glyph = fGlyphCacheProc(fCache, &text);
78             SkScalar width = SkScalarMul(SkFixedToScalar((&glyph.fAdvanceX)[0]), fScale);
79             if (fPaint.getTextAlign() == SkPaint::kCenter_Align) {
80                 width = SkScalarHalf(width);
81             }
82             xOffset = width;
83         }
84 
85         for (int i = 0; i < (int) SK_ARRAY_COUNT(fBounds); ++i) {
86             SkScalar bound = fBoundsBase[i] - (fXYIndex ? x : y);
87             if (fXYIndex) {
88                 bound += xOffset;
89             }
90             fBounds[i] = bound / fScale;
91         }
92 
93         fXPos = xOffset + (fXYIndex ? y : x);
94         fPrevAdvance = 0;
95     }
96 
97 private:
98     SkScalar fBounds[2];
99     SkScalar fBoundsBase[2];
100     TextType fTextType;
101 };
102 
103 #endif
104