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