blob: 0eeb0cf27793f665d4811823e16bfb93144ff9b8 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
herb0c752f42015-06-24 13:06:21 -07004 * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 */
6
Herb Derby5fd955e2019-01-16 11:23:29 -05007#ifndef SkStrike_DEFINED
8#define SkStrike_DEFINED
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkFontMetrics.h"
11#include "include/core/SkFontTypes.h"
12#include "include/core/SkPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/private/SkTHash.h"
14#include "include/private/SkTemplates.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040015#include "src/core/SkArenaAlloc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/core/SkDescriptor.h"
17#include "src/core/SkGlyph.h"
18#include "src/core/SkGlyphRunPainter.h"
19#include "src/core/SkScalerContext.h"
20#include "src/core/SkStrikeInterface.h"
bungeman520ced62016-10-18 08:03:42 -040021#include <memory>
reed@android.com8a1c16f2008-12-17 15:59:43 +000022
reed@android.com8a1c16f2008-12-17 15:59:43 +000023/** \class SkGlyphCache
24
herb0c752f42015-06-24 13:06:21 -070025 This class represents a strike: a specific combination of typeface, size, matrix, etc., and
Mike Reedfdb876d2019-02-01 09:55:20 -050026 holds the glyphs for that strike. Calling any of the getGlyphID... methods will
herb0c752f42015-06-24 13:06:21 -070027 return the requested glyph, either instantly if it is already cached, or by first generating
28 it and then adding it to the strike.
reed@android.com8a1c16f2008-12-17 15:59:43 +000029
herb0c752f42015-06-24 13:06:21 -070030 The strikes are held in a global list, available to all threads. To interact with one, call
Herb Derby82a36ac2018-03-09 16:40:48 -050031 either Find{OrCreate}Exclusive().
Herb Derbydfeb2aa2018-02-28 18:47:27 -050032
33 The Find*Exclusive() method returns SkExclusiveStrikePtr, which releases exclusive ownership
34 when they go out of scope.
reed@android.com8a1c16f2008-12-17 15:59:43 +000035*/
Herb Derbye8d2d012019-03-11 17:22:47 -040036class SkStrike final : public SkStrikeInterface {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037public:
Herb Derby5fd955e2019-01-16 11:23:29 -050038 SkStrike(const SkDescriptor& desc,
39 std::unique_ptr<SkScalerContext> scaler,
40 const SkFontMetrics&);
Herb Derbydce19a72018-04-18 16:02:17 -040041
Herb Derbydfeb2aa2018-02-28 18:47:27 -050042 /** Return true if glyph is cached. */
43 bool isGlyphCached(SkGlyphID glyphID, SkFixed x, SkFixed y) const;
44
Herb Derby33a6f7c2019-06-07 11:01:36 -040045 // Return a glyph. Create it if it doesn't exist, and initialize the glyph with metrics and
46 // advances.
Herb Derby37216882019-06-13 17:24:24 -040047 SkGlyph* glyph(SkPackedGlyphID packedID);
48 SkGlyph* glyph(SkGlyphID glyphID);
Herb Derby511dcfc2019-06-24 12:58:41 -040049 SkGlyph* glyphFromPrototype(const SkGlyphPrototype& p, void* image = nullptr);
50 SkGlyph* glyph(SkGlyphID, SkPoint);
Herb Derby33a6f7c2019-06-07 11:01:36 -040051
Herb Derbyf0e75812019-06-12 11:14:50 -040052 // Return a glyph or nullptr if it does not exits in the strike.
53 SkGlyph* glyphOrNull(SkPackedGlyphID id) const;
54
Herb Derby33a6f7c2019-06-07 11:01:36 -040055 // Return a glyph. Create it if it doesn't exist, but zero the data.
56 SkGlyph* uninitializedGlyph(SkPackedGlyphID id);
57
Herb Derbyf0e75812019-06-12 11:14:50 -040058 // If the path has never been set, then use the scaler context to add the glyph.
59 const SkPath* preparePath(SkGlyph*) override;
60
61 // If the path has never been set, then add a path to glyph.
62 const SkPath* preparePath(SkGlyph* glyph, const SkPath* path);
63
Herb Derbyd2a18872019-06-18 17:07:39 -040064 SkSpan<SkPoint> getAdvances(SkSpan<const SkGlyphID>, SkPoint[]);
Herb Derby41f4f312018-06-06 17:45:53 +000065
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +000066 /** Returns the number of glyphs for this strike.
67 */
reed216b6432015-08-19 12:25:40 -070068 unsigned getGlyphCount() const;
69
70 /** Return the number of glyphs currently cached. */
71 int countCachedGlyphs() const;
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +000072
herb0c752f42015-06-24 13:06:21 -070073 /** Return the image associated with the glyph. If it has not been generated this will
74 trigger that.
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 */
76 const void* findImage(const SkGlyph&);
herb0c752f42015-06-24 13:06:21 -070077
Khushal4010c792018-06-13 09:44:23 -070078 /** Initializes the image associated with the glyph with |data|.
Khushalb2e71272018-05-15 12:59:48 -070079 */
Herb Derby9b06f212019-06-21 14:25:47 -040080 void initializeImage(const void* data, size_t size, SkGlyph*);
Khushalb2e71272018-05-15 12:59:48 -070081
caryclark0449bcf2016-02-09 13:25:45 -080082 /** If the advance axis intersects the glyph's path, append the positions scaled and offset
83 to the array (if non-null), and set the count to the updated array length.
84 */
85 void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
Herb Derby6a075912019-05-29 17:02:49 -040086 SkGlyph* , SkScalar* array, int* count);
caryclark0449bcf2016-02-09 13:25:45 -080087
Khushal8523b6b2018-06-12 11:26:17 -070088 /** Fallback glyphs used during font remoting if the original glyph can't be found.
89 */
90 bool belongsToCache(const SkGlyph* glyph) const;
91 /** Find any glyph in this cache with the given ID, regardless of subpixel positioning.
92 * If set and present, skip over the glyph with vetoID.
93 */
94 const SkGlyph* getCachedGlyphAnySubPix(SkGlyphID,
95 SkPackedGlyphID vetoID = SkPackedGlyphID()) const;
96 void initializeGlyphFromFallback(SkGlyph* glyph, const SkGlyph&);
97
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 /** Return the vertical metrics for this strike.
99 */
Mike Reedcb6f53e2018-11-06 12:44:54 -0500100 const SkFontMetrics& getFontMetrics() const {
reed@google.com0a01f5a2013-05-08 14:19:08 +0000101 return fFontMetrics;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000103
reed@google.com98539c62011-03-15 15:40:16 +0000104 SkMask::Format getMaskFormat() const {
105 return fScalerContext->getMaskFormat();
106 }
107
reed@google.comabf00aa2012-01-03 19:43:20 +0000108 bool isSubpixel() const {
Herb Derby4f169ec2018-08-22 17:26:46 -0400109 return fIsSubpixel;
reed@google.comabf00aa2012-01-03 19:43:20 +0000110 }
111
Herb Derby4f169ec2018-08-22 17:26:46 -0400112 SkVector rounding() const override;
113
114 const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) override;
115
Herb Derby96850572019-02-11 13:02:18 -0500116 const SkDescriptor& getDescriptor() const override;
117
Herb Derby812499d2019-04-10 18:09:13 -0400118 SkSpan<const SkGlyphPos> prepareForDrawing(const SkGlyphID glyphIDs[],
119 const SkPoint positions[],
120 size_t n,
121 int maxDimension,
Herb Derby1c550f72019-04-23 11:04:29 -0400122 PreparationDetail detail,
Herb Derby812499d2019-04-10 18:09:13 -0400123 SkGlyphPos results[]) override;
Herb Derbye8d2d012019-03-11 17:22:47 -0400124
Herb Derby49253642019-02-11 14:20:31 -0500125 void onAboutToExitScope() override;
Herb Derby96850572019-02-11 13:02:18 -0500126
ssid33c594c2015-08-27 09:23:54 -0700127 /** Return the approx RAM usage for this cache. */
128 size_t getMemoryUsed() const { return fMemoryUsed; }
129
reed40dab982015-01-28 13:28:53 -0800130 void dump() const;
131
bungeman7cfd46a2016-10-20 16:06:52 -0400132 SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
djsollen@google.com15eeca02012-06-01 12:52:26 +0000133
reed@android.comf2b98d62010-12-20 18:26:13 +0000134#ifdef SK_DEBUG
Khushalb2e71272018-05-15 12:59:48 -0700135 void forceValidate() const;
reed@android.comf2b98d62010-12-20 18:26:13 +0000136 void validate() const;
137#else
138 void validate() const {}
139#endif
140
141 class AutoValidate : SkNoncopyable {
142 public:
Herb Derby5fd955e2019-01-16 11:23:29 -0500143 AutoValidate(const SkStrike* cache) : fCache(cache) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000144 if (fCache) {
145 fCache->validate();
146 }
147 }
148 ~AutoValidate() {
149 if (fCache) {
150 fCache->validate();
151 }
152 }
153 void forget() {
halcanary96fcdcc2015-08-27 07:41:13 -0700154 fCache = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000155 }
156 private:
Herb Derby5fd955e2019-01-16 11:23:29 -0500157 const SkStrike* fCache;
reed@android.comf2b98d62010-12-20 18:26:13 +0000158 };
reed@google.com98539c62011-03-15 15:40:16 +0000159
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160private:
Herb Derbye46ccf82019-01-09 11:22:00 -0500161 class GlyphMapHashTraits {
162 public:
163 static SkPackedGlyphID GetKey(const SkGlyph* glyph) {
164 return glyph->getPackedID();
165 }
166 static uint32_t Hash(SkPackedGlyphID glyphId) {
167 return glyphId.hash();
168 }
169 };
170
Herb Derby33a6f7c2019-06-07 11:01:36 -0400171 SkGlyph* makeGlyph(SkPackedGlyphID);
172
Herb Derbyd2a18872019-06-18 17:07:39 -0400173 // Metrics will hold a mutex while doing its work. This is one of the few places that will
174 // need a mutex.
175 SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID>glyphIDs, const SkGlyph* result[]);
176
Herb Derby33a6f7c2019-06-07 11:01:36 -0400177 const SkAutoDescriptor fDesc;
178 const std::unique_ptr<SkScalerContext> fScalerContext;
179 SkFontMetrics fFontMetrics;
180
Herb Derbye46ccf82019-01-09 11:22:00 -0500181 // Map from a combined GlyphID and sub-pixel position to a SkGlyph*.
182 // The actual glyph is stored in the fAlloc. This structure provides an
Herb Derby33a6f7c2019-06-07 11:01:36 -0400183 // unchanging pointer as long as the strike is alive.
Herb Derbye46ccf82019-01-09 11:22:00 -0500184 SkTHashTable<SkGlyph*, SkPackedGlyphID, GlyphMapHashTraits> fGlyphMap;
herbcd7f0352015-09-15 15:15:40 -0700185
Herb Derby7c5a8062017-01-20 11:59:03 -0500186 // so we don't grow our arrays a lot
Herb Derby80d22ea2017-01-24 11:01:59 -0500187 static constexpr size_t kMinGlyphCount = 8;
188 static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
189 static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
Herb Derby7c5a8062017-01-20 11:59:03 -0500190
Herb Derby80d22ea2017-01-24 11:01:59 -0500191 SkArenaAlloc fAlloc {kMinAllocAmount};
herbcd7f0352015-09-15 15:15:40 -0700192
Herb Derby33a6f7c2019-06-07 11:01:36 -0400193 // Tracks (approx) how much ram is tied-up in this strike.
Herb Derby80d22ea2017-01-24 11:01:59 -0500194 size_t fMemoryUsed;
Herb Derby4f169ec2018-08-22 17:26:46 -0400195
196 const bool fIsSubpixel;
197 const SkAxisAlignment fAxisAlignment;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198};
199
Herb Derby5fd955e2019-01-16 11:23:29 -0500200#endif // SkStrike_DEFINED