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