xref: /third_party/skia/src/core/SkScalerCache.h (revision cb93a386)
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
5 */
6
7#ifndef SkStrike_DEFINED
8#define SkStrike_DEFINED
9
10#include "include/core/SkFontMetrics.h"
11#include "include/core/SkFontTypes.h"
12#include "include/private/SkMutex.h"
13#include "include/private/SkTHash.h"
14#include "include/private/SkTemplates.h"
15#include "src/core/SkArenaAlloc.h"
16#include "src/core/SkDescriptor.h"
17#include "src/core/SkGlyph.h"
18#include "src/core/SkGlyphRunPainter.h"
19#include "src/core/SkStrikeForGPU.h"
20#include <memory>
21
22class SkScalerContext;
23
24// The value stored in fDigestForPackedGlyphID.
25// index() is the index into fGlyphForIndex.
26class SkGlyphDigest {
27public:
28    // Default ctor is only needed for the hash table.
29    SkGlyphDigest() = default;
30    SkGlyphDigest(size_t i, const SkGlyph& glyph)
31        : fIndex{SkTo<uint32_t>(i)}
32        , fIsEmpty(glyph.isEmpty())
33        , fIsColor(glyph.isColor())
34        , fCanDrawAsMask{SkStrikeForGPU::CanDrawAsMask(glyph)}
35        , fCanDrawAsSDFT{SkStrikeForGPU::CanDrawAsSDFT(glyph)} {}
36    int index()          const {return fIndex;        }
37    bool isEmpty()       const {return fIsEmpty;      }
38    bool isColor()       const {return fIsColor;      }
39    bool canDrawAsMask() const {return fCanDrawAsMask;}
40    bool canDrawAsSDFT() const {return fCanDrawAsSDFT;}
41
42private:
43    static_assert(SkPackedGlyphID::kEndData == 20);
44    uint32_t fIndex : SkPackedGlyphID::kEndData;
45    uint32_t fIsEmpty       : 1;
46    uint32_t fIsColor       : 1;
47    uint32_t fCanDrawAsMask : 1;
48    uint32_t fCanDrawAsSDFT : 1;
49};
50
51// This class represents a strike: a specific combination of typeface, size, matrix, etc., and
52// holds the glyphs for that strike.
53class SkScalerCache {
54public:
55    SkScalerCache(std::unique_ptr<SkScalerContext> scaler,
56                  const SkFontMetrics* metrics = nullptr);
57
58    // Lookup (or create if needed) the toGlyph using toID. If that glyph is not initialized with
59    // an image, then use the information in from to initialize the width, height top, left,
60    // format and image of the toGlyph. This is mainly used preserving the glyph if it was
61    // created by a search of desperation.
62    std::tuple<SkGlyph*, size_t> mergeGlyphAndImage(
63            SkPackedGlyphID toID, const SkGlyph& from) SK_EXCLUDES(fMu);
64
65    // If the path has never been set, then add a path to glyph.
66    std::tuple<const SkPath*, size_t> mergePath(
67            SkGlyph* glyph, const SkPath* path) SK_EXCLUDES(fMu);
68
69    /** Return the number of glyphs currently cached. */
70    int countCachedGlyphs() const SK_EXCLUDES(fMu);
71
72    /** If the advance axis intersects the glyph's path, append the positions scaled and offset
73        to the array (if non-null), and set the count to the updated array length.
74    */
75    void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
76                        SkGlyph* , SkScalar* array, int* count) SK_EXCLUDES(fMu);
77
78    const SkFontMetrics& getFontMetrics() const {
79        return fFontMetrics;
80    }
81
82    std::tuple<SkSpan<const SkGlyph*>, size_t> metrics(
83            SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
84
85    std::tuple<SkSpan<const SkGlyph*>, size_t> preparePaths(
86            SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
87
88    std::tuple<SkSpan<const SkGlyph*>, size_t> prepareImages(
89            SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
90
91    size_t prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* drawables) SK_EXCLUDES(fMu);
92
93    // SkStrikeForGPU APIs
94    const SkGlyphPositionRoundingSpec& roundingSpec() const {
95        return fRoundingSpec;
96    }
97
98    size_t prepareForMaskDrawing(
99            SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
100
101    size_t prepareForSDFTDrawing(
102            SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
103
104    size_t prepareForPathDrawing(
105            SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
106
107    void dump() const SK_EXCLUDES(fMu);
108
109    SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
110
111private:
112    template <typename Fn>
113    size_t commonFilterLoop(SkDrawableGlyphBuffer* drawables, Fn&& fn) SK_REQUIRES(fMu);
114
115    // Return a glyph. Create it if it doesn't exist, and initialize the glyph with metrics and
116    // advances using a scaler.
117    std::tuple<SkGlyph*, size_t> glyph(SkPackedGlyphID) SK_REQUIRES(fMu);
118
119    std::tuple<SkGlyphDigest, size_t> digest(SkPackedGlyphID) SK_REQUIRES(fMu);
120
121    // Generate the glyph digest information and update structures to add the glyph.
122    SkGlyphDigest addGlyph(SkGlyph* glyph) SK_REQUIRES(fMu);
123
124    std::tuple<const void*, size_t> prepareImage(SkGlyph* glyph) SK_REQUIRES(fMu);
125
126    // If the path has never been set, then use the scaler context to add the glyph.
127    std::tuple<const SkPath*, size_t> preparePath(SkGlyph*) SK_REQUIRES(fMu);
128
129    enum PathDetail {
130        kMetricsOnly,
131        kMetricsAndPath
132    };
133
134    // internalPrepare will only be called with a mutex already held.
135    std::tuple<SkSpan<const SkGlyph*>, size_t> internalPrepare(
136            SkSpan<const SkGlyphID> glyphIDs,
137            PathDetail pathDetail,
138            const SkGlyph** results) SK_REQUIRES(fMu);
139
140    const std::unique_ptr<SkScalerContext> fScalerContext;
141    const SkFontMetrics                    fFontMetrics;
142    const SkGlyphPositionRoundingSpec      fRoundingSpec;
143
144    mutable SkMutex fMu;
145
146    // Map from a combined GlyphID and sub-pixel position to a SkGlyphDigest. The actual glyph is
147    // stored in the fAlloc. The pointer to the glyph is stored fGlyphForIndex. The
148    // SkGlyphDigest's fIndex field stores the index. This pointer provides an unchanging
149    // reference to the SkGlyph as long as the strike is alive, and fGlyphForIndex
150    // provides a dense index for glyphs.
151    SkTHashMap<SkPackedGlyphID, SkGlyphDigest> fDigestForPackedGlyphID SK_GUARDED_BY(fMu);
152    std::vector<SkGlyph*> fGlyphForIndex SK_GUARDED_BY(fMu);
153
154    // so we don't grow our arrays a lot
155    inline static constexpr size_t kMinGlyphCount = 8;
156    inline static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
157    inline static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
158
159    SkArenaAlloc            fAlloc SK_GUARDED_BY(fMu) {kMinAllocAmount};
160};
161
162#endif  // SkStrike_DEFINED
163