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 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 22 GrStrikeCache::~GrStrikeCache() { 23 StrikeHash::Iter iter(&fCache); 24 while (!iter.done()) { 25 (*iter).fIsAbandoned = true; 26 (*iter).unref(); 27 ++iter; 28 } 29 } 30 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 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> 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 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 172 GrTextStrike::GrTextStrike(const SkDescriptor& key) 173 : fFontScalerKey(key) {} 174 175 GrGlyph* GrTextStrike::generateGlyph(const SkGlyph& skGlyph) { 176 GrGlyph* grGlyph = fAlloc.make<GrGlyph>(skGlyph); 177 fCache.add(grGlyph); 178 return grGlyph; 179 } 180 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 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