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