aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkTextToPathIter.h
blob: dcd5a01cd3caf764e4667fbeb50150b094a58a70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkTextToPathIter_DEFINED
#define SkTextToPathIter_DEFINED

#include "SkAutoKern.h"
#include "SkPaint.h"

class SkGlyphCache;

class SkTextBaseIter {
protected:
    SkTextBaseIter(const char text[], size_t length, const SkPaint& paint,
                   bool applyStrokeAndPathEffects);
    ~SkTextBaseIter();

    SkGlyphCache*   fCache;
    SkPaint         fPaint;
    SkScalar        fScale;
    SkScalar        fPrevAdvance;
    const char*     fText;
    const char*     fStop;
    SkPaint::GlyphCacheProc fGlyphCacheProc;

    SkScalar        fXPos;      // accumulated xpos, returned in next
    SkAutoKern      fAutoKern;
    int             fXYIndex;   // cache for horizontal -vs- vertical text
};

class SkTextToPathIter : SkTextBaseIter {
public:
    SkTextToPathIter(const char text[], size_t length, const SkPaint& paint,
                     bool applyStrokeAndPathEffects)
                     : SkTextBaseIter(text, length, paint, applyStrokeAndPathEffects) {
    }

    const SkPaint&  getPaint() const { return fPaint; }
    SkScalar        getPathScale() const { return fScale; }

    /**
     *  Returns false when all of the text has been consumed
     */
    bool next(const SkPath** path, SkScalar* xpos);
};

class SkTextInterceptsIter : SkTextBaseIter {
public:
    enum class TextType {
        kText,
        kPosText
    };

    SkTextInterceptsIter(const char text[], size_t length, const SkPaint& paint,
                         const SkScalar bounds[2], SkScalar x, SkScalar y, TextType textType)
                         : SkTextBaseIter(text, length, paint, false)
                         , fTextType(textType) {
        fBoundsBase[0] = bounds[0];
        fBoundsBase[1] = bounds[1];
        this->setPosition(x, y);
    }

    /**
     *  Returns false when all of the text has been consumed
     */
    bool next(SkScalar* array, int* count);

    void setPosition(SkScalar x, SkScalar y) {
        SkScalar xOffset = TextType::kText == fTextType && fXYIndex ? fXPos : 0;
        if (TextType::kPosText == fTextType
                && fPaint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first
            const char* text = fText;
            const SkGlyph& glyph = fGlyphCacheProc(fCache, &text);
            SkScalar width = SkScalarMul(SkFloatToScalar((&glyph.fAdvanceX)[0]), fScale);
            if (fPaint.getTextAlign() == SkPaint::kCenter_Align) {
                width = SkScalarHalf(width);
            }
            xOffset = width;
        }

        for (int i = 0; i < (int) SK_ARRAY_COUNT(fBounds); ++i) {
            SkScalar bound = fBoundsBase[i] - (fXYIndex ? x : y);
            if (fXYIndex) {
                bound += xOffset;
            }
            fBounds[i] = bound / fScale;
        }

        fXPos = xOffset + (fXYIndex ? y : x);
        fPrevAdvance = 0;
    }

private:
    SkScalar fBounds[2];
    SkScalar fBoundsBase[2];
    TextType fTextType;
};

#endif