blob: 1c6798673b22b052d7d3a97e9a18be004de216c9 [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"
Herb Derby53eb1ec2019-09-25 13:34:19 -040020#include "src/core/SkStrikeForGPU.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 Derby53eb1ec2019-09-25 13:34:19 -040036class SkStrike final : public SkStrikeForGPU {
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 Derby33a6f7c2019-06-07 11:01:36 -040042 // Return a glyph. Create it if it doesn't exist, and initialize the glyph with metrics and
Herb Derbya4eecd82019-06-25 15:05:30 -040043 // advances using a scaler.
Herb Derby37216882019-06-13 17:24:24 -040044 SkGlyph* glyph(SkPackedGlyphID packedID);
45 SkGlyph* glyph(SkGlyphID glyphID);
Herb Derby511dcfc2019-06-24 12:58:41 -040046 SkGlyph* glyph(SkGlyphID, SkPoint);
Herb Derby33a6f7c2019-06-07 11:01:36 -040047
Herb Derbya4eecd82019-06-25 15:05:30 -040048 // Return a glyph. Create it if it doesn't exist, and initialize with the prototype.
49 SkGlyph* glyphFromPrototype(const SkGlyphPrototype& p, void* image = nullptr);
50
Herb Derbyf0e75812019-06-12 11:14:50 -040051 // Return a glyph or nullptr if it does not exits in the strike.
52 SkGlyph* glyphOrNull(SkPackedGlyphID id) const;
53
Herb Derbya4eecd82019-06-25 15:05:30 -040054 const void* prepareImage(SkGlyph* glyph);
55
Herb Derby70190602019-06-24 14:53:59 -040056 // Lookup (or create if needed) the toGlyph using toID. If that glyph is not initialized with
57 // an image, then use the information in from to initialize the width, height top, left,
58 // format and image of the toGlyph. This is mainly used preserving the glyph if it was
59 // created by a search of desperation.
60 SkGlyph* mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from);
Herb Derby33a6f7c2019-06-07 11:01:36 -040061
Herb Derbyf0e75812019-06-12 11:14:50 -040062 // If the path has never been set, then use the scaler context to add the glyph.
Herb Derby1ddee022019-06-28 16:08:35 -040063 const SkPath* preparePath(SkGlyph*);
Herb Derbyf0e75812019-06-12 11:14:50 -040064
65 // If the path has never been set, then add a path to glyph.
66 const SkPath* preparePath(SkGlyph* glyph, const SkPath* path);
67
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +000068 /** Returns the number of glyphs for this strike.
69 */
reed216b6432015-08-19 12:25:40 -070070 unsigned getGlyphCount() const;
71
72 /** Return the number of glyphs currently cached. */
73 int countCachedGlyphs() const;
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +000074
caryclark0449bcf2016-02-09 13:25:45 -080075 /** If the advance axis intersects the glyph's path, append the positions scaled and offset
76 to the array (if non-null), and set the count to the updated array length.
77 */
78 void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
Herb Derby6a075912019-05-29 17:02:49 -040079 SkGlyph* , SkScalar* array, int* count);
caryclark0449bcf2016-02-09 13:25:45 -080080
Khushal8523b6b2018-06-12 11:26:17 -070081 /** Fallback glyphs used during font remoting if the original glyph can't be found.
82 */
83 bool belongsToCache(const SkGlyph* glyph) const;
84 /** Find any glyph in this cache with the given ID, regardless of subpixel positioning.
85 * If set and present, skip over the glyph with vetoID.
86 */
87 const SkGlyph* getCachedGlyphAnySubPix(SkGlyphID,
88 SkPackedGlyphID vetoID = SkPackedGlyphID()) const;
Khushal8523b6b2018-06-12 11:26:17 -070089
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 /** Return the vertical metrics for this strike.
91 */
Mike Reedcb6f53e2018-11-06 12:44:54 -050092 const SkFontMetrics& getFontMetrics() const {
reed@google.com0a01f5a2013-05-08 14:19:08 +000093 return fFontMetrics;
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 }
reed@android.comf2b98d62010-12-20 18:26:13 +000095
reed@google.com98539c62011-03-15 15:40:16 +000096 SkMask::Format getMaskFormat() const {
97 return fScalerContext->getMaskFormat();
98 }
99
reed@google.comabf00aa2012-01-03 19:43:20 +0000100 bool isSubpixel() const {
Herb Derby4f169ec2018-08-22 17:26:46 -0400101 return fIsSubpixel;
reed@google.comabf00aa2012-01-03 19:43:20 +0000102 }
103
Herb Derby4f169ec2018-08-22 17:26:46 -0400104 SkVector rounding() const override;
105
Herb Derbyc9fce9c2019-06-28 13:48:08 -0400106 SkIPoint subpixelMask() const override {
107 return SkIPoint::Make((!fIsSubpixel || fAxisAlignment == kY_SkAxisAlignment) ? 0 : ~0,
108 (!fIsSubpixel || fAxisAlignment == kX_SkAxisAlignment) ? 0 : ~0);
109 }
110
Herb Derby96850572019-02-11 13:02:18 -0500111 const SkDescriptor& getDescriptor() const override;
112
Herb Derby9c9af8e2019-06-28 17:54:54 -0400113 SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID> glyphIDs,
114 const SkGlyph* results[]);
115
Herb Derby246c3ea2019-07-03 10:42:20 -0400116 SkSpan<const SkGlyph*> preparePaths(SkSpan<const SkGlyphID> glyphIDs,
117 const SkGlyph* results[]);
118
119 SkSpan<const SkGlyph*> prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,
120 const SkGlyph* results[]);
121
Herb Derby1436a132019-08-08 18:02:27 -0400122 SkSpan<const SkGlyphPos> prepareForDrawingRemoveEmpty(const SkPackedGlyphID packedGlyphIDs[],
123 const SkPoint positions[],
124 size_t n,
125 int maxDimension,
Herb Derby1436a132019-08-08 18:02:27 -0400126 SkGlyphPos results[]) override;
Herb Derbye8d2d012019-03-11 17:22:47 -0400127
Herb Derby49253642019-02-11 14:20:31 -0500128 void onAboutToExitScope() override;
Herb Derby96850572019-02-11 13:02:18 -0500129
ssid33c594c2015-08-27 09:23:54 -0700130 /** Return the approx RAM usage for this cache. */
131 size_t getMemoryUsed() const { return fMemoryUsed; }
132
reed40dab982015-01-28 13:28:53 -0800133 void dump() const;
134
bungeman7cfd46a2016-10-20 16:06:52 -0400135 SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
djsollen@google.com15eeca02012-06-01 12:52:26 +0000136
reed@android.comf2b98d62010-12-20 18:26:13 +0000137#ifdef SK_DEBUG
Khushalb2e71272018-05-15 12:59:48 -0700138 void forceValidate() const;
reed@android.comf2b98d62010-12-20 18:26:13 +0000139 void validate() const;
140#else
141 void validate() const {}
142#endif
143
144 class AutoValidate : SkNoncopyable {
145 public:
Herb Derby5fd955e2019-01-16 11:23:29 -0500146 AutoValidate(const SkStrike* cache) : fCache(cache) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000147 if (fCache) {
148 fCache->validate();
149 }
150 }
151 ~AutoValidate() {
152 if (fCache) {
153 fCache->validate();
154 }
155 }
156 void forget() {
halcanary96fcdcc2015-08-27 07:41:13 -0700157 fCache = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000158 }
159 private:
Herb Derby5fd955e2019-01-16 11:23:29 -0500160 const SkStrike* fCache;
reed@android.comf2b98d62010-12-20 18:26:13 +0000161 };
reed@google.com98539c62011-03-15 15:40:16 +0000162
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163private:
Herb Derbye46ccf82019-01-09 11:22:00 -0500164 class GlyphMapHashTraits {
165 public:
166 static SkPackedGlyphID GetKey(const SkGlyph* glyph) {
167 return glyph->getPackedID();
168 }
169 static uint32_t Hash(SkPackedGlyphID glyphId) {
170 return glyphId.hash();
171 }
172 };
173
Herb Derby33a6f7c2019-06-07 11:01:36 -0400174 SkGlyph* makeGlyph(SkPackedGlyphID);
175
Herb Derby246c3ea2019-07-03 10:42:20 -0400176 enum PathDetail {
177 kMetricsOnly,
178 kMetricsAndPath
179 };
180
181 // internalPrepare will only be called with a mutex already held.
182 SkSpan<const SkGlyph*> internalPrepare(
183 SkSpan<const SkGlyphID> glyphIDs,
184 PathDetail pathDetail,
185 const SkGlyph** results);
Herb Derbyd2a18872019-06-18 17:07:39 -0400186
Herb Derby33a6f7c2019-06-07 11:01:36 -0400187 const SkAutoDescriptor fDesc;
188 const std::unique_ptr<SkScalerContext> fScalerContext;
189 SkFontMetrics fFontMetrics;
190
Herb Derbye46ccf82019-01-09 11:22:00 -0500191 // Map from a combined GlyphID and sub-pixel position to a SkGlyph*.
192 // The actual glyph is stored in the fAlloc. This structure provides an
Herb Derby33a6f7c2019-06-07 11:01:36 -0400193 // unchanging pointer as long as the strike is alive.
Herb Derbye46ccf82019-01-09 11:22:00 -0500194 SkTHashTable<SkGlyph*, SkPackedGlyphID, GlyphMapHashTraits> fGlyphMap;
herbcd7f0352015-09-15 15:15:40 -0700195
Herb Derby7c5a8062017-01-20 11:59:03 -0500196 // so we don't grow our arrays a lot
Herb Derby80d22ea2017-01-24 11:01:59 -0500197 static constexpr size_t kMinGlyphCount = 8;
198 static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
199 static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
Herb Derby7c5a8062017-01-20 11:59:03 -0500200
Herb Derby80d22ea2017-01-24 11:01:59 -0500201 SkArenaAlloc fAlloc {kMinAllocAmount};
herbcd7f0352015-09-15 15:15:40 -0700202
Herb Derby33a6f7c2019-06-07 11:01:36 -0400203 // Tracks (approx) how much ram is tied-up in this strike.
Herb Derby80d22ea2017-01-24 11:01:59 -0500204 size_t fMemoryUsed;
Herb Derby4f169ec2018-08-22 17:26:46 -0400205
206 const bool fIsSubpixel;
207 const SkAxisAlignment fAxisAlignment;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208};
209
Herb Derby5fd955e2019-01-16 11:23:29 -0500210#endif // SkStrike_DEFINED