1 /*
2 * Copyright 2015 Google Inc.
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
8 #include "GrStrikeCache.h"
9 #include "GrAtlasManager.h"
10 #include "GrCaps.h"
11 #include "GrColor.h"
12 #include "GrDistanceFieldGenFromVector.h"
13
14 #include "SkAutoMalloc.h"
15 #include "SkDistanceFieldGen.h"
16
GrStrikeCache(const GrCaps * caps,size_t maxTextureBytes)17 GrStrikeCache::GrStrikeCache(const GrCaps* caps, size_t maxTextureBytes)
18 : fPreserveStrike(nullptr)
19 , f565Masks(SkMasks::CreateMasks({0xF800, 0x07E0, 0x001F, 0},
20 GrMaskFormatBytesPerPixel(kA565_GrMaskFormat) * 8)) { }
21
~GrStrikeCache()22 GrStrikeCache::~GrStrikeCache() {
23 StrikeHash::Iter iter(&fCache);
24 while (!iter.done()) {
25 (*iter).fIsAbandoned = true;
26 (*iter).unref();
27 ++iter;
28 }
29 }
30
freeAll()31 void GrStrikeCache::freeAll() {
32 StrikeHash::Iter iter(&fCache);
33 while (!iter.done()) {
34 (*iter).fIsAbandoned = true;
35 (*iter).unref();
36 ++iter;
37 }
38 fCache.rewind();
39 }
40
HandleEviction(GrDrawOpAtlas::AtlasID id,void * ptr)41 void GrStrikeCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) {
42 GrStrikeCache* glyphCache = reinterpret_cast<GrStrikeCache*>(ptr);
43
44 StrikeHash::Iter iter(&glyphCache->fCache);
45 for (; !iter.done(); ++iter) {
46 GrTextStrike* strike = &*iter;
47 strike->removeID(id);
48
49 // clear out any empty strikes. We will preserve the strike whose call to addToAtlas
50 // triggered the eviction
51 if (strike != glyphCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) {
52 glyphCache->fCache.remove(GrTextStrike::GetKey(*strike));
53 strike->fIsAbandoned = true;
54 strike->unref();
55 }
56 }
57 }
58
59 // expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
60 // A8, RGB565, or RGBA8888.
61 template <typename INT_TYPE>
expand_bits(INT_TYPE * dst,const uint8_t * src,int width,int height,int dstRowBytes,int srcRowBytes)62 static void expand_bits(INT_TYPE* dst,
63 const uint8_t* src,
64 int width,
65 int height,
66 int dstRowBytes,
67 int srcRowBytes) {
68 for (int i = 0; i < height; ++i) {
69 int rowWritesLeft = width;
70 const uint8_t* s = src;
71 INT_TYPE* d = dst;
72 while (rowWritesLeft > 0) {
73 unsigned mask = *s++;
74 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
75 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
76 }
77 }
78 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
79 src += srcRowBytes;
80 }
81 }
82
get_packed_glyph_image(SkStrike * cache,const SkGlyph & glyph,int width,int height,int dstRB,GrMaskFormat expectedMaskFormat,void * dst,const SkMasks & masks)83 static bool get_packed_glyph_image(SkStrike* cache, const SkGlyph& glyph, int width,
84 int height, int dstRB, GrMaskFormat expectedMaskFormat,
85 void* dst, const SkMasks& masks) {
86 SkASSERT(glyph.fWidth == width);
87 SkASSERT(glyph.fHeight == height);
88 const void* src = cache->findImage(glyph);
89 if (nullptr == src) {
90 return false;
91 }
92
93 // Convert if the glyph uses a 565 mask format since it is using LCD text rendering but the
94 // expected format is 8888 (will happen on macOS with Metal since that combination does not
95 // support 565).
96 if (kA565_GrMaskFormat == GrGlyph::FormatFromSkGlyph(glyph) &&
97 kARGB_GrMaskFormat == expectedMaskFormat) {
98 const int a565Bpp = GrMaskFormatBytesPerPixel(kA565_GrMaskFormat);
99 const int argbBpp = GrMaskFormatBytesPerPixel(kARGB_GrMaskFormat);
100 for (int y = 0; y < height; y++) {
101 for (int x = 0; x < width; x++) {
102 uint16_t color565 = 0;
103 memcpy(&color565, src, a565Bpp);
104 uint32_t colorRGBA = GrColorPackRGBA(masks.getRed(color565),
105 masks.getGreen(color565),
106 masks.getBlue(color565),
107 0xFF);
108 memcpy(dst, &colorRGBA, argbBpp);
109 src = (char*)src + a565Bpp;
110 dst = (char*)dst + argbBpp;
111 }
112 }
113 return true;
114 }
115
116 // crbug:510931
117 // Retrieving the image from the cache can actually change the mask format. This case is very
118 // uncommon so for now we just draw a clear box for these glyphs.
119 if (GrGlyph::FormatFromSkGlyph(glyph) != expectedMaskFormat) {
120 const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
121 for (int y = 0; y < height; y++) {
122 sk_bzero(dst, width * bpp);
123 dst = (char*)dst + dstRB;
124 }
125 return true;
126 }
127
128 int srcRB = glyph.rowBytes();
129 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
130 // check the glyph's format, not the strike's format, and to be able to convert to any of the
131 // GrMaskFormats.
132 if (SkMask::kBW_Format == glyph.fMaskFormat) {
133 // expand bits to our mask type
134 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
135 switch (expectedMaskFormat) {
136 case kA8_GrMaskFormat:{
137 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
138 expand_bits(bytes, bits, width, height, dstRB, srcRB);
139 break;
140 }
141 case kA565_GrMaskFormat: {
142 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
143 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
144 break;
145 }
146 default:
147 SK_ABORT("Invalid GrMaskFormat");
148 }
149 } else if (srcRB == dstRB) {
150 memcpy(dst, src, dstRB * height);
151 } else {
152 const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
153 for (int y = 0; y < height; y++) {
154 memcpy(dst, src, width * bbp);
155 src = (const char*)src + srcRB;
156 dst = (char*)dst + dstRB;
157 }
158 }
159 return true;
160 }
161
162 ///////////////////////////////////////////////////////////////////////////////
163
164 /*
165 The text strike is specific to a given font/style/matrix setup, which is
166 represented by the GrHostFontScaler object we are given in getGlyph().
167
168 We map a 32bit glyphID to a GrGlyph record, which in turn points to a
169 atlas and a position within that texture.
170 */
171
GrTextStrike(const SkDescriptor & key)172 GrTextStrike::GrTextStrike(const SkDescriptor& key)
173 : fFontScalerKey(key) {}
174
generateGlyph(const SkGlyph & skGlyph)175 GrGlyph* GrTextStrike::generateGlyph(const SkGlyph& skGlyph) {
176 GrGlyph* grGlyph = fAlloc.make<GrGlyph>(skGlyph);
177 fCache.add(grGlyph);
178 return grGlyph;
179 }
180
removeID(GrDrawOpAtlas::AtlasID id)181 void GrTextStrike::removeID(GrDrawOpAtlas::AtlasID id) {
182 SkTDynamicHash<GrGlyph, SkPackedGlyphID>::Iter iter(&fCache);
183 while (!iter.done()) {
184 if (id == (*iter).fID) {
185 (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID;
186 fAtlasedGlyphs--;
187 SkASSERT(fAtlasedGlyphs >= 0);
188 }
189 ++iter;
190 }
191 }
192
addGlyphToAtlas(GrResourceProvider * resourceProvider,GrDeferredUploadTarget * target,GrStrikeCache * glyphCache,GrAtlasManager * fullAtlasManager,GrGlyph * glyph,SkStrike * cache,GrMaskFormat expectedMaskFormat,bool isScaledGlyph)193 GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(
194 GrResourceProvider* resourceProvider,
195 GrDeferredUploadTarget* target,
196 GrStrikeCache* glyphCache,
197 GrAtlasManager* fullAtlasManager,
198 GrGlyph* glyph,
199 SkStrike* cache,
200 GrMaskFormat expectedMaskFormat,
201 bool isScaledGlyph) {
202 SkASSERT(glyph);
203 SkASSERT(cache);
204 SkASSERT(fCache.find(glyph->fPackedID));
205
206 expectedMaskFormat = fullAtlasManager->resolveMaskFormat(expectedMaskFormat);
207 int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
208 int width = glyph->width();
209 int height = glyph->height();
210 int rowBytes = width * bytesPerPixel;
211
212 size_t size = glyph->fBounds.area() * bytesPerPixel;
213 bool isSDFGlyph = GrGlyph::kDistance_MaskStyle == glyph->maskStyle();
214 bool addPad = isScaledGlyph && !isSDFGlyph;
215 if (addPad) {
216 width += 2;
217 rowBytes += 2*bytesPerPixel;
218 size += 2 * rowBytes;
219 height += 2;
220 size += 2 * (height + 2) * bytesPerPixel;
221 }
222 SkAutoSMalloc<1024> storage(size);
223
224 const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
225 void* dataPtr = storage.get();
226 if (addPad) {
227 sk_bzero(dataPtr, size);
228 dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
229 }
230 if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
231 rowBytes, expectedMaskFormat,
232 dataPtr, glyphCache->getMasks())) {
233 return GrDrawOpAtlas::ErrorCode::kError;
234 }
235
236 GrDrawOpAtlas::ErrorCode result = fullAtlasManager->addToAtlas(
237 resourceProvider, glyphCache, this,
238 &glyph->fID, target, expectedMaskFormat,
239 width, height,
240 storage.get(), &glyph->fAtlasLocation);
241 if (GrDrawOpAtlas::ErrorCode::kSucceeded == result) {
242 if (addPad) {
243 glyph->fAtlasLocation.fX += 1;
244 glyph->fAtlasLocation.fY += 1;
245 }
246 SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
247 fAtlasedGlyphs++;
248 }
249 return result;
250 }
251