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 "src/gpu/GrCaps.h"
9 #include "src/gpu/GrColor.h"
10 #include "src/gpu/GrDistanceFieldGenFromVector.h"
11 #include "src/gpu/text/GrAtlasManager.h"
12 #include "src/gpu/text/GrStrikeCache.h"
13
14 #include "src/core/SkAutoMalloc.h"
15 #include "src/core/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))) { }
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* grStrikeCache = reinterpret_cast<GrStrikeCache*>(ptr);
43
44 StrikeHash::Iter iter(&grStrikeCache->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 != grStrikeCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) {
52 grStrikeCache->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,SkGlyph * glyph,int width,int height,int dstRB,GrMaskFormat expectedMaskFormat,void * dst,const SkMasks & masks)83 static bool get_packed_glyph_image(SkStrike* cache, SkGlyph* glyph, int width,
84 int height, int dstRB, GrMaskFormat expectedMaskFormat,
85 void* dst, const SkMasks& masks) {
86 SkASSERT(glyph->width() == width);
87 SkASSERT(glyph->height() == height);
88 const void* src = cache->prepareImage(glyph);
89 if (src == nullptr) {
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->maskFormat()) &&
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->maskFormat()) != 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 (glyph->maskFormat() == SkMask::kBW_Format) {
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
removeID(GrDrawOpAtlas::AtlasID id)175 void GrTextStrike::removeID(GrDrawOpAtlas::AtlasID id) {
176 SkTDynamicHash<GrGlyph, SkPackedGlyphID>::Iter iter(&fCache);
177 while (!iter.done()) {
178 if (id == (*iter).fID) {
179 (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID;
180 fAtlasedGlyphs--;
181 SkASSERT(fAtlasedGlyphs >= 0);
182 }
183 ++iter;
184 }
185 }
186
addGlyphToAtlas(GrResourceProvider * resourceProvider,GrDeferredUploadTarget * target,GrStrikeCache * glyphCache,GrAtlasManager * fullAtlasManager,GrGlyph * glyph,SkStrike * skStrikeCache,GrMaskFormat expectedMaskFormat,bool isScaledGlyph)187 GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(
188 GrResourceProvider* resourceProvider,
189 GrDeferredUploadTarget* target,
190 GrStrikeCache* glyphCache,
191 GrAtlasManager* fullAtlasManager,
192 GrGlyph* glyph,
193 SkStrike* skStrikeCache,
194 GrMaskFormat expectedMaskFormat,
195 bool isScaledGlyph) {
196 SkASSERT(glyph);
197 SkASSERT(skStrikeCache);
198 SkASSERT(fCache.find(glyph->fPackedID));
199
200 expectedMaskFormat = fullAtlasManager->resolveMaskFormat(expectedMaskFormat);
201 int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
202 int width = glyph->width();
203 int height = glyph->height();
204 int rowBytes = width * bytesPerPixel;
205
206 size_t size = glyph->fBounds.area() * bytesPerPixel;
207 bool isSDFGlyph = GrGlyph::kDistance_MaskStyle == glyph->maskStyle();
208 bool addPad = isScaledGlyph && !isSDFGlyph;
209 if (addPad) {
210 width += 2;
211 rowBytes += 2*bytesPerPixel;
212 size += 2 * rowBytes;
213 height += 2;
214 size += 2 * (height + 2) * bytesPerPixel;
215 }
216 SkAutoSMalloc<1024> storage(size);
217
218 SkGlyph* skGlyph = skStrikeCache->glyph(glyph->fPackedID);
219 void* dataPtr = storage.get();
220 if (addPad) {
221 sk_bzero(dataPtr, size);
222 dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
223 }
224 if (!get_packed_glyph_image(skStrikeCache, skGlyph, glyph->width(), glyph->height(),
225 rowBytes, expectedMaskFormat,
226 dataPtr, glyphCache->getMasks())) {
227 return GrDrawOpAtlas::ErrorCode::kError;
228 }
229
230 GrDrawOpAtlas::ErrorCode result = fullAtlasManager->addToAtlas(
231 resourceProvider, glyphCache, this,
232 &glyph->fID, target, expectedMaskFormat,
233 width, height,
234 storage.get(), &glyph->fAtlasLocation);
235 if (GrDrawOpAtlas::ErrorCode::kSucceeded == result) {
236 if (addPad) {
237 glyph->fAtlasLocation.fX += 1;
238 glyph->fAtlasLocation.fY += 1;
239 }
240 SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
241 fAtlasedGlyphs++;
242 }
243 return result;
244 }
245