blob: 76b2fae7880a7638e86937ce4100bbca3ec8c5b9 [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 Derby706a7cd2019-02-08 16:01:47 -0500129 bool decideCouldDrawFromPath(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,
143 SkGlyphPos results[]) override;
Herb Derbye8d2d012019-03-11 17:22:47 -0400144
Herb Derby49253642019-02-11 14:20:31 -0500145 void onAboutToExitScope() override;
Herb Derby96850572019-02-11 13:02:18 -0500146
ssid33c594c2015-08-27 09:23:54 -0700147 /** Return the approx RAM usage for this cache. */
148 size_t getMemoryUsed() const { return fMemoryUsed; }
149
reed40dab982015-01-28 13:28:53 -0800150 void dump() const;
151
bungeman7cfd46a2016-10-20 16:06:52 -0400152 SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
djsollen@google.com15eeca02012-06-01 12:52:26 +0000153
reed@android.comf2b98d62010-12-20 18:26:13 +0000154#ifdef SK_DEBUG
Khushalb2e71272018-05-15 12:59:48 -0700155 void forceValidate() const;
reed@android.comf2b98d62010-12-20 18:26:13 +0000156 void validate() const;
157#else
158 void validate() const {}
159#endif
160
161 class AutoValidate : SkNoncopyable {
162 public:
Herb Derby5fd955e2019-01-16 11:23:29 -0500163 AutoValidate(const SkStrike* cache) : fCache(cache) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000164 if (fCache) {
165 fCache->validate();
166 }
167 }
168 ~AutoValidate() {
169 if (fCache) {
170 fCache->validate();
171 }
172 }
173 void forget() {
halcanary96fcdcc2015-08-27 07:41:13 -0700174 fCache = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000175 }
176 private:
Herb Derby5fd955e2019-01-16 11:23:29 -0500177 const SkStrike* fCache;
reed@android.comf2b98d62010-12-20 18:26:13 +0000178 };
reed@google.com98539c62011-03-15 15:40:16 +0000179
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180private:
mtklein8d57faf2015-10-06 07:00:45 -0700181 enum MetricsType {
Herb Derbydfeb2aa2018-02-28 18:47:27 -0500182 kNothing_MetricsType,
mtklein8d57faf2015-10-06 07:00:45 -0700183 kJustAdvance_MetricsType,
184 kFull_MetricsType
185 };
186
herbcd7f0352015-09-15 15:15:40 -0700187 enum {
Herb Derbydfeb2aa2018-02-28 18:47:27 -0500188 kHashBits = 8,
189 kHashCount = 1 << kHashBits,
190 kHashMask = kHashCount - 1
herbcd7f0352015-09-15 15:15:40 -0700191 };
192
herb0c752f42015-06-24 13:06:21 -0700193 // Return the SkGlyph* associated with MakeID. The id parameter is the
194 // combined glyph/x/y id generated by MakeID. If it is just a glyph id
Herb Derby883a9912019-02-12 16:43:43 -0500195 // then x and y are assumed to be zero. Limit the amount of work using type.
Ben Wagner6e9ac122016-11-11 14:31:06 -0500196 SkGlyph* lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, MetricsType type);
herb0c752f42015-06-24 13:06:21 -0700197
caryclark0449bcf2016-02-09 13:25:45 -0800198 static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale,
199 SkScalar xPos, SkScalar* array, int* count);
200 static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept);
halcanary9d524f22016-03-29 09:03:52 -0700201 static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2],
caryclark0449bcf2016-02-09 13:25:45 -0800202 bool yAxis, SkGlyph::Intercept* intercept);
203 static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis,
204 SkGlyph::Intercept* intercept);
205 static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis,
206 SkGlyph::Intercept* intercept);
207 static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis,
208 SkGlyph::Intercept* intercept);
209 static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph,
210 const SkScalar bounds[2]);
211
Herb Derbydce19a72018-04-18 16:02:17 -0400212 const SkAutoDescriptor fDesc;
bungeman7cfd46a2016-10-20 16:06:52 -0400213 const std::unique_ptr<SkScalerContext> fScalerContext;
Mike Reedcb6f53e2018-11-06 12:44:54 -0500214 SkFontMetrics fFontMetrics;
herb0c752f42015-06-24 13:06:21 -0700215
Herb Derbye46ccf82019-01-09 11:22:00 -0500216 class GlyphMapHashTraits {
217 public:
218 static SkPackedGlyphID GetKey(const SkGlyph* glyph) {
219 return glyph->getPackedID();
220 }
221 static uint32_t Hash(SkPackedGlyphID glyphId) {
222 return glyphId.hash();
223 }
224 };
225
226 // Map from a combined GlyphID and sub-pixel position to a SkGlyph*.
227 // The actual glyph is stored in the fAlloc. This structure provides an
228 // unchanging pointer as long as the cache is alive.
229 SkTHashTable<SkGlyph*, SkPackedGlyphID, GlyphMapHashTraits> fGlyphMap;
herbcd7f0352015-09-15 15:15:40 -0700230
Herb Derby7c5a8062017-01-20 11:59:03 -0500231 // so we don't grow our arrays a lot
Herb Derby80d22ea2017-01-24 11:01:59 -0500232 static constexpr size_t kMinGlyphCount = 8;
233 static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
234 static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
Herb Derby7c5a8062017-01-20 11:59:03 -0500235
Herb Derby80d22ea2017-01-24 11:01:59 -0500236 SkArenaAlloc fAlloc {kMinAllocAmount};
herbcd7f0352015-09-15 15:15:40 -0700237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 // used to track (approx) how much ram is tied-up in this cache
Herb Derby80d22ea2017-01-24 11:01:59 -0500239 size_t fMemoryUsed;
Herb Derby4f169ec2018-08-22 17:26:46 -0400240
241 const bool fIsSubpixel;
242 const SkAxisAlignment fAxisAlignment;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243};
244
Herb Derby5fd955e2019-01-16 11:23:29 -0500245#endif // SkStrike_DEFINED