xref: /aosp_15_r20/external/skia/src/core/SkStrike.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkRefCnt.h"
12 #include "include/core/SkScalar.h"
13 #include "include/core/SkTypes.h"
14 #include "include/private/base/SkMutex.h"
15 #include "include/private/base/SkSpan_impl.h"
16 #include "include/private/base/SkThreadAnnotations.h"
17 #include "src/base/SkArenaAlloc.h"
18 #include "src/core/SkGlyph.h"
19 #include "src/core/SkScalerContext.h"
20 #include "src/core/SkStrikeSpec.h"
21 #include "src/core/SkTHash.h"
22 #include "src/text/StrikeForGPU.h"
23 
24 #include <cstddef>
25 #include <memory>
26 #include <vector>
27 
28 class SkDescriptor;
29 class SkDrawable;
30 class SkPath;
31 class SkReadBuffer;
32 class SkStrikeCache;
33 class SkTraceMemoryDump;
34 class SkWriteBuffer;
35 
36 class SkStrikePinner {
37 public:
38     virtual ~SkStrikePinner() = default;
39     virtual bool canDelete() = 0;
assertValid()40     virtual void assertValid() {}
41 };
42 
43 // This class holds the results of an SkScalerContext, and owns a references to that scaler.
44 class SkStrike final : public sktext::StrikeForGPU {
45 public:
46     SkStrike(SkStrikeCache* strikeCache,
47              const SkStrikeSpec& strikeSpec,
48              std::unique_ptr<SkScalerContext> scaler,
49              const SkFontMetrics* metrics,
50              std::unique_ptr<SkStrikePinner> pinner);
51 
52     void lock() override SK_ACQUIRE(fStrikeLock);
53     void unlock() override SK_RELEASE_CAPABILITY(fStrikeLock);
54     SkGlyphDigest digestFor(skglyph::ActionType, SkPackedGlyphID) override SK_REQUIRES(fStrikeLock);
55     bool prepareForImage(SkGlyph* glyph) override SK_REQUIRES(fStrikeLock);
56     bool prepareForPath(SkGlyph*) override SK_REQUIRES(fStrikeLock);
57     bool prepareForDrawable(SkGlyph*) override SK_REQUIRES(fStrikeLock);
58 
59     bool mergeFromBuffer(SkReadBuffer& buffer) SK_EXCLUDES(fStrikeLock);
60     static void FlattenGlyphsByType(SkWriteBuffer& buffer,
61                                     SkSpan<SkGlyph> images,
62                                     SkSpan<SkGlyph> paths,
63                                     SkSpan<SkGlyph> drawables);
64 
65     // Lookup (or create if needed) the returned glyph using toID. If that glyph is not initialized
66     // with an image, then use the information in fromGlyph to initialize the width, height top,
67     // left, format and image of the glyph. This is mainly used preserving the glyph if it was
68     // created by a search of desperation. This is deprecated.
69     SkGlyph* mergeGlyphAndImage(
70             SkPackedGlyphID toID, const SkGlyph& fromGlyph) SK_EXCLUDES(fStrikeLock);
71 
72     // If the path has never been set, then add a path to glyph. This is deprecated.
73     const SkPath* mergePath(
74             SkGlyph* glyph, const SkPath* path, bool hairline, bool modified) SK_EXCLUDES(fStrikeLock);
75 
76     // If the drawable has never been set, then add a drawable to glyph. This is deprecated.
77     const SkDrawable* mergeDrawable(
78             SkGlyph* glyph, sk_sp<SkDrawable> drawable) SK_EXCLUDES(fStrikeLock);
79 
80     // If the advance axis intersects the glyph's path, append the positions scaled and offset
81     // to the array (if non-null), and set the count to the updated array length.
82     // TODO: track memory usage.
83     void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
84                         SkGlyph*, SkScalar* array, int* count) SK_EXCLUDES(fStrikeLock);
85 
getFontMetrics()86     const SkFontMetrics& getFontMetrics() const {
87         return fFontMetrics;
88     }
89 
90     SkSpan<const SkGlyph*> metrics(
91             SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fStrikeLock);
92 
93     SkSpan<const SkGlyph*> preparePaths(
94             SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fStrikeLock);
95 
96     SkSpan<const SkGlyph*> prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,
97                                          const SkGlyph* results[]) SK_EXCLUDES(fStrikeLock);
98 
99     SkSpan<const SkGlyph*> prepareDrawables(
100             SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fStrikeLock);
101 
102     // SkStrikeForGPU APIs
getDescriptor()103     const SkDescriptor& getDescriptor() const override {
104         return fStrikeSpec.descriptor();
105     }
106 
roundingSpec()107     const SkGlyphPositionRoundingSpec& roundingSpec() const override {
108         return fRoundingSpec;
109     }
110 
strikePromise()111     sktext::SkStrikePromise strikePromise() override {
112         return sktext::SkStrikePromise(sk_ref_sp<SkStrike>(this));
113     }
114 
115     // Convert all the IDs into SkPaths in the span.
116     void glyphIDsToPaths(SkSpan<sktext::IDOrPath> idsOrPaths) SK_EXCLUDES(fStrikeLock);
117 
118     // Convert all the IDs into SkDrawables in the span.
119     void glyphIDsToDrawables(SkSpan<sktext::IDOrDrawable> idsOrDrawables) SK_EXCLUDES(fStrikeLock);
120 
strikeSpec()121     const SkStrikeSpec& strikeSpec() const {
122         return fStrikeSpec;
123     }
124 
verifyPinnedStrike()125     void verifyPinnedStrike() const {
126         if (fPinner != nullptr) {
127             fPinner->assertValid();
128         }
129     }
130 
131     void dump() const SK_EXCLUDES(fStrikeLock);
132     void dumpMemoryStatistics(SkTraceMemoryDump* dump) const SK_EXCLUDES(fStrikeLock);
133 
134     SkGlyph* glyph(SkGlyphDigest) SK_REQUIRES(fStrikeLock);
135 
136 private:
137     friend class SkStrikeCache;
138     friend class SkStrikeTestingPeer;
139     class Monitor;
140 
141     // Return a glyph. Create it if it doesn't exist, and initialize the glyph with metrics and
142     // advances using a scaler.
143     SkGlyph* glyph(SkPackedGlyphID) SK_REQUIRES(fStrikeLock);
144 
145     // Generate the glyph digest information and update structures to add the glyph.
146     SkGlyphDigest* addGlyphAndDigest(SkGlyph* glyph) SK_REQUIRES(fStrikeLock);
147 
148     SkGlyph* mergeGlyphFromBuffer(SkReadBuffer& buffer) SK_REQUIRES(fStrikeLock);
149     bool mergeGlyphAndImageFromBuffer(SkReadBuffer& buffer) SK_REQUIRES(fStrikeLock);
150     bool mergeGlyphAndPathFromBuffer(SkReadBuffer& buffer) SK_REQUIRES(fStrikeLock);
151     bool mergeGlyphAndDrawableFromBuffer(SkReadBuffer& buffer) SK_REQUIRES(fStrikeLock);
152 
153     // Maintain memory use statistics.
154     void updateMemoryUsage(size_t increase) SK_EXCLUDES(fStrikeLock);
155 
156     enum PathDetail {
157         kMetricsOnly,
158         kMetricsAndPath
159     };
160 
161     // internalPrepare will only be called with a mutex already held.
162     SkSpan<const SkGlyph*> internalPrepare(
163             SkSpan<const SkGlyphID> glyphIDs,
164             PathDetail pathDetail,
165             const SkGlyph** results) SK_REQUIRES(fStrikeLock);
166 
167     // The following are const and need no mutex protection.
168     const SkFontMetrics               fFontMetrics;
169     const SkGlyphPositionRoundingSpec fRoundingSpec;
170     const SkStrikeSpec                fStrikeSpec;
171     SkStrikeCache* const              fStrikeCache;
172 
173     // This mutex provides protection for this specific SkStrike.
174     mutable SkMutex fStrikeLock;
175 
176     // Maps from a combined GlyphID and sub-pixel position to a SkGlyphDigest. The actual glyph is
177     // stored in the fAlloc. The pointer to the glyph is stored fGlyphForIndex. The
178     // SkGlyphDigest's fIndex field stores the index. This pointer provides an unchanging
179     // reference to the SkGlyph as long as the strike is alive, and fGlyphForIndex
180     // provides a dense index for glyphs.
181     skia_private::THashTable<SkGlyphDigest, SkPackedGlyphID, SkGlyphDigest>
182             fDigestForPackedGlyphID SK_GUARDED_BY(fStrikeLock);
183 
184     // Maps from a glyphIndex to a glyph
185     std::vector<SkGlyph*> fGlyphForIndex SK_GUARDED_BY(fStrikeLock);
186 
187     // Context that corresponds to the glyph information in this strike.
188     const std::unique_ptr<SkScalerContext> fScalerContext SK_GUARDED_BY(fStrikeLock);
189 
190     // Used while changing the strike to track memory increase.
SK_GUARDED_BY(fStrikeLock)191     size_t fMemoryIncrease SK_GUARDED_BY(fStrikeLock) {0};
192 
193     // So, we don't grow our arrays a lot.
194     inline static constexpr size_t kMinGlyphCount = 8;
195     inline static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
196     inline static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
197 
SK_GUARDED_BY(fStrikeLock)198     SkArenaAlloc            fAlloc SK_GUARDED_BY(fStrikeLock) {kMinAllocAmount};
199 
200     // The following are protected by the SkStrikeCache's mutex.
201     SkStrike*                       fNext{nullptr};
202     SkStrike*                       fPrev{nullptr};
203     std::unique_ptr<SkStrikePinner> fPinner;
204     size_t                          fMemoryUsed{sizeof(SkStrike)};
205     bool                            fRemoved{false};
206 };
207 
208 #endif  // SkStrike_DEFINED
209