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
14class SkGlyphCache;
15
16class SkTextBaseIter {
17protected:
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    SkScalar        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
35class SkTextToPathIter : SkTextBaseIter {
36public:
37    SkTextToPathIter(const char text[], size_t length, const SkPaint& paint,
38                     bool applyStrokeAndPathEffects)
39                     : SkTextBaseIter(text, length, paint, applyStrokeAndPathEffects) {
40    }
41
42    const SkPaint&  getPaint() const { return fPaint; }
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
51class SkTextInterceptsIter : SkTextBaseIter {
52public:
53    enum class TextType {
54        kText,
55        kPosText
56    };
57
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
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 = (&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
97private:
98    SkScalar fBounds[2];
99    SkScalar fBoundsBase[2];
100    TextType fTextType;
101};
102
103#endif
104