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 
22 class SkScalerContext;
23 
24 // This class represents a strike: a specific combination of typeface, size, matrix, etc., and
25 // holds the glyphs for that strike.
26 
27 class SkScalerCache {
28 public:
29     SkScalerCache(const SkDescriptor& desc,
30                   std::unique_ptr<SkScalerContext> scaler,
31                   const SkFontMetrics* metrics = nullptr);
32 
33     // Lookup (or create if needed) the toGlyph using toID. If that glyph is not initialized with
34     // an image, then use the information in from to initialize the width, height top, left,
35     // format and image of the toGlyph. This is mainly used preserving the glyph if it was
36     // created by a search of desperation.
37     std::tuple<SkGlyph*, size_t> mergeGlyphAndImage(
38             SkPackedGlyphID toID, const SkGlyph& from) SK_EXCLUDES(fMu);
39 
40     // If the path has never been set, then add a path to glyph.
41     std::tuple<const SkPath*, size_t> mergePath(
42             SkGlyph* glyph, const SkPath* path) SK_EXCLUDES(fMu);
43 
44     /** Return the number of glyphs currently cached. */
45     int countCachedGlyphs() const SK_EXCLUDES(fMu);
46 
47     /** If the advance axis intersects the glyph's path, append the positions scaled and offset
48         to the array (if non-null), and set the count to the updated array length.
49     */
50     void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
51                         SkGlyph* , SkScalar* array, int* count) SK_EXCLUDES(fMu);
52 
getFontMetrics()53     const SkFontMetrics& getFontMetrics() const {
54         return fFontMetrics;
55     }
56 
57     std::tuple<SkSpan<const SkGlyph*>, size_t> metrics(
58             SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
59 
60     std::tuple<SkSpan<const SkGlyph*>, size_t> preparePaths(
61             SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
62 
63     std::tuple<SkSpan<const SkGlyph*>, size_t> prepareImages(
64             SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
65 
66     size_t prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* drawables) SK_EXCLUDES(fMu);
67 
68     // SkStrikeForGPU APIs
roundingSpec()69     const SkGlyphPositionRoundingSpec& roundingSpec() const {
70         return fRoundingSpec;
71     }
72 
73     const SkDescriptor& getDescriptor() const;
74 
75     size_t prepareForMaskDrawing(
76             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
77 
78     size_t prepareForSDFTDrawing(
79             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
80 
81     size_t prepareForPathDrawing(
82             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
83 
84     void dump() const SK_EXCLUDES(fMu);
85 
getScalerContext()86     SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
87 
88 private:
89     class GlyphMapHashTraits {
90     public:
GetKey(const SkGlyph * glyph)91         static SkPackedGlyphID GetKey(const SkGlyph* glyph) {
92             return glyph->getPackedID();
93         }
Hash(SkPackedGlyphID glyphId)94         static uint32_t Hash(SkPackedGlyphID glyphId) {
95             return glyphId.hash();
96         }
97     };
98 
99     std::tuple<SkGlyph*, size_t> makeGlyph(SkPackedGlyphID) SK_REQUIRES(fMu);
100 
101     template <typename Fn>
102     size_t commonFilterLoop(SkDrawableGlyphBuffer* drawables, Fn&& fn) SK_REQUIRES(fMu);
103 
104     // Return a glyph. Create it if it doesn't exist, and initialize the glyph with metrics and
105     // advances using a scaler.
106     std::tuple<SkGlyph*, size_t> glyph(SkPackedGlyphID) SK_REQUIRES(fMu);
107 
108     std::tuple<const void*, size_t> prepareImage(SkGlyph* glyph) SK_REQUIRES(fMu);
109 
110     // If the path has never been set, then use the scaler context to add the glyph.
111     std::tuple<const SkPath*, size_t> preparePath(SkGlyph*) SK_REQUIRES(fMu);
112 
113     enum PathDetail {
114         kMetricsOnly,
115         kMetricsAndPath
116     };
117 
118     // internalPrepare will only be called with a mutex already held.
119     std::tuple<SkSpan<const SkGlyph*>, size_t> internalPrepare(
120             SkSpan<const SkGlyphID> glyphIDs,
121             PathDetail pathDetail,
122             const SkGlyph** results) SK_REQUIRES(fMu);
123 
124     const SkAutoDescriptor                 fDesc;
125     const std::unique_ptr<SkScalerContext> fScalerContext;
126     const SkFontMetrics                    fFontMetrics;
127     const SkGlyphPositionRoundingSpec      fRoundingSpec;
128 
129     mutable SkMutex fMu;
130 
131     // Map from a combined GlyphID and sub-pixel position to a SkGlyph*.
132     // The actual glyph is stored in the fAlloc. This structure provides an
133     // unchanging pointer as long as the strike is alive.
134     SkTHashTable<SkGlyph*, SkPackedGlyphID, GlyphMapHashTraits> fGlyphMap SK_GUARDED_BY(fMu);
135 
136     // so we don't grow our arrays a lot
137     static constexpr size_t kMinGlyphCount = 8;
138     static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
139     static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
140 
SK_GUARDED_BY(fMu)141     SkArenaAlloc            fAlloc SK_GUARDED_BY(fMu) {kMinAllocAmount};
142 };
143 
144 #endif  // SkStrike_DEFINED
145