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