blob: 51113592cacfe2c27ef3c6eebf624980151ad341 [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
Herb Derby7c5a8062017-01-20 11:59:03 -050010#include "SkArenaAlloc.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkDescriptor.h"
Mike Reed77f94ea2019-01-22 16:30:40 -050012#include "SkFontMetrics.h"
13#include "SkFontTypes.h"
bungeman@google.combbe50132012-07-24 20:33:21 +000014#include "SkGlyph.h"
Herbert Derbya0f59352018-11-05 11:48:00 -050015#include "SkGlyphRunPainter.h"
bungemanf6d1e602016-02-22 13:20:28 -080016#include "SkPaint.h"
herbc71239b2015-07-21 15:36:25 -070017#include "SkTHash.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#include "SkScalerContext.h"
Herb Derby0f27b5e2019-03-04 11:20:28 -050019#include "SkStrikeInterface.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000020#include "SkTemplates.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
45 /** Return a glyph that has no information if it is not already filled out. */
46 SkGlyph* getRawGlyphByID(SkPackedGlyphID);
47
herb0c752f42015-06-24 13:06:21 -070048 /** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be
Mike Reedfdb876d2019-02-01 09:55:20 -050049 valid, but that is not guaranteed. If you require those, call getGlyphIDMetrics instead.
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 */
Ben Wagner6e9ac122016-11-11 14:31:06 -050051 const SkGlyph& getGlyphIDAdvance(SkGlyphID);
reed@google.com98539c62011-03-15 15:40:16 +000052
herb0c752f42015-06-24 13:06:21 -070053 /** Returns a glyph with all fields valid except fImage and fPath, which may be null. If they
54 are null, call findImage or findPath for those. If they are not null, then they are valid.
reed@google.com98539c62011-03-15 15:40:16 +000055
herb0c752f42015-06-24 13:06:21 -070056 This call is potentially slower than the matching ...Advance call. If you only need the
57 fAdvance/fDevKern fields, call those instead.
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 */
Ben Wagner6e9ac122016-11-11 14:31:06 -050059 const SkGlyph& getGlyphIDMetrics(SkGlyphID);
reed@google.com98539c62011-03-15 15:40:16 +000060
herb0c752f42015-06-24 13:06:21 -070061 /** These are variants that take the device position of the glyph. Call these only if you are
62 drawing in subpixel mode. Passing 0, 0 is effectively the same as calling the variants
63 w/o the extra params, though a tiny bit slower.
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 */
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
reed@google.com98539c62011-03-15 15:40:16 +000066
Herb Derbyed554192018-06-22 17:05:04 -040067 void getAdvances(SkSpan<const SkGlyphID>, SkPoint[]);
Herb Derby41f4f312018-06-06 17:45:53 +000068
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +000069 /** Returns the number of glyphs for this strike.
70 */
reed216b6432015-08-19 12:25:40 -070071 unsigned getGlyphCount() const;
72
73 /** Return the number of glyphs currently cached. */
74 int countCachedGlyphs() const;
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +000075
herb0c752f42015-06-24 13:06:21 -070076 /** Return the image associated with the glyph. If it has not been generated this will
77 trigger that.
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 */
79 const void* findImage(const SkGlyph&);
herb0c752f42015-06-24 13:06:21 -070080
Khushal4010c792018-06-13 09:44:23 -070081 /** Initializes the image associated with the glyph with |data|.
Khushalb2e71272018-05-15 12:59:48 -070082 */
Khushal4010c792018-06-13 09:44:23 -070083 void initializeImage(const volatile void* data, size_t size, SkGlyph*);
Khushalb2e71272018-05-15 12:59:48 -070084
caryclark0449bcf2016-02-09 13:25:45 -080085 /** If the advance axis intersects the glyph's path, append the positions scaled and offset
86 to the array (if non-null), and set the count to the updated array length.
87 */
88 void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
89 bool yAxis, SkGlyph* , SkScalar* array, int* count);
90
herb0c752f42015-06-24 13:06:21 -070091 /** Return the Path associated with the glyph. If it has not been generated this will trigger
92 that.
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 */
94 const SkPath* findPath(const SkGlyph&);
95
Khushal4010c792018-06-13 09:44:23 -070096 /** Initializes the path associated with the glyph with |data|. Returns false if
97 * data is invalid.
Khushal51371a42018-05-17 10:41:40 -070098 */
99 bool initializePath(SkGlyph*, const volatile void* data, size_t size);
100
Khushal8523b6b2018-06-12 11:26:17 -0700101 /** Fallback glyphs used during font remoting if the original glyph can't be found.
102 */
103 bool belongsToCache(const SkGlyph* glyph) const;
104 /** Find any glyph in this cache with the given ID, regardless of subpixel positioning.
105 * If set and present, skip over the glyph with vetoID.
106 */
107 const SkGlyph* getCachedGlyphAnySubPix(SkGlyphID,
108 SkPackedGlyphID vetoID = SkPackedGlyphID()) const;
109 void initializeGlyphFromFallback(SkGlyph* glyph, const SkGlyph&);
110
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111 /** Return the vertical metrics for this strike.
112 */
Mike Reedcb6f53e2018-11-06 12:44:54 -0500113 const SkFontMetrics& getFontMetrics() const {
reed@google.com0a01f5a2013-05-08 14:19:08 +0000114 return fFontMetrics;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000116
reed@google.com98539c62011-03-15 15:40:16 +0000117 SkMask::Format getMaskFormat() const {
118 return fScalerContext->getMaskFormat();
119 }
120
reed@google.comabf00aa2012-01-03 19:43:20 +0000121 bool isSubpixel() const {
Herb Derby4f169ec2018-08-22 17:26:46 -0400122 return fIsSubpixel;
reed@google.comabf00aa2012-01-03 19:43:20 +0000123 }
124
Herb Derby4f169ec2018-08-22 17:26:46 -0400125 SkVector rounding() const override;
126
127 const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) override;
128
Herb Derby5dd7f842019-04-16 11:20:38 -0400129 void generatePath(const SkGlyph& glyph) override;
Herb Derby2d4f7cb2018-11-27 12:37:50 -0500130
Herb Derby96850572019-02-11 13:02:18 -0500131 const SkDescriptor& getDescriptor() const override;
132
Herb Derbya4c64872019-02-13 11:46:19 -0500133 SkStrikeSpec strikeSpec() const override {
134 return SkStrikeSpec{this->getDescriptor(),
135 *this->getScalerContext()->getTypeface(),
136 this->getScalerContext()->getEffects()};
137 }
138
Herb Derby812499d2019-04-10 18:09:13 -0400139 SkSpan<const SkGlyphPos> prepareForDrawing(const SkGlyphID glyphIDs[],
140 const SkPoint positions[],
141 size_t n,
142 int maxDimension,
Herb Derby1c550f72019-04-23 11:04:29 -0400143 PreparationDetail detail,
Herb Derby812499d2019-04-10 18:09:13 -0400144 SkGlyphPos results[]) override;
Herb Derbye8d2d012019-03-11 17:22:47 -0400145
Herb Derby49253642019-02-11 14:20:31 -0500146 void onAboutToExitScope() override;
Herb Derby96850572019-02-11 13:02:18 -0500147
ssid33c594c2015-08-27 09:23:54 -0700148 /** Return the approx RAM usage for this cache. */
149 size_t getMemoryUsed() const { return fMemoryUsed; }
150
reed40dab982015-01-28 13:28:53 -0800151 void dump() const;
152
bungeman7cfd46a2016-10-20 16:06:52 -0400153 SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
djsollen@google.com15eeca02012-06-01 12:52:26 +0000154
reed@android.comf2b98d62010-12-20 18:26:13 +0000155#ifdef SK_DEBUG
Khushalb2e71272018-05-15 12:59:48 -0700156 void forceValidate() const;
reed@android.comf2b98d62010-12-20 18:26:13 +0000157 void validate() const;
158#else
159 void validate() const {}
160#endif
161
162 class AutoValidate : SkNoncopyable {
163 public:
Herb Derby5fd955e2019-01-16 11:23:29 -0500164 AutoValidate(const SkStrike* cache) : fCache(cache) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000165 if (fCache) {
166 fCache->validate();
167 }
168 }
169 ~AutoValidate() {
170 if (fCache) {
171 fCache->validate();
172 }
173 }
174 void forget() {
halcanary96fcdcc2015-08-27 07:41:13 -0700175 fCache = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000176 }
177 private:
Herb Derby5fd955e2019-01-16 11:23:29 -0500178 const SkStrike* fCache;
reed@android.comf2b98d62010-12-20 18:26:13 +0000179 };
reed@google.com98539c62011-03-15 15:40:16 +0000180
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181private:
mtklein8d57faf2015-10-06 07:00:45 -0700182 enum MetricsType {
Herb Derbydfeb2aa2018-02-28 18:47:27 -0500183 kNothing_MetricsType,
mtklein8d57faf2015-10-06 07:00:45 -0700184 kJustAdvance_MetricsType,
185 kFull_MetricsType
186 };
187
herbcd7f0352015-09-15 15:15:40 -0700188 enum {
Herb Derbydfeb2aa2018-02-28 18:47:27 -0500189 kHashBits = 8,
190 kHashCount = 1 << kHashBits,
191 kHashMask = kHashCount - 1
herbcd7f0352015-09-15 15:15:40 -0700192 };
193
herb0c752f42015-06-24 13:06:21 -0700194 // Return the SkGlyph* associated with MakeID. The id parameter is the
195 // combined glyph/x/y id generated by MakeID. If it is just a glyph id
Herb Derby883a9912019-02-12 16:43:43 -0500196 // then x and y are assumed to be zero. Limit the amount of work using type.
Ben Wagner6e9ac122016-11-11 14:31:06 -0500197 SkGlyph* lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, MetricsType type);
herb0c752f42015-06-24 13:06:21 -0700198
caryclark0449bcf2016-02-09 13:25:45 -0800199 static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale,
200 SkScalar xPos, SkScalar* array, int* count);
201 static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept);
halcanary9d524f22016-03-29 09:03:52 -0700202 static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2],
caryclark0449bcf2016-02-09 13:25:45 -0800203 bool yAxis, SkGlyph::Intercept* intercept);
204 static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis,
205 SkGlyph::Intercept* intercept);
206 static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis,
207 SkGlyph::Intercept* intercept);
208 static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis,
209 SkGlyph::Intercept* intercept);
210 static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph,
211 const SkScalar bounds[2]);
212
Herb Derbydce19a72018-04-18 16:02:17 -0400213 const SkAutoDescriptor fDesc;
bungeman7cfd46a2016-10-20 16:06:52 -0400214 const std::unique_ptr<SkScalerContext> fScalerContext;
Mike Reedcb6f53e2018-11-06 12:44:54 -0500215 SkFontMetrics fFontMetrics;
herb0c752f42015-06-24 13:06:21 -0700216
Herb Derbye46ccf82019-01-09 11:22:00 -0500217 class GlyphMapHashTraits {
218 public:
219 static SkPackedGlyphID GetKey(const SkGlyph* glyph) {
220 return glyph->getPackedID();
221 }
222 static uint32_t Hash(SkPackedGlyphID glyphId) {
223 return glyphId.hash();
224 }
225 };
226
227 // Map from a combined GlyphID and sub-pixel position to a SkGlyph*.
228 // The actual glyph is stored in the fAlloc. This structure provides an
229 // unchanging pointer as long as the cache is alive.
230 SkTHashTable<SkGlyph*, SkPackedGlyphID, GlyphMapHashTraits> fGlyphMap;
herbcd7f0352015-09-15 15:15:40 -0700231
Herb Derby7c5a8062017-01-20 11:59:03 -0500232 // so we don't grow our arrays a lot
Herb Derby80d22ea2017-01-24 11:01:59 -0500233 static constexpr size_t kMinGlyphCount = 8;
234 static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
235 static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
Herb Derby7c5a8062017-01-20 11:59:03 -0500236
Herb Derby80d22ea2017-01-24 11:01:59 -0500237 SkArenaAlloc fAlloc {kMinAllocAmount};
herbcd7f0352015-09-15 15:15:40 -0700238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 // used to track (approx) how much ram is tied-up in this cache
Herb Derby80d22ea2017-01-24 11:01:59 -0500240 size_t fMemoryUsed;
Herb Derby4f169ec2018-08-22 17:26:46 -0400241
242 const bool fIsSubpixel;
243 const SkAxisAlignment fAxisAlignment;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244};
245
Herb Derby5fd955e2019-01-16 11:23:29 -0500246#endif // SkStrike_DEFINED