1 /*
2  * Copyright 2006-2012 The Android Open Source Project
3  * Copyright 2012 Mozilla Foundation
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 "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkColor.h"
12 #include "SkColorPriv.h"
13 #include "SkFDot6.h"
14 #include "SkFontHost_FreeType_common.h"
15 #include "SkPath.h"
16 
17 #include <ft2build.h>
18 #include FT_FREETYPE_H
19 #include FT_BITMAP_H
20 #include FT_IMAGE_H
21 #include FT_OUTLINE_H
22 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
23 #include FT_SYNTHESIS_H
24 
25 // FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
26 // were introduced in FreeType 2.5.0.
27 // The following may be removed once FreeType 2.5.0 is required to build.
28 #ifndef FT_LOAD_COLOR
29 #    define FT_LOAD_COLOR ( 1L << 20 )
30 #    define FT_PIXEL_MODE_BGRA 7
31 #endif
32 
33 //#define SK_SHOW_TEXT_BLIT_COVERAGE
34 
compute_pixel_mode(SkMask::Format format)35 static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
36     switch (format) {
37         case SkMask::kBW_Format:
38             return FT_PIXEL_MODE_MONO;
39         case SkMask::kA8_Format:
40         default:
41             return FT_PIXEL_MODE_GRAY;
42     }
43 }
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 
packTriple(U8CPU r,U8CPU g,U8CPU b)47 static uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
48 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
49     r = SkTMax(r, (U8CPU)0x40);
50     g = SkTMax(g, (U8CPU)0x40);
51     b = SkTMax(b, (U8CPU)0x40);
52 #endif
53     return SkPack888ToRGB16(r, g, b);
54 }
55 
grayToRGB16(U8CPU gray)56 static uint16_t grayToRGB16(U8CPU gray) {
57 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
58     gray = SkTMax(gray, (U8CPU)0x40);
59 #endif
60     return SkPack888ToRGB16(gray, gray, gray);
61 }
62 
bittst(const uint8_t data[],int bitOffset)63 static int bittst(const uint8_t data[], int bitOffset) {
64     SkASSERT(bitOffset >= 0);
65     int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
66     return lowBit & 1;
67 }
68 
69 /**
70  *  Copies a FT_Bitmap into an SkMask with the same dimensions.
71  *
72  *  FT_PIXEL_MODE_MONO
73  *  FT_PIXEL_MODE_GRAY
74  *  FT_PIXEL_MODE_LCD
75  *  FT_PIXEL_MODE_LCD_V
76  */
77 template<bool APPLY_PREBLEND>
copyFT2LCD16(const FT_Bitmap & bitmap,const SkMask & mask,int lcdIsBGR,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)78 static void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
79                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
80 {
81     SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
82     if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
83         SkASSERT(mask.fBounds.width() == static_cast<int>(bitmap.width));
84     }
85     if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
86         SkASSERT(mask.fBounds.height() == static_cast<int>(bitmap.rows));
87     }
88 
89     const uint8_t* src = bitmap.buffer;
90     uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
91     const size_t dstRB = mask.fRowBytes;
92 
93     const int width = mask.fBounds.width();
94     const int height = mask.fBounds.height();
95 
96     switch (bitmap.pixel_mode) {
97         case FT_PIXEL_MODE_MONO:
98             for (int y = height; y --> 0;) {
99                 for (int x = 0; x < width; ++x) {
100                     dst[x] = -bittst(src, x);
101                 }
102                 dst = (uint16_t*)((char*)dst + dstRB);
103                 src += bitmap.pitch;
104             }
105             break;
106         case FT_PIXEL_MODE_GRAY:
107             for (int y = height; y --> 0;) {
108                 for (int x = 0; x < width; ++x) {
109                     dst[x] = grayToRGB16(src[x]);
110                 }
111                 dst = (uint16_t*)((char*)dst + dstRB);
112                 src += bitmap.pitch;
113             }
114             break;
115         case FT_PIXEL_MODE_LCD:
116             SkASSERT(3 * mask.fBounds.width() == static_cast<int>(bitmap.width));
117             for (int y = height; y --> 0;) {
118                 const uint8_t* triple = src;
119                 if (lcdIsBGR) {
120                     for (int x = 0; x < width; x++) {
121                         dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
122                                             sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
123                                             sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
124                         triple += 3;
125                     }
126                 } else {
127                     for (int x = 0; x < width; x++) {
128                         dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
129                                             sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
130                                             sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
131                         triple += 3;
132                     }
133                 }
134                 src += bitmap.pitch;
135                 dst = (uint16_t*)((char*)dst + dstRB);
136             }
137             break;
138         case FT_PIXEL_MODE_LCD_V:
139             SkASSERT(3 * mask.fBounds.height() == static_cast<int>(bitmap.rows));
140             for (int y = height; y --> 0;) {
141                 const uint8_t* srcR = src;
142                 const uint8_t* srcG = srcR + bitmap.pitch;
143                 const uint8_t* srcB = srcG + bitmap.pitch;
144                 if (lcdIsBGR) {
145                     SkTSwap(srcR, srcB);
146                 }
147                 for (int x = 0; x < width; x++) {
148                     dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
149                                         sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
150                                         sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
151                 }
152                 src += 3 * bitmap.pitch;
153                 dst = (uint16_t*)((char*)dst + dstRB);
154             }
155             break;
156         default:
157             SkDEBUGF(("FT_Pixel_Mode %d", bitmap.pixel_mode));
158             SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
159             break;
160     }
161 }
162 
163 /**
164  *  Copies a FT_Bitmap into an SkMask with the same dimensions.
165  *
166  *  Yes, No, Never Requested, Never Produced
167  *
168  *                        kBW kA8 k3D kARGB32 kLCD16
169  *  FT_PIXEL_MODE_MONO     Y   Y  NR     N       Y
170  *  FT_PIXEL_MODE_GRAY     N   Y  NR     N       Y
171  *  FT_PIXEL_MODE_GRAY2   NP  NP  NR    NP      NP
172  *  FT_PIXEL_MODE_GRAY4   NP  NP  NR    NP      NP
173  *  FT_PIXEL_MODE_LCD     NP  NP  NR    NP      NP
174  *  FT_PIXEL_MODE_LCD_V   NP  NP  NR    NP      NP
175  *  FT_PIXEL_MODE_BGRA     N   N  NR     Y       N
176  *
177  *  TODO: All of these N need to be Y or otherwise ruled out.
178  */
copyFTBitmap(const FT_Bitmap & srcFTBitmap,SkMask & dstMask)179 static void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
180     SkASSERT(dstMask.fBounds.width() == static_cast<int>(srcFTBitmap.width));
181     SkASSERT(dstMask.fBounds.height() == static_cast<int>(srcFTBitmap.rows));
182 
183     const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
184     const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
185     // FT_Bitmap::pitch is an int and allowed to be negative.
186     const int srcPitch = srcFTBitmap.pitch;
187     const size_t srcRowBytes = SkTAbs(srcPitch);
188 
189     uint8_t* dst = dstMask.fImage;
190     const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
191     const size_t dstRowBytes = dstMask.fRowBytes;
192 
193     const size_t width = srcFTBitmap.width;
194     const size_t height = srcFTBitmap.rows;
195 
196     if (SkMask::kLCD16_Format == dstFormat) {
197         copyFT2LCD16<false>(srcFTBitmap, dstMask, false, nullptr, nullptr, nullptr);
198         return;
199     }
200 
201     if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
202         (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
203     {
204         size_t commonRowBytes = SkTMin(srcRowBytes, dstRowBytes);
205         for (size_t y = height; y --> 0;) {
206             memcpy(dst, src, commonRowBytes);
207             src += srcPitch;
208             dst += dstRowBytes;
209         }
210     } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
211         for (size_t y = height; y --> 0;) {
212             uint8_t byte = 0;
213             int bits = 0;
214             const uint8_t* src_row = src;
215             uint8_t* dst_row = dst;
216             for (size_t x = width; x --> 0;) {
217                 if (0 == bits) {
218                     byte = *src_row++;
219                     bits = 8;
220                 }
221                 *dst_row++ = byte & 0x80 ? 0xff : 0x00;
222                 bits--;
223                 byte <<= 1;
224             }
225             src += srcPitch;
226             dst += dstRowBytes;
227         }
228     } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
229         // FT_PIXEL_MODE_BGRA is pre-multiplied.
230         for (size_t y = height; y --> 0;) {
231             const uint8_t* src_row = src;
232             SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
233             for (size_t x = 0; x < width; ++x) {
234                 uint8_t b = *src_row++;
235                 uint8_t g = *src_row++;
236                 uint8_t r = *src_row++;
237                 uint8_t a = *src_row++;
238                 *dst_row++ = SkPackARGB32(a, r, g, b);
239 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
240                 *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
241 #endif
242             }
243             src += srcPitch;
244             dst += dstRowBytes;
245         }
246     } else {
247         SkDEBUGF(("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat));
248         SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
249     }
250 }
251 
convert_8_to_1(unsigned byte)252 static inline int convert_8_to_1(unsigned byte) {
253     SkASSERT(byte <= 0xFF);
254     // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
255     return (byte >> 6) != 0;
256 }
257 
pack_8_to_1(const uint8_t alpha[8])258 static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
259     unsigned bits = 0;
260     for (int i = 0; i < 8; ++i) {
261         bits <<= 1;
262         bits |= convert_8_to_1(alpha[i]);
263     }
264     return SkToU8(bits);
265 }
266 
packA8ToA1(const SkMask & mask,const uint8_t * src,size_t srcRB)267 static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
268     const int height = mask.fBounds.height();
269     const int width = mask.fBounds.width();
270     const int octs = width >> 3;
271     const int leftOverBits = width & 7;
272 
273     uint8_t* dst = mask.fImage;
274     const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
275     SkASSERT(dstPad >= 0);
276 
277     const int srcPad = srcRB - width;
278     SkASSERT(srcPad >= 0);
279 
280     for (int y = 0; y < height; ++y) {
281         for (int i = 0; i < octs; ++i) {
282             *dst++ = pack_8_to_1(src);
283             src += 8;
284         }
285         if (leftOverBits > 0) {
286             unsigned bits = 0;
287             int shift = 7;
288             for (int i = 0; i < leftOverBits; ++i, --shift) {
289                 bits |= convert_8_to_1(*src++) << shift;
290             }
291             *dst++ = bits;
292         }
293         src += srcPad;
294         dst += dstPad;
295     }
296 }
297 
SkMaskFormat_for_SkColorType(SkColorType colorType)298 inline SkMask::Format SkMaskFormat_for_SkColorType(SkColorType colorType) {
299     switch (colorType) {
300         case kAlpha_8_SkColorType:
301             return SkMask::kA8_Format;
302         case kN32_SkColorType:
303             return SkMask::kARGB32_Format;
304         default:
305             SkDEBUGFAIL("unsupported SkBitmap::Config");
306             return SkMask::kA8_Format;
307     }
308 }
309 
SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode)310 inline SkColorType SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
311     switch (pixel_mode) {
312         case FT_PIXEL_MODE_MONO:
313         case FT_PIXEL_MODE_GRAY:
314             return kAlpha_8_SkColorType;
315         case FT_PIXEL_MODE_BGRA:
316             return kN32_SkColorType;
317         default:
318             SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
319             return kAlpha_8_SkColorType;
320     }
321 }
322 
SkColorType_for_SkMaskFormat(SkMask::Format format)323 inline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) {
324     switch (format) {
325         case SkMask::kBW_Format:
326         case SkMask::kA8_Format:
327         case SkMask::kLCD16_Format:
328             return kAlpha_8_SkColorType;
329         case SkMask::kARGB32_Format:
330             return kN32_SkColorType;
331         default:
332             SkDEBUGFAIL("unsupported destination SkBitmap::Config");
333             return kAlpha_8_SkColorType;
334     }
335 }
336 
generateGlyphImage(FT_Face face,const SkGlyph & glyph)337 void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
338     const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
339     const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
340 
341     switch ( face->glyph->format ) {
342         case FT_GLYPH_FORMAT_OUTLINE: {
343             FT_Outline* outline = &face->glyph->outline;
344             FT_BBox     bbox;
345             FT_Bitmap   target;
346 
347             int dx = 0, dy = 0;
348             if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
349                 dx = SkFixedToFDot6(glyph.getSubXFixed());
350                 dy = SkFixedToFDot6(glyph.getSubYFixed());
351                 // negate dy since freetype-y-goes-up and skia-y-goes-down
352                 dy = -dy;
353             }
354             FT_Outline_Get_CBox(outline, &bbox);
355             /*
356                 what we really want to do for subpixel is
357                     offset(dx, dy)
358                     compute_bounds
359                     offset(bbox & !63)
360                 but that is two calls to offset, so we do the following, which
361                 achieves the same thing with only one offset call.
362             */
363             FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
364                                           dy - ((bbox.yMin + dy) & ~63));
365 
366             if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
367                 FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
368                 SkMask mask;
369                 glyph.toMask(&mask);
370                 if (fPreBlend.isApplicable()) {
371                     copyFT2LCD16<true>(face->glyph->bitmap, mask, doBGR,
372                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
373                 } else {
374                     copyFT2LCD16<false>(face->glyph->bitmap, mask, doBGR,
375                                         fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
376                 }
377             } else {
378                 target.width = glyph.fWidth;
379                 target.rows = glyph.fHeight;
380                 target.pitch = glyph.rowBytes();
381                 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
382                 target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat);
383                 target.num_grays = 256;
384 
385                 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
386                 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
387             }
388         } break;
389 
390         case FT_GLYPH_FORMAT_BITMAP: {
391             FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
392             SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
393 
394             // Assume that the other formats do not exist.
395             SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
396                      FT_PIXEL_MODE_GRAY == pixel_mode ||
397                      FT_PIXEL_MODE_BGRA == pixel_mode);
398 
399             // These are the only formats this ScalerContext should request.
400             SkASSERT(SkMask::kBW_Format == maskFormat ||
401                      SkMask::kA8_Format == maskFormat ||
402                      SkMask::kARGB32_Format == maskFormat ||
403                      SkMask::kLCD16_Format == maskFormat);
404 
405             if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
406                 !(face->style_flags & FT_STYLE_FLAG_BOLD))
407             {
408                 FT_GlyphSlot_Own_Bitmap(face->glyph);
409                 FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap,
410                                    kBitmapEmboldenStrength, 0);
411             }
412 
413             // If no scaling needed, directly copy glyph bitmap.
414             if (glyph.fWidth == face->glyph->bitmap.width &&
415                 glyph.fHeight == face->glyph->bitmap.rows &&
416                 glyph.fTop == -face->glyph->bitmap_top &&
417                 glyph.fLeft == face->glyph->bitmap_left)
418             {
419                 SkMask dstMask;
420                 glyph.toMask(&dstMask);
421                 copyFTBitmap(face->glyph->bitmap, dstMask);
422                 break;
423             }
424 
425             // Otherwise, scale the bitmap.
426 
427             // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
428             SkBitmap unscaledBitmap;
429             unscaledBitmap.allocPixels(SkImageInfo::Make(face->glyph->bitmap.width,
430                                                          face->glyph->bitmap.rows,
431                                                          SkColorType_for_FTPixelMode(pixel_mode),
432                                                          kPremul_SkAlphaType));
433 
434             SkMask unscaledBitmapAlias;
435             unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
436             unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height());
437             unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
438             unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkColorType(unscaledBitmap.colorType());
439             copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
440 
441             // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
442             // BW requires an A8 target for resizing, which can then be down sampled.
443             // LCD should use a 4x A8 target, which will then be down sampled.
444             // For simplicity, LCD uses A8 and is replicated.
445             int bitmapRowBytes = 0;
446             if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
447                 bitmapRowBytes = glyph.rowBytes();
448             }
449             SkBitmap dstBitmap;
450             dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
451                                                 SkColorType_for_SkMaskFormat(maskFormat),
452                                                 kPremul_SkAlphaType),
453                               bitmapRowBytes);
454             if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
455                 dstBitmap.allocPixels();
456             } else {
457                 dstBitmap.setPixels(glyph.fImage);
458             }
459 
460             // Scale unscaledBitmap into dstBitmap.
461             SkCanvas canvas(dstBitmap);
462             canvas.clear(SK_ColorTRANSPARENT);
463             canvas.scale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width),
464                          SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows));
465             SkPaint paint;
466             paint.setFilterQuality(kMedium_SkFilterQuality);
467             canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
468 
469             // If the destination is BW or LCD, convert from A8.
470             if (SkMask::kBW_Format == maskFormat) {
471                 // Copy the A8 dstBitmap into the A1 glyph.fImage.
472                 SkMask dstMask;
473                 glyph.toMask(&dstMask);
474                 packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
475             } else if (SkMask::kLCD16_Format == maskFormat) {
476                 // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
477                 uint8_t* src = dstBitmap.getAddr8(0, 0);
478                 uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
479                 for (int y = dstBitmap.height(); y --> 0;) {
480                     for (int x = 0; x < dstBitmap.width(); ++x) {
481                         dst[x] = grayToRGB16(src[x]);
482                     }
483                     dst = (uint16_t*)((char*)dst + glyph.rowBytes());
484                     src += dstBitmap.rowBytes();
485                 }
486             }
487 
488         } break;
489 
490         default:
491             SkDEBUGFAIL("unknown glyph format");
492             memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
493             return;
494     }
495 
496 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
497 // it is optional
498 #if defined(SK_GAMMA_APPLY_TO_A8)
499     if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
500         uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
501         unsigned rowBytes = glyph.rowBytes();
502 
503         for (int y = glyph.fHeight - 1; y >= 0; --y) {
504             for (int x = glyph.fWidth - 1; x >= 0; --x) {
505                 dst[x] = fPreBlend.fG[dst[x]];
506             }
507             dst += rowBytes;
508         }
509     }
510 #endif
511 }
512 
513 ///////////////////////////////////////////////////////////////////////////////
514 
move_proc(const FT_Vector * pt,void * ctx)515 static int move_proc(const FT_Vector* pt, void* ctx) {
516     SkPath* path = (SkPath*)ctx;
517     path->close();  // to close the previous contour (if any)
518     path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
519     return 0;
520 }
521 
line_proc(const FT_Vector * pt,void * ctx)522 static int line_proc(const FT_Vector* pt, void* ctx) {
523     SkPath* path = (SkPath*)ctx;
524     path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
525     return 0;
526 }
527 
quad_proc(const FT_Vector * pt0,const FT_Vector * pt1,void * ctx)528 static int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1,
529                      void* ctx) {
530     SkPath* path = (SkPath*)ctx;
531     path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
532                  SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
533     return 0;
534 }
535 
cubic_proc(const FT_Vector * pt0,const FT_Vector * pt1,const FT_Vector * pt2,void * ctx)536 static int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1,
537                       const FT_Vector* pt2, void* ctx) {
538     SkPath* path = (SkPath*)ctx;
539     path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
540                   SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
541                   SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
542     return 0;
543 }
544 
generateGlyphPath(FT_Face face,SkPath * path)545 void SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face,
546                                                       SkPath* path)
547 {
548     FT_Outline_Funcs    funcs;
549 
550     funcs.move_to   = move_proc;
551     funcs.line_to   = line_proc;
552     funcs.conic_to  = quad_proc;
553     funcs.cubic_to  = cubic_proc;
554     funcs.shift     = 0;
555     funcs.delta     = 0;
556 
557     FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path);
558 
559     if (err != 0) {
560         path->reset();
561         return;
562     }
563 
564     path->close();
565 }
566