1 
2 /*
3  * Copyright 2010 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 #include "GrFontScaler.h"
10 #include "SkDescriptor.h"
11 #include "SkDistanceFieldGen.h"
12 #include "SkGlyphCache.h"
13 
14 ///////////////////////////////////////////////////////////////////////////////
15 
GrFontScaler(SkGlyphCache * strike)16 GrFontScaler::GrFontScaler(SkGlyphCache* strike) {
17     fStrike = strike;
18     fKey = nullptr;
19 }
20 
~GrFontScaler()21 GrFontScaler::~GrFontScaler() {
22     SkSafeUnref(fKey);
23 }
24 
getMaskFormat() const25 GrMaskFormat GrFontScaler::getMaskFormat() const {
26     SkMask::Format format = fStrike->getMaskFormat();
27     switch (format) {
28         case SkMask::kBW_Format:
29             // fall through to kA8 -- we store BW glyphs in our 8-bit cache
30         case SkMask::kA8_Format:
31             return kA8_GrMaskFormat;
32         case SkMask::kLCD16_Format:
33             return kA565_GrMaskFormat;
34         case SkMask::kARGB32_Format:
35             return kARGB_GrMaskFormat;
36         default:
37             SkDEBUGFAIL("unsupported SkMask::Format");
38             return kA8_GrMaskFormat;
39     }
40 }
41 
getKey()42 const GrFontDescKey* GrFontScaler::getKey() {
43     if (nullptr == fKey) {
44         fKey = new GrFontDescKey(fStrike->getDescriptor());
45     }
46     return fKey;
47 }
48 
getPackedGlyphMaskFormat(const SkGlyph & glyph) const49 GrMaskFormat GrFontScaler::getPackedGlyphMaskFormat(const SkGlyph& glyph) const {
50     SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
51     switch (format) {
52         case SkMask::kBW_Format:
53             // fall through to kA8 -- we store BW glyphs in our 8-bit cache
54         case SkMask::kA8_Format:
55             return kA8_GrMaskFormat;
56         case SkMask::kLCD16_Format:
57             return kA565_GrMaskFormat;
58         case SkMask::kARGB32_Format:
59             return kARGB_GrMaskFormat;
60         default:
61             SkDEBUGFAIL("unsupported SkMask::Format");
62             return kA8_GrMaskFormat;
63     }
64 }
65 
getPackedGlyphBounds(const SkGlyph & glyph,SkIRect * bounds)66 bool GrFontScaler::getPackedGlyphBounds(const SkGlyph& glyph, SkIRect* bounds) {
67 #if 1
68     // crbug:510931
69     // Retrieving the image from the cache can actually change the mask format.
70     fStrike->findImage(glyph);
71 #endif
72     bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
73 
74     return true;
75 }
76 
getPackedGlyphDFBounds(const SkGlyph & glyph,SkIRect * bounds)77 bool GrFontScaler::getPackedGlyphDFBounds(const SkGlyph& glyph, SkIRect* bounds) {
78 #if 1
79     // crbug:510931
80     // Retrieving the image from the cache can actually change the mask format.
81     fStrike->findImage(glyph);
82 #endif
83     bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
84     bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
85 
86     return true;
87 }
88 
89 namespace {
90 // expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
91 // A8, RGB565, or RGBA8888.
92 template <typename INT_TYPE>
expand_bits(INT_TYPE * dst,const uint8_t * src,int width,int height,int dstRowBytes,int srcRowBytes)93 void expand_bits(INT_TYPE* dst,
94                  const uint8_t* src,
95                  int width,
96                  int height,
97                  int dstRowBytes,
98                  int srcRowBytes) {
99     for (int i = 0; i < height; ++i) {
100         int rowWritesLeft = width;
101         const uint8_t* s = src;
102         INT_TYPE* d = dst;
103         while (rowWritesLeft > 0) {
104             unsigned mask = *s++;
105             for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
106                 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
107             }
108         }
109         dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
110         src += srcRowBytes;
111     }
112 }
113 }
114 
getPackedGlyphImage(const SkGlyph & glyph,int width,int height,int dstRB,GrMaskFormat expectedMaskFormat,void * dst)115 bool GrFontScaler::getPackedGlyphImage(const SkGlyph& glyph, int width, int height, int dstRB,
116                                        GrMaskFormat expectedMaskFormat, void* dst) {
117     SkASSERT(glyph.fWidth == width);
118     SkASSERT(glyph.fHeight == height);
119     const void* src = fStrike->findImage(glyph);
120     if (nullptr == src) {
121         return false;
122     }
123 
124     // crbug:510931
125     // Retrieving the image from the cache can actually change the mask format.  This case is very
126     // uncommon so for now we just draw a clear box for these glyphs.
127     if (getPackedGlyphMaskFormat(glyph) != expectedMaskFormat) {
128         const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
129         for (int y = 0; y < height; y++) {
130             sk_bzero(dst, width * bpp);
131             dst = (char*)dst + dstRB;
132         }
133         return true;
134     }
135 
136     int srcRB = glyph.rowBytes();
137     // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
138     // check the glyph's format, not the strike's format, and to be able to convert to any of the
139     // GrMaskFormats.
140     if (SkMask::kBW_Format == glyph.fMaskFormat) {
141         // expand bits to our mask type
142         const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
143         switch (expectedMaskFormat) {
144             case kA8_GrMaskFormat:{
145                 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
146                 expand_bits(bytes, bits, width, height, dstRB, srcRB);
147                 break;
148             }
149             case kA565_GrMaskFormat: {
150                 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
151                 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
152                 break;
153             }
154             default:
155                 SkFAIL("Invalid GrMaskFormat");
156         }
157     } else if (srcRB == dstRB) {
158         memcpy(dst, src, dstRB * height);
159     } else {
160         const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
161         for (int y = 0; y < height; y++) {
162             memcpy(dst, src, width * bbp);
163             src = (const char*)src + srcRB;
164             dst = (char*)dst + dstRB;
165         }
166     }
167     return true;
168 }
169 
getPackedGlyphDFImage(const SkGlyph & glyph,int width,int height,void * dst)170 bool GrFontScaler::getPackedGlyphDFImage(const SkGlyph& glyph, int width, int height, void* dst) {
171     SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
172     SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
173     const void* image = fStrike->findImage(glyph);
174     if (nullptr == image) {
175         return false;
176     }
177     // now generate the distance field
178     SkASSERT(dst);
179     SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
180     if (SkMask::kA8_Format == maskFormat) {
181         // make the distance field from the image
182         SkGenerateDistanceFieldFromA8Image((unsigned char*)dst,
183                                            (unsigned char*)image,
184                                            glyph.fWidth, glyph.fHeight,
185                                            glyph.rowBytes());
186     } else if (SkMask::kBW_Format == maskFormat) {
187         // make the distance field from the image
188         SkGenerateDistanceFieldFromBWImage((unsigned char*)dst,
189                                            (unsigned char*)image,
190                                            glyph.fWidth, glyph.fHeight,
191                                            glyph.rowBytes());
192     } else {
193         return false;
194     }
195 
196     return true;
197 }
198 
getGlyphPath(const SkGlyph & glyph)199 const SkPath* GrFontScaler::getGlyphPath(const SkGlyph& glyph) {
200     return fStrike->findPath(glyph);
201 }
202 
grToSkGlyph(GrGlyph::PackedID id)203 const SkGlyph& GrFontScaler::grToSkGlyph(GrGlyph::PackedID id) {
204     return fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(id),
205                                       GrGlyph::UnpackFixedX(id),
206                                       GrGlyph::UnpackFixedY(id));
207 }
208