1 | /* |
2 | * Copyright 2015 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef GrStrikeCache_DEFINED |
9 | #define GrStrikeCache_DEFINED |
10 | |
11 | #include "include/private/SkTHash.h" |
12 | #include "src/core/SkDescriptor.h" |
13 | #include "src/gpu/GrDrawOpAtlas.h" |
14 | #include "src/gpu/GrGlyph.h" |
15 | |
16 | class GrAtlasManager; |
17 | class GrGpu; |
18 | class GrStrikeCache; |
19 | class SkBulkGlyphMetricsAndImages; |
20 | |
21 | /** |
22 | * The GrTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory |
23 | * is indexed by a PackedID and SkStrike. The SkStrike is what actually creates the mask. |
24 | * The GrTextStrike may outlive the generating SkStrike. However, it retains a copy |
25 | * of it's SkDescriptor as a key to access (or regenerate) the SkStrike. GrTextStrikes are |
26 | * created by and owned by a GrStrikeCache. |
27 | */ |
28 | class GrTextStrike : public SkNVRefCnt<GrTextStrike> { |
29 | public: |
30 | GrTextStrike(const SkDescriptor& fontScalerKey); |
31 | |
32 | GrGlyph* getGlyph(SkPackedGlyphID); |
33 | |
34 | // returns true if glyph successfully added to texture atlas, false otherwise. If the glyph's |
35 | // mask format has changed, then addGlyphToAtlas will draw a clear box. This will almost never |
36 | // happen. |
37 | // TODO we can handle some of these cases if we really want to, but the long term solution is to |
38 | // get the actual glyph image itself when we get the glyph metrics. |
39 | GrDrawOpAtlas::ErrorCode addGlyphToAtlas(const SkGlyph&, |
40 | GrMaskFormat expectedMaskFormat, |
41 | bool needsPadding, |
42 | GrResourceProvider*, |
43 | GrDeferredUploadTarget*, |
44 | GrAtlasManager*, |
45 | GrGlyph*); |
46 | |
47 | private: |
48 | struct HashTraits { |
49 | // GetKey and Hash for the the hash table. |
50 | static const SkPackedGlyphID& GetKey(const GrGlyph* glyph) { |
51 | return glyph->fPackedID; |
52 | } |
53 | |
54 | static uint32_t Hash(SkPackedGlyphID key) { |
55 | return SkChecksum::Mix(key.hash()); |
56 | } |
57 | }; |
58 | SkTHashTable<GrGlyph*, SkPackedGlyphID, HashTraits> fCache; |
59 | SkAutoDescriptor fFontScalerKey; |
60 | SkArenaAlloc fAlloc{512}; |
61 | |
62 | friend class GrStrikeCache; |
63 | }; |
64 | |
65 | /** |
66 | * GrStrikeCache manages strikes which are indexed by a SkStrike. These strikes can then be |
67 | * used to generate individual Glyph Masks. |
68 | */ |
69 | class GrStrikeCache { |
70 | public: |
71 | ~GrStrikeCache(); |
72 | |
73 | // The user of the cache may hold a long-lived ref to the returned strike. However, actions by |
74 | // another client of the cache may cause the strike to be purged while it is still reffed. |
75 | // Therefore, the caller must check GrTextStrike::isAbandoned() if there are other |
76 | // interactions with the cache since the strike was received. |
77 | sk_sp<GrTextStrike> getStrike(const SkDescriptor& desc) { |
78 | if (sk_sp<GrTextStrike>* cached = fCache.find(desc)) { |
79 | return *cached; |
80 | } |
81 | return this->generateStrike(desc); |
82 | } |
83 | |
84 | void freeAll(); |
85 | |
86 | private: |
87 | sk_sp<GrTextStrike> generateStrike(const SkDescriptor& desc) { |
88 | sk_sp<GrTextStrike> strike = sk_make_sp<GrTextStrike>(desc); |
89 | fCache.set(strike); |
90 | return strike; |
91 | } |
92 | |
93 | struct DescriptorHashTraits { |
94 | static const SkDescriptor& GetKey(const sk_sp<GrTextStrike>& strike) { |
95 | return *strike->fFontScalerKey.getDesc(); |
96 | } |
97 | static uint32_t Hash(const SkDescriptor& desc) { return desc.getChecksum(); } |
98 | }; |
99 | |
100 | using StrikeHash = SkTHashTable<sk_sp<GrTextStrike>, SkDescriptor, DescriptorHashTraits>; |
101 | |
102 | StrikeHash fCache; |
103 | }; |
104 | |
105 | #endif // GrStrikeCache_DEFINED |
106 | |