huangcm
2025-08-25 f350412dc55c15118d0a7925d1071877498e5e24
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
 
#ifndef SkGlyphRunPainter_DEFINED
#define SkGlyphRunPainter_DEFINED
 
#include "SkDistanceFieldGen.h"
#include "SkGlyphRun.h"
#include "SkScalerContext.h"
#include "SkSurfaceProps.h"
#include "SkTextBlobPriv.h"
 
#if SK_SUPPORT_GPU
#include "text/GrTextContext.h"
class GrColorSpaceInfo;
class GrRenderTargetContext;
#endif
 
class SkGlyphRunPainterInterface;
 
class SkStrikeCommon {
public:
    static SkVector PixelRounding(bool isSubpixel, SkAxisAlignment axisAlignment);
 
    // This assumes that position has the appropriate rounding term applied.
    static SkIPoint SubpixelLookup(SkAxisAlignment axisAlignment, SkPoint position);
 
    // An atlas consists of plots, and plots hold glyphs. The minimum a plot can be is 256x256.
    // This means that the maximum size a glyph can be is 256x256.
    static constexpr uint16_t kSkSideTooBigForAtlas = 256;
 
    static bool GlyphTooBigForAtlas(const SkGlyph& glyph);
};
 
class SkGlyphRunListPainter {
public:
    // Constructor for SkBitmpapDevice.
    SkGlyphRunListPainter(const SkSurfaceProps& props,
                          SkColorType colorType,
                          SkColorSpace* cs,
                          SkStrikeCacheInterface* strikeCache);
 
#if SK_SUPPORT_GPU
    // The following two ctors are used exclusively by the GPU, and will always use the global
    // strike cache.
    SkGlyphRunListPainter(const SkSurfaceProps&, const GrColorSpaceInfo&);
    explicit SkGlyphRunListPainter(const GrRenderTargetContext& renderTargetContext);
#endif  // SK_SUPPORT_GPU
 
    class BitmapDevicePainter {
    public:
        virtual ~BitmapDevicePainter() = default;
 
        virtual void paintPaths(SkSpan<const SkPathPos> pathsAndPositions,
                                SkScalar scale,
                                const SkPaint& paint) const = 0;
 
        virtual void paintMasks(SkSpan<const SkMask> masks, const SkPaint& paint) const = 0;
    };
 
    void drawForBitmapDevice(
            const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix,
            const BitmapDevicePainter* bitmapDevice);
 
#if SK_SUPPORT_GPU
    // A nullptr for process means that the calls to the cache will be performed, but none of the
    // callbacks will be called.
    void processGlyphRunList(const SkGlyphRunList& glyphRunList,
                             const SkMatrix& viewMatrix,
                             const SkSurfaceProps& props,
                             bool contextSupportsDistanceFieldText,
                             const GrTextContext::Options& options,
                             SkGlyphRunPainterInterface* process);
#endif  // SK_SUPPORT_GPU
 
    // TODO: Make this the canonical check for Skia.
    static bool ShouldDrawAsPath(const SkPaint& paint, const SkFont& font, const SkMatrix& matrix);
 
private:
    SkGlyphRunListPainter(const SkSurfaceProps& props, SkColorType colorType,
                          SkScalerContextFlags flags, SkStrikeCacheInterface* strikeCache);
 
    struct ScopedBuffers {
        ScopedBuffers(SkGlyphRunListPainter* painter, int size);
        ~ScopedBuffers();
        SkGlyphRunListPainter* fPainter;
    };
 
    ScopedBuffers SK_WARN_UNUSED_RESULT ensureBuffers(const SkGlyphRunList& glyphRunList);
 
    // TODO: Remove once I can hoist ensureBuffers above the list for loop in all cases.
    ScopedBuffers SK_WARN_UNUSED_RESULT ensureBuffers(const SkGlyphRun& glyphRun);
 
    /**
     *  @param fARGBPositions in source space
     *  @param fARGBGlyphsIDs the glyphs to process
     *  @param fGlyphPos used as scratch space
     *  @param maxSourceGlyphDimension the longest dimension of any glyph as if all fARGBGlyphsIDs
     *                                 were drawn in source space (as if viewMatrix were identity)
     */
    void processARGBFallback(SkScalar maxSourceGlyphDimension,
                             const SkPaint& runPaint,
                             const SkFont& runFont,
                             const SkMatrix& viewMatrix,
                             SkGlyphRunPainterInterface* process);
 
    // The props as on the actual device.
    const SkSurfaceProps fDeviceProps;
    // The props for when the bitmap device can't draw LCD text.
    const SkSurfaceProps fBitmapFallbackProps;
    const SkColorType fColorType;
    const SkScalerContextFlags fScalerContextFlags;
 
    SkStrikeCacheInterface* const fStrikeCache;
 
    int fMaxRunSize{0};
    SkAutoTMalloc<SkPoint> fPositions;
    SkAutoTMalloc<SkGlyphPos> fGlyphPos;
 
    std::vector<SkGlyphPos> fPaths;
 
    // Vectors for tracking ARGB fallback information.
    std::vector<SkGlyphID> fARGBGlyphsIDs;
    std::vector<SkPoint>   fARGBPositions;
};
 
// SkGlyphRunPainterInterface are all the ways that Ganesh generates glyphs. The first
// distinction is between Device and Source.
// * Device - the data in the cache is scaled to the device. There is no transformation from the
//   cache to the screen.
// * Source - the data in the cache needs to be scaled from the cache to source space using the
//   factor cacheToSourceScale. When drawn the system must combine cacheToSourceScale and the
//   deviceView matrix to transform the cache data onto the screen. This allows zooming and
//   simple animation to reuse the same glyph data by just changing the transform.
//
// In addition to transformation type above, Masks, Paths, SDFT, and Fallback (or really the
// rendering method of last resort) are the different
// formats of data used from the cache.
class SkGlyphRunPainterInterface {
public:
    virtual ~SkGlyphRunPainterInterface() = default;
 
    virtual void startRun(const SkGlyphRun& glyphRun, bool useSDFT) = 0;
 
    virtual void processDeviceMasks(SkSpan<const SkGlyphPos> masks,
                                    SkStrikeInterface* strike) = 0;
 
    virtual void processSourcePaths(SkSpan<const SkGlyphPos> paths,
                                    SkStrikeInterface* strike, SkScalar cacheToSourceScale) = 0;
 
    virtual void processDevicePaths(SkSpan<const SkGlyphPos> paths) = 0;
 
    virtual void processSourceSDFT(SkSpan<const SkGlyphPos> masks,
                                   SkStrikeInterface* strike,
                                   const SkFont& runFont,
                                   SkScalar cacheToSourceScale,
                                   SkScalar minScale,
                                   SkScalar maxScale,
                                   bool hasWCoord) = 0;
 
    virtual void processSourceFallback(SkSpan<const SkGlyphPos> masks,
                                       SkStrikeInterface* strike,
                                       SkScalar cacheToSourceScale,
                                       bool hasW) = 0;
 
    virtual void processDeviceFallback(SkSpan<const SkGlyphPos> masks,
                                       SkStrikeInterface* strike) = 0;
 
};
 
#endif  // SkGlyphRunPainter_DEFINED