aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkDrawProcs.h
blob: d059c674701fe146ef9076c6068e42be1816c86e (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkDrawProcs_DEFINED
#define SkDrawProcs_DEFINED

#include "SkBlitter.h"
#include "SkDraw.h"
#include "SkGlyph.h"

class SkAAClip;
class SkBlitter;

struct SkDraw1Glyph {
    const SkDraw* fDraw;
    const SkRegion* fClip;
    const SkAAClip* fAAClip;
    SkBlitter* fBlitter;
    SkGlyphCache* fCache;
    const SkPaint* fPaint;
    SkIRect fClipBounds;
    /** Half the sampling frequency of the rasterized glyph in x. */
    SkFixed fHalfSampleX;
    /** Half the sampling frequency of the rasterized glyph in y. */
    SkFixed fHalfSampleY;

    /** Draws one glyph.
     *
     *  The x and y are pre-biased, so implementations may just truncate them.
     *  i.e. half the sampling frequency has been added.
     *  e.g. 1/2 or 1/(2^(SkGlyph::kSubBits+1)) has already been added.
     *  This added bias can be found in fHalfSampleX,Y.
     */
    typedef void (*Proc)(const SkDraw1Glyph&, SkFixed x, SkFixed y, const SkGlyph&);

    Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache,
              const SkPaint&);

    // call this instead of fBlitter->blitMask() since this wrapper will handle
    // the case when the mask is ARGB32_Format
    //
    void blitMask(const SkMask& mask, const SkIRect& clip) const {
        if (SkMask::kARGB32_Format == mask.fFormat) {
            this->blitMaskAsSprite(mask);
        } else {
            fBlitter->blitMask(mask, clip);
        }
    }

    // mask must be kARGB32_Format
    void blitMaskAsSprite(const SkMask& mask) const;
};

struct SkDrawProcs {
    SkDraw1Glyph::Proc  fD1GProc;
};

bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix&,
                                   SkScalar* coverage);

/**
 *  If the current paint is set to stroke and the stroke-width when applied to
 *  the matrix is <= 1.0, then this returns true, and sets coverage (simulating
 *  a stroke by drawing a hairline with partial coverage). If any of these
 *  conditions are false, then this returns false and coverage is ignored.
 */
inline bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix,
                                  SkScalar* coverage) {
    if (SkPaint::kStroke_Style != paint.getStyle()) {
        return false;
    }

    SkScalar strokeWidth = paint.getStrokeWidth();
    if (0 == strokeWidth) {
        *coverage = SK_Scalar1;
        return true;
    }

    if (!paint.isAntiAlias()) {
        return false;
    }

    return SkDrawTreatAAStrokeAsHairline(strokeWidth, matrix, coverage);
}

class SkTextAlignProc {
public:
    SkTextAlignProc(SkPaint::Align align)
        : fAlign(align) {
    }

    // Returns the position of the glyph in fixed point, which may be rounded or not
    //         by the caller e.g. subpixel doesn't round.
    // @param point interpreted as SkFixed [x, y].
    void operator()(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
        if (SkPaint::kLeft_Align == fAlign) {
            dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
        } else if (SkPaint::kCenter_Align == fAlign) {
            dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
                     SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
        } else {
            SkASSERT(SkPaint::kRight_Align == fAlign);
            dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
                     SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
        }
    }
private:
    const SkPaint::Align fAlign;
};

class SkTextAlignProcScalar {
public:
    SkTextAlignProcScalar(SkPaint::Align align)
        : fAlign(align) {
    }

    // Returns the glyph position, which may be rounded or not by the caller
    //   e.g. subpixel doesn't round.
    void operator()(const SkPoint& loc, const SkGlyph& glyph, SkPoint* dst) {
        if (SkPaint::kLeft_Align == fAlign) {
            dst->set(loc.fX, loc.fY);
        } else if (SkPaint::kCenter_Align == fAlign) {
            dst->set(loc.fX - SkFixedToScalar(glyph.fAdvanceX >> 1),
                     loc.fY - SkFixedToScalar(glyph.fAdvanceY >> 1));
        } else {
            SkASSERT(SkPaint::kRight_Align == fAlign);
            dst->set(loc.fX - SkFixedToScalar(glyph.fAdvanceX),
                     loc.fY - SkFixedToScalar(glyph.fAdvanceY));
        }
    }
private:
    const SkPaint::Align fAlign;
};

#endif