blob: e41e368545c32f3e7d09e0ebe2e8860e33814c61 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/core/SkStrike.h"
Herb Derbydce19a72018-04-18 16:02:17 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkGraphics.h"
11#include "include/core/SkPath.h"
12#include "include/core/SkTypeface.h"
13#include "include/private/SkMutex.h"
14#include "include/private/SkOnce.h"
15#include "include/private/SkTemplates.h"
16#include "src/core/SkMakeUnique.h"
ssid60df5422015-10-01 12:41:35 -070017#include <cctype>
18
Herb Derby5fd955e2019-01-16 11:23:29 -050019SkStrike::SkStrike(
Herb Derbydce19a72018-04-18 16:02:17 -040020 const SkDescriptor& desc,
21 std::unique_ptr<SkScalerContext> scaler,
Mike Reedcb6f53e2018-11-06 12:44:54 -050022 const SkFontMetrics& fontMetrics)
Herb Derbydce19a72018-04-18 16:02:17 -040023 : fDesc{desc}
Herb Derbyaeb425d2018-03-19 15:39:16 -040024 , fScalerContext{std::move(scaler)}
Herb Derby4f169ec2018-08-22 17:26:46 -040025 , fFontMetrics{fontMetrics}
26 , fIsSubpixel{fScalerContext->isSubpixel()}
27 , fAxisAlignment{fScalerContext->computeAxisAlignmentForHText()}
Herb Derbydfeb2aa2018-02-28 18:47:27 -050028{
Herb Derbyaeb425d2018-03-19 15:39:16 -040029 SkASSERT(fScalerContext != nullptr);
herbcd7f0352015-09-15 15:15:40 -070030 fMemoryUsed = sizeof(*this);
reed@android.com8a1c16f2008-12-17 15:59:43 +000031}
32
reed@android.com8a1c16f2008-12-17 15:59:43 +000033#ifdef SK_DEBUG
reed@android.comf2b98d62010-12-20 18:26:13 +000034#define VALIDATE() AutoValidate av(this)
reed@android.com8a1c16f2008-12-17 15:59:43 +000035#else
36#define VALIDATE()
37#endif
38
Herb Derby33a6f7c2019-06-07 11:01:36 -040039// -- glyph creation -------------------------------------------------------------------------------
40SkGlyph* SkStrike::makeGlyph(SkPackedGlyphID packedGlyphID) {
41 fMemoryUsed += sizeof(SkGlyph);
42 SkGlyph* glyph = fAlloc.make<SkGlyph>(packedGlyphID);
43 fGlyphMap.set(glyph);
44 return glyph;
45}
46
Herb Derby33a6f7c2019-06-07 11:01:36 -040047SkGlyph* SkStrike::glyph(SkPackedGlyphID packedGlyphID) {
Herb Derbya4eecd82019-06-25 15:05:30 -040048 VALIDATE();
Herb Derby33a6f7c2019-06-07 11:01:36 -040049 SkGlyph* glyph = fGlyphMap.findOrNull(packedGlyphID);
50 if (glyph == nullptr) {
51 glyph = this->makeGlyph(packedGlyphID);
52 fScalerContext->getMetrics(glyph);
53 }
54 return glyph;
55}
56
57SkGlyph* SkStrike::glyph(SkGlyphID glyphID) {
58 return this->glyph(SkPackedGlyphID{glyphID});
59}
60
Herb Derby511dcfc2019-06-24 12:58:41 -040061SkGlyph* SkStrike::glyph(SkGlyphID glyphID, SkPoint position) {
62 const SkFixed maskX = (!fIsSubpixel || fAxisAlignment == kY_SkAxisAlignment) ? 0 : ~0;
63 const SkFixed maskY = (!fIsSubpixel || fAxisAlignment == kX_SkAxisAlignment) ? 0 : ~0;
64 SkFixed subX = SkScalarToFixed(position.x()) & maskX,
65 subY = SkScalarToFixed(position.y()) & maskY;
66 return this->glyph(SkPackedGlyphID{glyphID, subX, subY});
67}
68
69SkGlyph* SkStrike::glyphFromPrototype(const SkGlyphPrototype& p, void* image) {
Herb Derby37216882019-06-13 17:24:24 -040070 SkGlyph* glyph = fGlyphMap.findOrNull(p.id);
71 if (glyph == nullptr) {
72 fMemoryUsed += sizeof(SkGlyph);
73 glyph = fAlloc.make<SkGlyph>(p);
74 fGlyphMap.set(glyph);
75 }
Herb Derby511dcfc2019-06-24 12:58:41 -040076 if (glyph->setImage(&fAlloc, image)) {
77 fMemoryUsed += glyph->imageSize();
78 }
Herb Derby37216882019-06-13 17:24:24 -040079 return glyph;
80}
81
Herb Derbyf0e75812019-06-12 11:14:50 -040082SkGlyph* SkStrike::glyphOrNull(SkPackedGlyphID id) const {
83 return fGlyphMap.findOrNull(id);
84}
85
Herb Derbyf0e75812019-06-12 11:14:50 -040086const SkPath* SkStrike::preparePath(SkGlyph* glyph) {
87 if (glyph->setPath(&fAlloc, fScalerContext.get())) {
88 fMemoryUsed += glyph->path()->approximateBytesUsed();
89 }
90 return glyph->path();
91}
92
93const SkPath* SkStrike::preparePath(SkGlyph* glyph, const SkPath* path) {
94 if (glyph->setPath(&fAlloc, path)) {
95 fMemoryUsed += glyph->path()->approximateBytesUsed();
96 }
97 return glyph->path();
98}
99
Herb Derby33a6f7c2019-06-07 11:01:36 -0400100const SkDescriptor& SkStrike::getDescriptor() const {
101 return *fDesc.getDesc();
102}
103
Herb Derby5fd955e2019-01-16 11:23:29 -0500104unsigned SkStrike::getGlyphCount() const {
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000105 return fScalerContext->getGlyphCount();
106}
107
Herb Derby5fd955e2019-01-16 11:23:29 -0500108int SkStrike::countCachedGlyphs() const {
reed216b6432015-08-19 12:25:40 -0700109 return fGlyphMap.count();
110}
111
Herb Derbyd2a18872019-06-18 17:07:39 -0400112SkSpan<const SkGlyph*> SkStrike::metrics(
113 SkSpan<const SkGlyphID>glyphIDs, const SkGlyph* results[]) {
Herb Derbyd2a18872019-06-18 17:07:39 -0400114 size_t glyphCount = 0;
115 for (auto glyphID : glyphIDs) {
116 SkGlyph* glyphPtr = this->glyph(glyphID);
117 results[glyphCount++] = glyphPtr;
118 }
119
120 return {results, glyphCount};
121}
122
Herb Derbyd2a18872019-06-18 17:07:39 -0400123SkSpan<SkPoint> SkStrike::getAdvances(SkSpan<const SkGlyphID> glyphIDs, SkPoint advances[]) {
124 auto cursor = advances;
125 SkAutoSTArray<50, const SkGlyph*> glyphStorage{SkTo<int>(glyphIDs.size())};
126 auto glyphs = this->metrics(glyphIDs, glyphStorage.get());
127 for (const SkGlyph* glyph : glyphs) {
128 *cursor++ = glyph->advanceVector();
Herb Derby41f4f312018-06-06 17:45:53 +0000129 }
Herb Derbyd2a18872019-06-18 17:07:39 -0400130 return {advances, glyphIDs.size()};
Herb Derby41f4f312018-06-06 17:45:53 +0000131}
132
Herb Derbya4eecd82019-06-25 15:05:30 -0400133
134const void* SkStrike::prepareImage(SkGlyph* glyph) {
Herb Derby9b06f212019-06-21 14:25:47 -0400135 if (glyph->setImage(&fAlloc, fScalerContext.get())) {
136 fMemoryUsed += glyph->imageSize();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 }
Herb Derby9b06f212019-06-21 14:25:47 -0400138 return glyph->image();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139}
140
Herb Derby70190602019-06-24 14:53:59 -0400141SkGlyph* SkStrike::mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from) {
142 SkGlyph* glyph = fGlyphMap.findOrNull(toID);
143 if (glyph == nullptr) {
144 glyph = this->makeGlyph(toID);
145 }
146 if (glyph->setMetricsAndImage(&fAlloc, from)) {
Herb Derby9b06f212019-06-21 14:25:47 -0400147 fMemoryUsed += glyph->imageSize();
Khushalb2e71272018-05-15 12:59:48 -0700148 }
Herb Derby70190602019-06-24 14:53:59 -0400149 return glyph;
Khushalb2e71272018-05-15 12:59:48 -0700150}
151
Herb Derby5fd955e2019-01-16 11:23:29 -0500152bool SkStrike::belongsToCache(const SkGlyph* glyph) const {
Herb Derbye46ccf82019-01-09 11:22:00 -0500153 return glyph && fGlyphMap.findOrNull(glyph->getPackedID()) == glyph;
Khushal8523b6b2018-06-12 11:26:17 -0700154}
155
Herb Derby5fd955e2019-01-16 11:23:29 -0500156const SkGlyph* SkStrike::getCachedGlyphAnySubPix(SkGlyphID glyphID,
Khushal8523b6b2018-06-12 11:26:17 -0700157 SkPackedGlyphID vetoID) const {
158 for (SkFixed subY = 0; subY < SK_Fixed1; subY += SK_FixedQuarter) {
159 for (SkFixed subX = 0; subX < SK_Fixed1; subX += SK_FixedQuarter) {
160 SkPackedGlyphID packedGlyphID{glyphID, subX, subY};
161 if (packedGlyphID == vetoID) continue;
Herb Derbye46ccf82019-01-09 11:22:00 -0500162 if (SkGlyph* glyphPtr = fGlyphMap.findOrNull(packedGlyphID)) {
163 return glyphPtr;
Khushal8523b6b2018-06-12 11:26:17 -0700164 }
165 }
166 }
167
168 return nullptr;
169}
170
Herb Derby5fd955e2019-01-16 11:23:29 -0500171SkVector SkStrike::rounding() const {
172 return SkStrikeCommon::PixelRounding(fIsSubpixel, fAxisAlignment);
Herb Derby4f169ec2018-08-22 17:26:46 -0400173}
174
Herb Derbye8d2d012019-03-11 17:22:47 -0400175// N.B. This glyphMetrics call culls all the glyphs which will not display based on a non-finite
176// position or that there are no mask pixels.
Herb Derby812499d2019-04-10 18:09:13 -0400177SkSpan<const SkGlyphPos> SkStrike::prepareForDrawing(const SkGlyphID glyphIDs[],
178 const SkPoint positions[],
179 size_t n,
180 int maxDimension,
Herb Derby1c550f72019-04-23 11:04:29 -0400181 PreparationDetail detail,
Herb Derby812499d2019-04-10 18:09:13 -0400182 SkGlyphPos result[]) {
Herb Derby13df1062019-04-08 16:29:36 -0400183 size_t drawableGlyphCount = 0;
Herb Derby13df1062019-04-08 16:29:36 -0400184 for (size_t i = 0; i < n; i++) {
Herb Derby812499d2019-04-10 18:09:13 -0400185 SkPoint position = positions[i];
186 if (SkScalarsAreFinite(position.x(), position.y())) {
187 // This assumes that the strike has no sub-pixel positioning for glyphs that are
188 // transformed from source space to device space.
Herb Derbya4eecd82019-06-25 15:05:30 -0400189 SkGlyph* glyph = this->glyph(glyphIDs[i], position);
190 if (!glyph->isEmpty()) {
191 result[drawableGlyphCount++] = {i, glyph, position};
192 if (glyph->maxDimension() <= maxDimension) {
193 // Glyph is an allowable size, good to go.
Herb Derby1c550f72019-04-23 11:04:29 -0400194 if (detail == SkStrikeInterface::kImageIfNeeded) {
Herb Derbya4eecd82019-06-25 15:05:30 -0400195 this->prepareImage(glyph);
Herb Derby1c550f72019-04-23 11:04:29 -0400196 }
Herb Derbya4eecd82019-06-25 15:05:30 -0400197 } else if (!glyph->isColor()) {
Herb Derby812499d2019-04-10 18:09:13 -0400198 // The out of atlas glyph is not color so we can draw it using paths.
Herb Derbya4eecd82019-06-25 15:05:30 -0400199 this->preparePath(glyph);
Herb Derby812499d2019-04-10 18:09:13 -0400200 } else {
Herb Derby812499d2019-04-10 18:09:13 -0400201 // This will be handled by the fallback strike.
Herb Derbya4eecd82019-06-25 15:05:30 -0400202 SkASSERT(glyph->maxDimension() > maxDimension && glyph->isColor());
Herb Derby812499d2019-04-10 18:09:13 -0400203 }
Herb Derbye8d2d012019-03-11 17:22:47 -0400204 }
205 }
206 }
207
Herb Derbyeded39a2019-04-10 16:13:26 -0400208 return SkSpan<const SkGlyphPos>{result, drawableGlyphCount};
Herb Derbye8d2d012019-03-11 17:22:47 -0400209}
210
Herb Derby5fd955e2019-01-16 11:23:29 -0500211void SkStrike::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
Herb Derby6a075912019-05-29 17:02:49 -0400212 SkGlyph* glyph, SkScalar* array, int* count) {
Herb Derby11697dc2019-06-06 11:50:42 -0400213 glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214}
215
Herb Derby5fd955e2019-01-16 11:23:29 -0500216void SkStrike::dump() const {
reed40dab982015-01-28 13:28:53 -0800217 const SkTypeface* face = fScalerContext->getTypeface();
218 const SkScalerContextRec& rec = fScalerContext->getRec();
219 SkMatrix matrix;
220 rec.getSingleMatrix(&matrix);
221 matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
222 SkString name;
223 face->getFamilyName(&name);
224
225 SkString msg;
Ben Wagner26308e12017-08-08 15:23:47 -0400226 SkFontStyle style = face->fontStyle();
Herb Derby108e94a2018-02-22 14:46:11 -0500227 msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d",
Ben Wagner26308e12017-08-08 15:23:47 -0400228 face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(),
Herb Derby108e94a2018-02-22 14:46:11 -0500229 rec.dump().c_str(), fGlyphMap.count());
reed40dab982015-01-28 13:28:53 -0800230 SkDebugf("%s\n", msg.c_str());
231}
232
Herb Derby49253642019-02-11 14:20:31 -0500233void SkStrike::onAboutToExitScope() { }
234
reed@google.com09837012012-04-23 15:04:44 +0000235#ifdef SK_DEBUG
Herb Derby5fd955e2019-01-16 11:23:29 -0500236void SkStrike::forceValidate() const {
Khushalb2e71272018-05-15 12:59:48 -0700237 size_t memoryUsed = sizeof(*this);
Herb Derbye46ccf82019-01-09 11:22:00 -0500238 fGlyphMap.foreach ([&memoryUsed](const SkGlyph* glyphPtr) {
Khushalb2e71272018-05-15 12:59:48 -0700239 memoryUsed += sizeof(SkGlyph);
Herb Derby793818b2019-06-25 17:10:11 -0400240 if (glyphPtr->setImageHasBeenCalled()) {
Herb Derby9b06f212019-06-21 14:25:47 -0400241 memoryUsed += glyphPtr->imageSize();
Khushalb2e71272018-05-15 12:59:48 -0700242 }
Herb Derbyf0e75812019-06-12 11:14:50 -0400243 if (glyphPtr->setPathHasBeenCalled() && glyphPtr->path() != nullptr) {
244 memoryUsed += glyphPtr->path()->approximateBytesUsed();
Khushalb2e71272018-05-15 12:59:48 -0700245 }
246 });
247 SkASSERT(fMemoryUsed == memoryUsed);
248}
reed@google.combaed71f2013-09-26 19:28:27 +0000249
Herb Derby5fd955e2019-01-16 11:23:29 -0500250void SkStrike::validate() const {
djsollen@google.com000dea72012-11-30 16:19:32 +0000251#ifdef SK_DEBUG_GLYPH_CACHE
Khushalb2e71272018-05-15 12:59:48 -0700252 forceValidate();
djsollen@google.com000dea72012-11-30 16:19:32 +0000253#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000254}
Herb Derbye8d2d012019-03-11 17:22:47 -0400255#endif // SK_DEBUG
reed@google.com09837012012-04-23 15:04:44 +0000256
reed@google.com09837012012-04-23 15:04:44 +0000257