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/SkArenaAlloc.h"
15 #include "src/core/SkAutoMalloc.h"
16 #include "src/core/SkDistanceFieldGen.h"
17 #include "src/core/SkStrikeSpec.h"
18 #include "src/gpu/text/GrStrikeCache.h"
19 
~GrStrikeCache()20 GrStrikeCache::~GrStrikeCache() {
21     this->freeAll();
22 }
23 
freeAll()24 void GrStrikeCache::freeAll() {
25     fCache.reset();
26 }
27 
28 // expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
29 // A8, RGB565, or RGBA8888.
30 template <typename INT_TYPE>
expand_bits(INT_TYPE * dst,const uint8_t * src,int width,int height,int dstRowBytes,int srcRowBytes)31 static void expand_bits(INT_TYPE* dst,
32                         const uint8_t* src,
33                         int width,
34                         int height,
35                         int dstRowBytes,
36                         int srcRowBytes) {
37     for (int i = 0; i < height; ++i) {
38         int rowWritesLeft = width;
39         const uint8_t* s = src;
40         INT_TYPE* d = dst;
41         while (rowWritesLeft > 0) {
42             unsigned mask = *s++;
43             for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
44                 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
45             }
46         }
47         dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
48         src += srcRowBytes;
49     }
50 }
51 
get_packed_glyph_image(const SkGlyph & glyph,int dstRB,GrMaskFormat expectedMaskFormat,void * dst)52 static void get_packed_glyph_image(
53         const SkGlyph& glyph, int dstRB, GrMaskFormat expectedMaskFormat, void* dst) {
54     const int width = glyph.width();
55     const int height = glyph.height();
56     const void* src = glyph.image();
57     SkASSERT(src != nullptr);
58 
59     GrMaskFormat grMaskFormat = GrGlyph::FormatFromSkGlyph(glyph.maskFormat());
60     if (grMaskFormat == expectedMaskFormat) {
61         int srcRB = glyph.rowBytes();
62         // Notice this comparison is with the glyphs raw mask format, and not its GrMaskFormat.
63         if (glyph.maskFormat() != SkMask::kBW_Format) {
64             if (srcRB != dstRB) {
65                 const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
66                 for (int y = 0; y < height; y++) {
67                     memcpy(dst, src, width * bbp);
68                     src = (const char*) src + srcRB;
69                     dst = (char*) dst + dstRB;
70                 }
71             } else {
72                 memcpy(dst, src, dstRB * height);
73             }
74         } else {
75             // Handle 8-bit format by expanding the mask to the expected format.
76             const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
77             switch (expectedMaskFormat) {
78                 case kA8_GrMaskFormat: {
79                     uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
80                     expand_bits(bytes, bits, width, height, dstRB, srcRB);
81                     break;
82                 }
83                 case kA565_GrMaskFormat: {
84                     uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
85                     expand_bits(rgb565, bits, width, height, dstRB, srcRB);
86                     break;
87                 }
88                 default:
89                     SK_ABORT("Invalid GrMaskFormat");
90             }
91         }
92     } else if (grMaskFormat == kA565_GrMaskFormat && expectedMaskFormat == kARGB_GrMaskFormat) {
93         // Convert if the glyph uses a 565 mask format since it is using LCD text rendering
94         // but the expected format is 8888 (will happen on macOS with Metal since that
95         // combination does not support 565).
96         static constexpr SkMasks masks{
97                 {0b1111'1000'0000'0000, 11, 5},  // Red
98                 {0b0000'0111'1110'0000,  5, 6},  // Green
99                 {0b0000'0000'0001'1111,  0, 5},  // Blue
100                 {0, 0, 0}                        // Alpha
101         };
102         const int a565Bpp = GrMaskFormatBytesPerPixel(kA565_GrMaskFormat);
103         const int argbBpp = GrMaskFormatBytesPerPixel(kARGB_GrMaskFormat);
104         for (int y = 0; y < height; y++) {
105             for (int x = 0; x < width; x++) {
106                 uint16_t color565 = 0;
107                 memcpy(&color565, src, a565Bpp);
108                 uint32_t colorRGBA = GrColorPackRGBA(masks.getRed(color565),
109                                                      masks.getGreen(color565),
110                                                      masks.getBlue(color565),
111                                                      0xFF);
112                 memcpy(dst, &colorRGBA, argbBpp);
113                 src = (char*)src + a565Bpp;
114                 dst = (char*)dst + argbBpp;
115             }
116         }
117     } else {
118         // crbug:510931
119         // Retrieving the image from the cache can actually change the mask format. This case is
120         // very uncommon so for now we just draw a clear box for these glyphs.
121         const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
122         for (int y = 0; y < height; y++) {
123             sk_bzero(dst, width * bpp);
124             dst = (char*)dst + dstRB;
125         }
126     }
127 }
128 
129 ///////////////////////////////////////////////////////////////////////////////
130 
131 /*
132     The text strike is specific to a given font/style/matrix setup, which is
133     represented by the GrHostFontScaler object we are given in getGlyph().
134 
135     We map a 32bit glyphID to a GrGlyph record, which in turn points to a
136     atlas and a position within that texture.
137  */
138 
GrTextStrike(const SkDescriptor & key)139 GrTextStrike::GrTextStrike(const SkDescriptor& key)
140     : fFontScalerKey(key) {}
141 
addGlyphToAtlas(const SkGlyph & skGlyph,GrMaskFormat expectedMaskFormat,bool isScaledGlyph,GrResourceProvider * resourceProvider,GrDeferredUploadTarget * target,GrAtlasManager * fullAtlasManager,GrGlyph * grGlyph)142 GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(const SkGlyph& skGlyph,
143                                                        GrMaskFormat expectedMaskFormat,
144                                                        bool isScaledGlyph,
145                                                        GrResourceProvider* resourceProvider,
146                                                        GrDeferredUploadTarget* target,
147                                                        GrAtlasManager* fullAtlasManager,
148                                                        GrGlyph* grGlyph) {
149     SkASSERT(grGlyph != nullptr);
150     SkASSERT(fCache.findOrNull(grGlyph->fPackedID));
151     SkASSERT(grGlyph->width() == skGlyph.width());
152     SkASSERT(grGlyph->height() == skGlyph.height());
153     SkASSERT(skGlyph.image() != nullptr);
154 
155     expectedMaskFormat = fullAtlasManager->resolveMaskFormat(expectedMaskFormat);
156     int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
157 
158     bool isSDFGlyph = skGlyph.maskFormat() == SkMask::kSDF_Format;
159     // Add 1 pixel padding around grGlyph if needed.
160     bool addPad = isScaledGlyph && !isSDFGlyph;
161     const int width = addPad ? skGlyph.width() + 2 : skGlyph.width();
162     const int height = addPad ? skGlyph.height() + 2 : skGlyph.height();
163     int rowBytes = width * bytesPerPixel;
164     size_t size = height * rowBytes;
165 
166     // Temporary storage for normalizing grGlyph image.
167     SkAutoSMalloc<1024> storage(size);
168     void* dataPtr = storage.get();
169     if (addPad) {
170         sk_bzero(dataPtr, size);
171         // Advance in one row and one column.
172         dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
173     }
174 
175     get_packed_glyph_image(skGlyph, rowBytes, expectedMaskFormat, dataPtr);
176 
177     GrDrawOpAtlas::ErrorCode result = fullAtlasManager->addToAtlas(
178             resourceProvider, &grGlyph->fPlotLocator, target, expectedMaskFormat,
179             width, height,
180             storage.get(), &grGlyph->fAtlasLocation);
181     if (GrDrawOpAtlas::ErrorCode::kSucceeded == result) {
182         if (addPad) {
183             grGlyph->fAtlasLocation.fX += 1;
184             grGlyph->fAtlasLocation.fY += 1;
185         }
186         SkASSERT(grGlyph->fPlotLocator != GrDrawOpAtlas::kInvalidPlotLocator);
187     }
188     return result;
189 }
190 
getGlyph(const SkGlyph & skGlyph)191 GrGlyph* GrTextStrike::getGlyph(const SkGlyph& skGlyph) {
192     GrGlyph* grGlyph = fCache.findOrNull(skGlyph.getPackedID());
193     if (grGlyph == nullptr) {
194         grGlyph = fAlloc.make<GrGlyph>(skGlyph);
195         fCache.set(grGlyph);
196     }
197     return grGlyph;
198 }
199 
200