OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrBatchFontCache.h" | 8 #include "GrBatchFontCache.h" |
9 #include "GrContext.h" | 9 #include "GrContext.h" |
10 #include "GrGpu.h" | 10 #include "GrGpu.h" |
11 #include "GrRectanizer.h" | 11 #include "GrRectanizer.h" |
12 #include "GrResourceProvider.h" | 12 #include "GrResourceProvider.h" |
13 #include "GrSurfacePriv.h" | 13 #include "GrSurfacePriv.h" |
14 #include "SkString.h" | 14 #include "SkString.h" |
15 | 15 |
16 #include "SkDistanceFieldGen.h" | 16 #include "SkDistanceFieldGen.h" |
17 | 17 |
18 /////////////////////////////////////////////////////////////////////////////// | |
19 | |
20 bool GrBatchFontCache::initAtlas(GrMaskFormat format) { | 18 bool GrBatchFontCache::initAtlas(GrMaskFormat format) { |
21 int index = MaskFormatToAtlasIndex(format); | 19 int index = MaskFormatToAtlasIndex(format); |
22 if (!fAtlases[index]) { | 20 if (!fAtlases[index]) { |
23 GrPixelConfig config = MaskFormatToPixelConfig(format); | 21 GrPixelConfig config = MaskFormatToPixelConfig(format); |
24 int width = fAtlasConfigs[index].fWidth; | 22 int width = fAtlasConfigs[index].fWidth; |
25 int height = fAtlasConfigs[index].fHeight; | 23 int height = fAtlasConfigs[index].fHeight; |
26 int numPlotsX = fAtlasConfigs[index].numPlotsX(); | 24 int numPlotsX = fAtlasConfigs[index].numPlotsX(); |
27 int numPlotsY = fAtlasConfigs[index].numPlotsY(); | 25 int numPlotsY = fAtlasConfigs[index].numPlotsY(); |
28 | 26 |
29 fAtlases[index] = | 27 fAtlases[index] = |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 if (fAtlases[i]) { | 136 if (fAtlases[i]) { |
139 delete fAtlases[i]; | 137 delete fAtlases[i]; |
140 fAtlases[i] = nullptr; | 138 fAtlases[i] = nullptr; |
141 } | 139 } |
142 } | 140 } |
143 memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs)); | 141 memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs)); |
144 } | 142 } |
145 | 143 |
146 /////////////////////////////////////////////////////////////////////////////// | 144 /////////////////////////////////////////////////////////////////////////////// |
147 | 145 |
146 static inline GrMaskFormat get_packed_glyph_mask_format(const SkGlyph& glyph) { | |
bsalomon
2016/05/17 19:11:04
This code is from GrFontScaler.cpp. Copied, pasted
| |
147 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat); | |
148 switch (format) { | |
149 case SkMask::kBW_Format: | |
150 // fall through to kA8 -- we store BW glyphs in our 8-bit cache | |
151 case SkMask::kA8_Format: | |
152 return kA8_GrMaskFormat; | |
153 case SkMask::kLCD16_Format: | |
154 return kA565_GrMaskFormat; | |
155 case SkMask::kARGB32_Format: | |
156 return kARGB_GrMaskFormat; | |
157 default: | |
158 SkDEBUGFAIL("unsupported SkMask::Format"); | |
159 return kA8_GrMaskFormat; | |
160 } | |
161 } | |
162 | |
163 static inline bool get_packed_glyph_bounds(SkGlyphCache* cache, const SkGlyph& g lyph, | |
164 SkIRect* bounds) { | |
165 #if 1 | |
166 // crbug:510931 | |
167 // Retrieving the image from the cache can actually change the mask format. | |
168 cache->findImage(glyph); | |
169 #endif | |
170 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight); | |
171 | |
172 return true; | |
173 } | |
174 | |
175 static inline bool get_packed_glyph_df_bounds(SkGlyphCache* cache, const SkGlyph & glyph, | |
176 SkIRect* bounds) { | |
177 #if 1 | |
178 // crbug:510931 | |
179 // Retrieving the image from the cache can actually change the mask format. | |
180 cache->findImage(glyph); | |
181 #endif | |
182 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight); | |
183 bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | |
184 | |
185 return true; | |
186 } | |
187 | |
188 // expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a B W glyph mask to | |
189 // A8, RGB565, or RGBA8888. | |
190 template <typename INT_TYPE> | |
191 static void expand_bits(INT_TYPE* dst, | |
192 const uint8_t* src, | |
193 int width, | |
194 int height, | |
195 int dstRowBytes, | |
196 int srcRowBytes) { | |
197 for (int i = 0; i < height; ++i) { | |
198 int rowWritesLeft = width; | |
199 const uint8_t* s = src; | |
200 INT_TYPE* d = dst; | |
201 while (rowWritesLeft > 0) { | |
202 unsigned mask = *s++; | |
203 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) { | |
204 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0; | |
205 } | |
206 } | |
207 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstR owBytes); | |
208 src += srcRowBytes; | |
209 } | |
210 } | |
211 | |
212 static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, in t width, | |
213 int height, int dstRB, GrMaskFormat expectedM askFormat, | |
214 void* dst) { | |
215 SkASSERT(glyph.fWidth == width); | |
216 SkASSERT(glyph.fHeight == height); | |
217 const void* src = cache->findImage(glyph); | |
218 if (nullptr == src) { | |
219 return false; | |
220 } | |
221 | |
222 // crbug:510931 | |
223 // Retrieving the image from the cache can actually change the mask format. This case is very | |
224 // uncommon so for now we just draw a clear box for these glyphs. | |
225 if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) { | |
226 const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat); | |
227 for (int y = 0; y < height; y++) { | |
228 sk_bzero(dst, width * bpp); | |
229 dst = (char*)dst + dstRB; | |
230 } | |
231 return true; | |
232 } | |
233 | |
234 int srcRB = glyph.rowBytes(); | |
235 // The windows font host sometimes has BW glyphs in a non-BW strike. So it i s important here to | |
236 // check the glyph's format, not the strike's format, and to be able to conv ert to any of the | |
237 // GrMaskFormats. | |
238 if (SkMask::kBW_Format == glyph.fMaskFormat) { | |
239 // expand bits to our mask type | |
240 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src); | |
241 switch (expectedMaskFormat) { | |
242 case kA8_GrMaskFormat:{ | |
243 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst); | |
244 expand_bits(bytes, bits, width, height, dstRB, srcRB); | |
245 break; | |
246 } | |
247 case kA565_GrMaskFormat: { | |
248 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst); | |
249 expand_bits(rgb565, bits, width, height, dstRB, srcRB); | |
250 break; | |
251 } | |
252 default: | |
253 SkFAIL("Invalid GrMaskFormat"); | |
254 } | |
255 } else if (srcRB == dstRB) { | |
256 memcpy(dst, src, dstRB * height); | |
257 } else { | |
258 const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat); | |
259 for (int y = 0; y < height; y++) { | |
260 memcpy(dst, src, width * bbp); | |
261 src = (const char*)src + srcRB; | |
262 dst = (char*)dst + dstRB; | |
263 } | |
264 } | |
265 return true; | |
266 } | |
267 | |
268 static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph, | |
269 int width, int height, void* dst) { | |
270 SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width); | |
271 SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height); | |
272 const void* image = cache->findImage(glyph); | |
273 if (nullptr == image) { | |
274 return false; | |
275 } | |
276 // now generate the distance field | |
277 SkASSERT(dst); | |
278 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); | |
279 if (SkMask::kA8_Format == maskFormat) { | |
280 // make the distance field from the image | |
281 SkGenerateDistanceFieldFromA8Image((unsigned char*)dst, | |
282 (unsigned char*)image, | |
283 glyph.fWidth, glyph.fHeight, | |
284 glyph.rowBytes()); | |
285 } else if (SkMask::kBW_Format == maskFormat) { | |
286 // make the distance field from the image | |
287 SkGenerateDistanceFieldFromBWImage((unsigned char*)dst, | |
288 (unsigned char*)image, | |
289 glyph.fWidth, glyph.fHeight, | |
290 glyph.rowBytes()); | |
291 } else { | |
292 return false; | |
293 } | |
294 | |
295 return true; | |
296 } | |
297 | |
298 /////////////////////////////////////////////////////////////////////////////// | |
299 | |
148 /* | 300 /* |
149 The text strike is specific to a given font/style/matrix setup, which is | 301 The text strike is specific to a given font/style/matrix setup, which is |
150 represented by the GrHostFontScaler object we are given in getGlyph(). | 302 represented by the GrHostFontScaler object we are given in getGlyph(). |
151 | 303 |
152 We map a 32bit glyphID to a GrGlyph record, which in turn points to a | 304 We map a 32bit glyphID to a GrGlyph record, which in turn points to a |
153 atlas and a position within that texture. | 305 atlas and a position within that texture. |
154 */ | 306 */ |
155 | 307 |
156 GrBatchTextStrike::GrBatchTextStrike(GrBatchFontCache* owner, const SkDescriptor & key) | 308 GrBatchTextStrike::GrBatchTextStrike(GrBatchFontCache* owner, const SkDescriptor & key) |
157 : fFontScalerKey(key) | 309 : fFontScalerKey(key) |
158 , fPool(9/*start allocations at 512 bytes*/) | 310 , fPool(9/*start allocations at 512 bytes*/) |
159 , fBatchFontCache(owner) // no need to ref, it won't go away before we do | 311 , fBatchFontCache(owner) // no need to ref, it won't go away before we do |
160 , fAtlasedGlyphs(0) | 312 , fAtlasedGlyphs(0) |
161 , fIsAbandoned(false) {} | 313 , fIsAbandoned(false) {} |
162 | 314 |
163 GrBatchTextStrike::~GrBatchTextStrike() { | 315 GrBatchTextStrike::~GrBatchTextStrike() { |
164 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache); | 316 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache); |
165 while (!iter.done()) { | 317 while (!iter.done()) { |
166 (*iter).reset(); | 318 (*iter).reset(); |
167 ++iter; | 319 ++iter; |
168 } | 320 } |
169 } | 321 } |
170 | 322 |
171 GrGlyph* GrBatchTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::Packe dID packed, | 323 GrGlyph* GrBatchTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::Packe dID packed, |
172 GrFontScaler* scaler) { | 324 SkGlyphCache* cache) { |
173 SkIRect bounds; | 325 SkIRect bounds; |
174 if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) { | 326 if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) { |
175 if (!scaler->getPackedGlyphDFBounds(skGlyph, &bounds)) { | 327 if (!get_packed_glyph_df_bounds(cache, skGlyph, &bounds)) { |
176 return nullptr; | 328 return nullptr; |
177 } | 329 } |
178 } else { | 330 } else { |
179 if (!scaler->getPackedGlyphBounds(skGlyph, &bounds)) { | 331 if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) { |
180 return nullptr; | 332 return nullptr; |
181 } | 333 } |
182 } | 334 } |
183 GrMaskFormat format = scaler->getPackedGlyphMaskFormat(skGlyph); | 335 GrMaskFormat format = get_packed_glyph_mask_format(skGlyph); |
184 | 336 |
185 GrGlyph* glyph = (GrGlyph*)fPool.alloc(sizeof(GrGlyph)); | 337 GrGlyph* glyph = (GrGlyph*)fPool.alloc(sizeof(GrGlyph)); |
186 glyph->init(packed, bounds, format); | 338 glyph->init(packed, bounds, format); |
187 fCache.add(glyph); | 339 fCache.add(glyph); |
188 return glyph; | 340 return glyph; |
189 } | 341 } |
190 | 342 |
191 void GrBatchTextStrike::removeID(GrBatchAtlas::AtlasID id) { | 343 void GrBatchTextStrike::removeID(GrBatchAtlas::AtlasID id) { |
192 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache); | 344 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache); |
193 while (!iter.done()) { | 345 while (!iter.done()) { |
194 if (id == (*iter).fID) { | 346 if (id == (*iter).fID) { |
195 (*iter).fID = GrBatchAtlas::kInvalidAtlasID; | 347 (*iter).fID = GrBatchAtlas::kInvalidAtlasID; |
196 fAtlasedGlyphs--; | 348 fAtlasedGlyphs--; |
197 SkASSERT(fAtlasedGlyphs >= 0); | 349 SkASSERT(fAtlasedGlyphs >= 0); |
198 } | 350 } |
199 ++iter; | 351 ++iter; |
200 } | 352 } |
201 } | 353 } |
202 | 354 |
203 bool GrBatchTextStrike::addGlyphToAtlas(GrDrawBatch::Target* target, | 355 bool GrBatchTextStrike::addGlyphToAtlas(GrDrawBatch::Target* target, |
204 GrGlyph* glyph, | 356 GrGlyph* glyph, |
205 GrFontScaler* scaler, | 357 SkGlyphCache* cache, |
206 GrMaskFormat expectedMaskFormat) { | 358 GrMaskFormat expectedMaskFormat) { |
207 SkASSERT(glyph); | 359 SkASSERT(glyph); |
208 SkASSERT(scaler); | 360 SkASSERT(cache); |
209 SkASSERT(fCache.find(glyph->fPackedID)); | 361 SkASSERT(fCache.find(glyph->fPackedID)); |
210 | 362 |
211 int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); | 363 int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); |
212 | 364 |
213 size_t size = glyph->fBounds.area() * bytesPerPixel; | 365 size_t size = glyph->fBounds.area() * bytesPerPixel; |
214 SkAutoSMalloc<1024> storage(size); | 366 SkAutoSMalloc<1024> storage(size); |
215 | 367 |
216 const SkGlyph& skGlyph = scaler->grToSkGlyph(glyph->fPackedID); | 368 const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID); |
217 if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedI D)) { | 369 if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedI D)) { |
218 if (!scaler->getPackedGlyphDFImage(skGlyph, glyph->width(), glyph->heigh t(), | 370 if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->he ight(), |
219 storage.get())) { | 371 storage.get())) { |
220 return false; | 372 return false; |
221 } | 373 } |
222 } else { | 374 } else { |
223 if (!scaler->getPackedGlyphImage(skGlyph, glyph->width(), glyph->height( ), | 375 if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->heigh t(), |
224 glyph->width() * bytesPerPixel, expecte dMaskFormat, | 376 glyph->width() * bytesPerPixel, expectedMask Format, |
225 storage.get())) { | 377 storage.get())) { |
226 return false; | 378 return false; |
227 } | 379 } |
228 } | 380 } |
229 | 381 |
230 bool success = fBatchFontCache->addToAtlas(this, &glyph->fID, target, expect edMaskFormat, | 382 bool success = fBatchFontCache->addToAtlas(this, &glyph->fID, target, expect edMaskFormat, |
231 glyph->width(), glyph->height(), | 383 glyph->width(), glyph->height(), |
232 storage.get(), &glyph->fAtlasLoca tion); | 384 storage.get(), &glyph->fAtlasLoca tion); |
233 if (success) { | 385 if (success) { |
234 SkASSERT(GrBatchAtlas::kInvalidAtlasID != glyph->fID); | 386 SkASSERT(GrBatchAtlas::kInvalidAtlasID != glyph->fID); |
235 fAtlasedGlyphs++; | 387 fAtlasedGlyphs++; |
236 } | 388 } |
237 return success; | 389 return success; |
238 } | 390 } |
OLD | NEW |