Chromium Code Reviews| 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 |