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 // The value stored in fDigestForPackedGlyphID.
25 // index() is the index into fGlyphForIndex.
26 class SkGlyphDigest {
27 public:
28     // Default ctor is only needed for the hash table.
29     SkGlyphDigest() = default;
SkGlyphDigest(size_t i,const SkGlyph & glyph)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)} {}
index()36     int index()          const {return fIndex;        }
isEmpty()37     bool isEmpty()       const {return fIsEmpty;      }
isColor()38     bool isColor()       const {return fIsColor;      }
canDrawAsMask()39     bool canDrawAsMask() const {return fCanDrawAsMask;}
canDrawAsSDFT()40     bool canDrawAsSDFT() const {return fCanDrawAsSDFT;}
41 
42 private:
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.
53 class SkScalerCache {
54 public:
55     SkScalerCache(const SkDescriptor& desc,
56                   std::unique_ptr<SkScalerContext> scaler,
57                   const SkFontMetrics* metrics = nullptr);
58 
59     // Lookup (or create if needed) the toGlyph using toID. If that glyph is not initialized with
60     // an image, then use the information in from to initialize the width, height top, left,
61     // format and image of the toGlyph. This is mainly used preserving the glyph if it was
62     // created by a search of desperation.
63     std::tuple<SkGlyph*, size_t> mergeGlyphAndImage(
64             SkPackedGlyphID toID, const SkGlyph& from) SK_EXCLUDES(fMu);
65 
66     // If the path has never been set, then add a path to glyph.
67     std::tuple<const SkPath*, size_t> mergePath(
68             SkGlyph* glyph, const SkPath* path) SK_EXCLUDES(fMu);
69 
70     /** Return the number of glyphs currently cached. */
71     int countCachedGlyphs() const SK_EXCLUDES(fMu);
72 
73     /** If the advance axis intersects the glyph's path, append the positions scaled and offset
74         to the array (if non-null), and set the count to the updated array length.
75     */
76     void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
77                         SkGlyph* , SkScalar* array, int* count) SK_EXCLUDES(fMu);
78 
getFontMetrics()79     const SkFontMetrics& getFontMetrics() const {
80         return fFontMetrics;
81     }
82 
83     std::tuple<SkSpan<const SkGlyph*>, size_t> metrics(
84             SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
85 
86     std::tuple<SkSpan<const SkGlyph*>, size_t> preparePaths(
87             SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
88 
89     std::tuple<SkSpan<const SkGlyph*>, size_t> prepareImages(
90             SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) SK_EXCLUDES(fMu);
91 
92     size_t prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* drawables) SK_EXCLUDES(fMu);
93 
94     // SkStrikeForGPU APIs
roundingSpec()95     const SkGlyphPositionRoundingSpec& roundingSpec() const {
96         return fRoundingSpec;
97     }
98 
99     const SkDescriptor& getDescriptor() const;
100 
101     size_t prepareForMaskDrawing(
102             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
103 
104     size_t prepareForSDFTDrawing(
105             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
106 
107     size_t prepareForPathDrawing(
108             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) SK_EXCLUDES(fMu);
109 
110     void dump() const SK_EXCLUDES(fMu);
111 
getScalerContext()112     SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
113 
114 private:
115     template <typename Fn>
116     size_t commonFilterLoop(SkDrawableGlyphBuffer* drawables, Fn&& fn) SK_REQUIRES(fMu);
117 
118     // Return a glyph. Create it if it doesn't exist, and initialize the glyph with metrics and
119     // advances using a scaler.
120     std::tuple<SkGlyph*, size_t> glyph(SkPackedGlyphID) SK_REQUIRES(fMu);
121 
122     std::tuple<SkGlyphDigest, size_t> digest(SkPackedGlyphID) SK_REQUIRES(fMu);
123 
124     // Generate the glyph digest information and update structures to add the glyph.
125     SkGlyphDigest addGlyph(SkGlyph* glyph) SK_REQUIRES(fMu);
126 
127     std::tuple<const void*, size_t> prepareImage(SkGlyph* glyph) SK_REQUIRES(fMu);
128 
129     // If the path has never been set, then use the scaler context to add the glyph.
130     std::tuple<const SkPath*, size_t> preparePath(SkGlyph*) SK_REQUIRES(fMu);
131 
132     enum PathDetail {
133         kMetricsOnly,
134         kMetricsAndPath
135     };
136 
137     // internalPrepare will only be called with a mutex already held.
138     std::tuple<SkSpan<const SkGlyph*>, size_t> internalPrepare(
139             SkSpan<const SkGlyphID> glyphIDs,
140             PathDetail pathDetail,
141             const SkGlyph** results) SK_REQUIRES(fMu);
142 
143     const SkAutoDescriptor                 fDesc;
144     const std::unique_ptr<SkScalerContext> fScalerContext;
145     const SkFontMetrics                    fFontMetrics;
146     const SkGlyphPositionRoundingSpec      fRoundingSpec;
147 
148     mutable SkMutex fMu;
149 
150     // Map from a combined GlyphID and sub-pixel position to a SkGlyphDigest. The actual glyph is
151     // stored in the fAlloc. The pointer to the glyph is stored fGlyphForIndex. The
152     // SkGlyphDigest's fIndex field stores the index. This pointer provides an unchanging
153     // reference to the SkGlyph as long as the strike is alive, and fGlyphForIndex
154     // provides a dense index for glyphs.
155     SkTHashMap<SkPackedGlyphID, SkGlyphDigest> fDigestForPackedGlyphID SK_GUARDED_BY(fMu);
156     std::vector<SkGlyph*> fGlyphForIndex SK_GUARDED_BY(fMu);
157 
158     // so we don't grow our arrays a lot
159     static constexpr size_t kMinGlyphCount = 8;
160     static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
161     static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
162 
SK_GUARDED_BY(fMu)163     SkArenaAlloc            fAlloc SK_GUARDED_BY(fMu) {kMinAllocAmount};
164 };
165 
166 #endif  // SkStrike_DEFINED
167