static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, int width, int height, int dstRB, GrMaskFormat expectedMaskFormat, void* dst) { SkASSERT(glyph.fWidth == width); SkASSERT(glyph.fHeight == height); const void* src = cache->findImage(glyph); if (nullptr == src) { return false; } // crbug:510931 // Retrieving the image from the cache can actually change the mask format. This case is very // uncommon so for now we just draw a clear box for these glyphs. if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) { const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat); for (int y = 0; y < height; y++) { sk_bzero(dst, width * bpp); dst = (char*)dst + dstRB; } return true; } int srcRB = glyph.rowBytes(); // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to // check the glyph's format, not the strike's format, and to be able to convert to any of the // GrMaskFormats. if (SkMask::kBW_Format == glyph.fMaskFormat) { // expand bits to our mask type const uint8_t* bits = reinterpret_cast<const uint8_t*>(src); switch (expectedMaskFormat) { case kA8_GrMaskFormat:{ uint8_t* bytes = reinterpret_cast<uint8_t*>(dst); expand_bits(bytes, bits, width, height, dstRB, srcRB); break; } case kA565_GrMaskFormat: { uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst); expand_bits(rgb565, bits, width, height, dstRB, srcRB); break; } default: SkFAIL("Invalid GrMaskFormat"); } } else if (srcRB == dstRB) { memcpy(dst, src, dstRB * height); } else { const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat); for (int y = 0; y < height; y++) { memcpy(dst, src, width * bbp); src = (const char*)src + srcRB; dst = (char*)dst + dstRB; } } return true; }
bool GrAtlas::addSubImage(int width, int height, const void* image, GrIPoint16* loc) { if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { return false; } GrAutoSMalloc<1024> storage; int dstW = width + 2*BORDER; int dstH = height + 2*BORDER; if (BORDER) { const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat); const size_t dstRB = dstW * bpp; uint8_t* dst = (uint8_t*)storage.realloc(dstH * dstRB); Gr_bzero(dst, dstRB); // zero top row dst += dstRB; for (int y = 0; y < height; y++) { dst = zerofill(dst, bpp); // zero left edge memcpy(dst, image, width * bpp); dst += width * bpp; dst = zerofill(dst, bpp); // zero right edge image = (const void*)((const char*)image + width * bpp); } Gr_bzero(dst, dstRB); // zero bottom row image = storage.get(); } adjustForPlot(loc, fPlot); fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image); // now tell the caller to skip the top/left BORDER loc->fX += BORDER; loc->fY += BORDER; return true; }
bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed, int width, int height, int dstRB, void* dst) { const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed), GrGlyph::UnpackFixedX(packed), GrGlyph::UnpackFixedY(packed)); GrAssert(glyph.fWidth == width); GrAssert(glyph.fHeight == height); const void* src = fStrike->findImage(glyph); if (NULL == src) { return false; } int srcRB = glyph.rowBytes(); if (SkMask::kBW_Format == fStrike->getMaskFormat()) { // expand bits to bytes const uint8_t* bits = reinterpret_cast<const uint8_t*>(src); uint8_t* bytes = reinterpret_cast<uint8_t*>(dst); for (int y = 0; y < height; y++) { bits_to_bytes(bits, bytes, width); bits += srcRB; bytes += dstRB; } } else if (srcRB == dstRB) { memcpy(dst, src, dstRB * height); } else { const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat()); for (int y = 0; y < height; y++) { memcpy(dst, src, width * bbp); src = (const char*)src + srcRB; dst = (char*)dst + dstRB; } } return true; }
bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed, int width, int height, int dstRB, void* dst) { const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed), GrGlyph::UnpackFixedX(packed), GrGlyph::UnpackFixedY(packed)); SkASSERT(glyph.fWidth == width); SkASSERT(glyph.fHeight == height); const void* src = fStrike->findImage(glyph); if (NULL == src) { return false; } int srcRB = glyph.rowBytes(); // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to // check the glyph's format, not the strike's format, and to be able to convert to any of the // GrMaskFormats. if (SkMask::kBW_Format == glyph.fMaskFormat) { // expand bits to our mask type const uint8_t* bits = reinterpret_cast<const uint8_t*>(src); switch (this->getMaskFormat()) { case kA8_GrMaskFormat: { uint8_t* bytes = reinterpret_cast<uint8_t*>(dst); expand_bits(bytes, bits, width, height, dstRB, srcRB); break; } case kA565_GrMaskFormat: { uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst); expand_bits(rgb565, bits, width, height, dstRB, srcRB); break; } case kA888_GrMaskFormat: { uint32_t* rgba8888 = reinterpret_cast<uint32_t*>(dst); expand_bits(rgba8888, bits, width, height, dstRB, srcRB); break; } default: GrCrash("Invalid GrMaskFormat"); } } else if (srcRB == dstRB) { memcpy(dst, src, dstRB * height); } else { const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat()); for (int y = 0; y < height; y++) { memcpy(dst, src, width * bbp); src = (const char*)src + srcRB; dst = (char*)dst + dstRB; } } return true; }
bool GrAtlas::addSubImage(int width, int height, const void* image, GrIPoint16* loc) { if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { return false; } SkAutoSMalloc<1024> storage; int dstW = width + 2*BORDER; int dstH = height + 2*BORDER; if (BORDER) { const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat); const size_t dstRB = dstW * bpp; uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB); Gr_bzero(dst, dstRB); // zero top row dst += dstRB; for (int y = 0; y < height; y++) { dst = zerofill(dst, bpp); // zero left edge memcpy(dst, image, width * bpp); dst += width * bpp; dst = zerofill(dst, bpp); // zero right edge image = (const void*)((const char*)image + width * bpp); } Gr_bzero(dst, dstRB); // zero bottom row image = storage.get(); } adjustForPlot(loc, fPlot); GrContext* context = fTexture->getContext(); // We pass the flag that does not force a flush. We assume our caller is // smart and hasn't referenced the part of the texture we're about to update // since the last flush. context->writeTexturePixels(fTexture, loc->fX, loc->fY, dstW, dstH, fTexture->config(), image, 0, GrContext::kDontFlush_PixelOpsFlag); // now tell the caller to skip the top/left BORDER loc->fX += BORDER; loc->fY += BORDER; #if FONT_CACHE_STATS ++g_UploadCount; #endif return true; }
bool GrTextStrike::addGlyphToAtlas(GrGlyph* glyph, GrFontScaler* scaler) { #if 0 // testing hack to force us to flush our cache often static int gCounter; if ((++gCounter % 10) == 0) return false; #endif SkASSERT(glyph); SkASSERT(scaler); SkASSERT(fCache.find(glyph->fPackedID)); SkASSERT(NULL == glyph->fPlot); SkAutoUnref ar(SkSafeRef(scaler)); int bytesPerPixel = GrMaskFormatBytesPerPixel(glyph->fMaskFormat); size_t size = glyph->fBounds.area() * bytesPerPixel; GrAutoMalloc<1024> storage(size); if (fUseDistanceField) { if (!scaler->getPackedGlyphDFImage(glyph->fPackedID, glyph->width(), glyph->height(), storage.get())) { return false; } } else { if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(), glyph->height(), glyph->width() * bytesPerPixel, storage.get())) { return false; } } GrPlot* plot = fFontCache->addToAtlas(glyph->fMaskFormat, &fPlotUsage, glyph->width(), glyph->height(), storage.get(), &glyph->fAtlasLocation); if (NULL == plot) { return false; } glyph->fPlot = plot; return true; }
bool GrBatchTextStrike::addGlyphToAtlas(GrDrawBatch::Target* target, GrGlyph* glyph, GrFontScaler* scaler, GrMaskFormat expectedMaskFormat) { SkASSERT(glyph); SkASSERT(scaler); SkASSERT(fCache.find(glyph->fPackedID)); SkAutoUnref ar(SkSafeRef(scaler)); int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); size_t size = glyph->fBounds.area() * bytesPerPixel; SkAutoSMalloc<1024> storage(size); const SkGlyph& skGlyph = scaler->grToSkGlyph(glyph->fPackedID); if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) { if (!scaler->getPackedGlyphDFImage(skGlyph, glyph->width(), glyph->height(), storage.get())) { return false; } } else { if (!scaler->getPackedGlyphImage(skGlyph, glyph->width(), glyph->height(), glyph->width() * bytesPerPixel, expectedMaskFormat, storage.get())) { return false; } } bool success = fBatchFontCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat, glyph->width(), glyph->height(), storage.get(), &glyph->fAtlasLocation); if (success) { SkASSERT(GrBatchAtlas::kInvalidAtlasID != glyph->fID); fAtlasedGlyphs++; } return success; }
bool GrBatchTextStrike::addGlyphToAtlas(GrBatchTarget* batchTarget, GrGlyph* glyph, GrFontScaler* scaler) { SkASSERT(glyph); SkASSERT(scaler); SkASSERT(fCache.find(glyph->fPackedID)); SkASSERT(NULL == glyph->fPlot); SkAutoUnref ar(SkSafeRef(scaler)); int bytesPerPixel = GrMaskFormatBytesPerPixel(glyph->fMaskFormat); size_t size = glyph->fBounds.area() * bytesPerPixel; GrAutoMalloc<1024> storage(size); if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) { if (!scaler->getPackedGlyphDFImage(glyph->fPackedID, glyph->width(), glyph->height(), storage.get())) { return false; } } else { if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(), glyph->height(), glyph->width() * bytesPerPixel, storage.get())) { return false; } } bool success = fBatchFontCache->addToAtlas(this, &glyph->fID, batchTarget, glyph->fMaskFormat, glyph->width(), glyph->height(), storage.get(), &glyph->fAtlasLocation); if (success) { fAtlasedGlyphs++; } return success; }
bool GrAtlasTextStrike::addGlyphToAtlas(GrDrawOp::Target* target, GrGlyph* glyph, SkGlyphCache* cache, GrMaskFormat expectedMaskFormat) { SkASSERT(glyph); SkASSERT(cache); SkASSERT(fCache.find(glyph->fPackedID)); int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); size_t size = glyph->fBounds.area() * bytesPerPixel; SkAutoSMalloc<1024> storage(size); const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID); if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) { if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(), storage.get())) { return false; } } else { if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(), glyph->width() * bytesPerPixel, expectedMaskFormat, storage.get())) { return false; } } bool success = fAtlasGlyphCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat, glyph->width(), glyph->height(), storage.get(), &glyph->fAtlasLocation); if (success) { SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID); fAtlasedGlyphs++; } return success; }