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 "include/core/SkBitmap.h"
10#include "include/core/SkCanvas.h"
11#include "include/core/SkColor.h"
12#include "include/core/SkPath.h"
13#include "include/private/SkColorData.h"
14#include "include/private/SkTo.h"
15#include "src/core/SkFDot6.h"
16#include "src/ports/SkFontHost_FreeType_common.h"
17
18#include <utility>
19
20#include <ft2build.h>
21#include FT_FREETYPE_H
22#include FT_BITMAP_H
23#ifdef FT_COLOR_H
24# include FT_COLOR_H
25#endif
26#include FT_IMAGE_H
27#include FT_OUTLINE_H
28// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
29#include FT_SYNTHESIS_H
30
31// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
32// were introduced in FreeType 2.5.0.
33// The following may be removed once FreeType 2.5.0 is required to build.
34#ifndef FT_LOAD_COLOR
35# define FT_LOAD_COLOR ( 1L << 20 )
36# define FT_PIXEL_MODE_BGRA 7
37#endif
38
39#ifdef SK_DEBUG
40const char* SkTraceFtrGetError(int e) {
41 switch ((FT_Error)e) {
42 #undef FTERRORS_H_
43 #define FT_ERRORDEF( e, v, s ) case v: return s;
44 #define FT_ERROR_START_LIST
45 #define FT_ERROR_END_LIST
46 #include FT_ERRORS_H
47 #undef FT_ERRORDEF
48 #undef FT_ERROR_START_LIST
49 #undef FT_ERROR_END_LIST
50 default: return "";
51 }
52}
53#endif // SK_DEBUG
54
55namespace {
56
57FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
58 switch (format) {
59 case SkMask::kBW_Format:
60 return FT_PIXEL_MODE_MONO;
61 case SkMask::kA8_Format:
62 default:
63 return FT_PIXEL_MODE_GRAY;
64 }
65}
66
67///////////////////////////////////////////////////////////////////////////////
68
69uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
70#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
71 r = std::max(r, (U8CPU)0x40);
72 g = std::max(g, (U8CPU)0x40);
73 b = std::max(b, (U8CPU)0x40);
74#endif
75 return SkPack888ToRGB16(r, g, b);
76}
77
78uint16_t grayToRGB16(U8CPU gray) {
79#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
80 gray = std::max(gray, (U8CPU)0x40);
81#endif
82 return SkPack888ToRGB16(gray, gray, gray);
83}
84
85int bittst(const uint8_t data[], int bitOffset) {
86 SkASSERT(bitOffset >= 0);
87 int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
88 return lowBit & 1;
89}
90
91/**
92 * Copies a FT_Bitmap into an SkMask with the same dimensions.
93 *
94 * FT_PIXEL_MODE_MONO
95 * FT_PIXEL_MODE_GRAY
96 * FT_PIXEL_MODE_LCD
97 * FT_PIXEL_MODE_LCD_V
98 */
99template<bool APPLY_PREBLEND>
100void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
101 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
102{
103 SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
104 if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
105 SkASSERT(mask.fBounds.width() == static_cast<int>(bitmap.width));
106 }
107 if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
108 SkASSERT(mask.fBounds.height() == static_cast<int>(bitmap.rows));
109 }
110
111 const uint8_t* src = bitmap.buffer;
112 uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
113 const size_t dstRB = mask.fRowBytes;
114
115 const int width = mask.fBounds.width();
116 const int height = mask.fBounds.height();
117
118 switch (bitmap.pixel_mode) {
119 case FT_PIXEL_MODE_MONO:
120 for (int y = height; y --> 0;) {
121 for (int x = 0; x < width; ++x) {
122 dst[x] = -bittst(src, x);
123 }
124 dst = (uint16_t*)((char*)dst + dstRB);
125 src += bitmap.pitch;
126 }
127 break;
128 case FT_PIXEL_MODE_GRAY:
129 for (int y = height; y --> 0;) {
130 for (int x = 0; x < width; ++x) {
131 dst[x] = grayToRGB16(src[x]);
132 }
133 dst = (uint16_t*)((char*)dst + dstRB);
134 src += bitmap.pitch;
135 }
136 break;
137 case FT_PIXEL_MODE_LCD:
138 SkASSERT(3 * mask.fBounds.width() == static_cast<int>(bitmap.width));
139 for (int y = height; y --> 0;) {
140 const uint8_t* triple = src;
141 if (lcdIsBGR) {
142 for (int x = 0; x < width; x++) {
143 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
144 sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
145 sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
146 triple += 3;
147 }
148 } else {
149 for (int x = 0; x < width; x++) {
150 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
151 sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
152 sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
153 triple += 3;
154 }
155 }
156 src += bitmap.pitch;
157 dst = (uint16_t*)((char*)dst + dstRB);
158 }
159 break;
160 case FT_PIXEL_MODE_LCD_V:
161 SkASSERT(3 * mask.fBounds.height() == static_cast<int>(bitmap.rows));
162 for (int y = height; y --> 0;) {
163 const uint8_t* srcR = src;
164 const uint8_t* srcG = srcR + bitmap.pitch;
165 const uint8_t* srcB = srcG + bitmap.pitch;
166 if (lcdIsBGR) {
167 using std::swap;
168 swap(srcR, srcB);
169 }
170 for (int x = 0; x < width; x++) {
171 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
172 sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
173 sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
174 }
175 src += 3 * bitmap.pitch;
176 dst = (uint16_t*)((char*)dst + dstRB);
177 }
178 break;
179 default:
180 SkDEBUGF("FT_Pixel_Mode %d", bitmap.pixel_mode);
181 SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
182 break;
183 }
184}
185
186/**
187 * Copies a FT_Bitmap into an SkMask with the same dimensions.
188 *
189 * Yes, No, Never Requested, Never Produced
190 *
191 * kBW kA8 k3D kARGB32 kLCD16
192 * FT_PIXEL_MODE_MONO Y Y NR N Y
193 * FT_PIXEL_MODE_GRAY N Y NR N Y
194 * FT_PIXEL_MODE_GRAY2 NP NP NR NP NP
195 * FT_PIXEL_MODE_GRAY4 NP NP NR NP NP
196 * FT_PIXEL_MODE_LCD NP NP NR NP NP
197 * FT_PIXEL_MODE_LCD_V NP NP NR NP NP
198 * FT_PIXEL_MODE_BGRA N N NR Y N
199 *
200 * TODO: All of these N need to be Y or otherwise ruled out.
201 */
202void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
203 SkASSERTF(dstMask.fBounds.width() == static_cast<int>(srcFTBitmap.width),
204 "dstMask.fBounds.width() = %d\n"
205 "static_cast<int>(srcFTBitmap.width) = %d",
206 dstMask.fBounds.width(),
207 static_cast<int>(srcFTBitmap.width)
208 );
209 SkASSERTF(dstMask.fBounds.height() == static_cast<int>(srcFTBitmap.rows),
210 "dstMask.fBounds.height() = %d\n"
211 "static_cast<int>(srcFTBitmap.rows) = %d",
212 dstMask.fBounds.height(),
213 static_cast<int>(srcFTBitmap.rows)
214 );
215
216 const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
217 const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
218 // FT_Bitmap::pitch is an int and allowed to be negative.
219 const int srcPitch = srcFTBitmap.pitch;
220 const size_t srcRowBytes = SkTAbs(srcPitch);
221
222 uint8_t* dst = dstMask.fImage;
223 const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
224 const size_t dstRowBytes = dstMask.fRowBytes;
225
226 const size_t width = srcFTBitmap.width;
227 const size_t height = srcFTBitmap.rows;
228
229 if (SkMask::kLCD16_Format == dstFormat) {
230 copyFT2LCD16<false>(srcFTBitmap, dstMask, false, nullptr, nullptr, nullptr);
231 return;
232 }
233
234 if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
235 (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
236 {
237 size_t commonRowBytes = std::min(srcRowBytes, dstRowBytes);
238 for (size_t y = height; y --> 0;) {
239 memcpy(dst, src, commonRowBytes);
240 src += srcPitch;
241 dst += dstRowBytes;
242 }
243 } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
244 for (size_t y = height; y --> 0;) {
245 uint8_t byte = 0;
246 int bits = 0;
247 const uint8_t* src_row = src;
248 uint8_t* dst_row = dst;
249 for (size_t x = width; x --> 0;) {
250 if (0 == bits) {
251 byte = *src_row++;
252 bits = 8;
253 }
254 *dst_row++ = byte & 0x80 ? 0xff : 0x00;
255 bits--;
256 byte <<= 1;
257 }
258 src += srcPitch;
259 dst += dstRowBytes;
260 }
261 } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
262 // FT_PIXEL_MODE_BGRA is pre-multiplied.
263 for (size_t y = height; y --> 0;) {
264 const uint8_t* src_row = src;
265 SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
266 for (size_t x = 0; x < width; ++x) {
267 uint8_t b = *src_row++;
268 uint8_t g = *src_row++;
269 uint8_t r = *src_row++;
270 uint8_t a = *src_row++;
271 *dst_row++ = SkPackARGB32(a, r, g, b);
272#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
273 *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
274#endif
275 }
276 src += srcPitch;
277 dst += dstRowBytes;
278 }
279 } else {
280 SkDEBUGF("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat);
281 SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
282 }
283}
284
285inline int convert_8_to_1(unsigned byte) {
286 SkASSERT(byte <= 0xFF);
287 // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
288 return (byte >> 6) != 0;
289}
290
291uint8_t pack_8_to_1(const uint8_t alpha[8]) {
292 unsigned bits = 0;
293 for (int i = 0; i < 8; ++i) {
294 bits <<= 1;
295 bits |= convert_8_to_1(alpha[i]);
296 }
297 return SkToU8(bits);
298}
299
300void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
301 const int height = mask.fBounds.height();
302 const int width = mask.fBounds.width();
303 const int octs = width >> 3;
304 const int leftOverBits = width & 7;
305
306 uint8_t* dst = mask.fImage;
307 const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
308 SkASSERT(dstPad >= 0);
309
310 const int srcPad = srcRB - width;
311 SkASSERT(srcPad >= 0);
312
313 for (int y = 0; y < height; ++y) {
314 for (int i = 0; i < octs; ++i) {
315 *dst++ = pack_8_to_1(src);
316 src += 8;
317 }
318 if (leftOverBits > 0) {
319 unsigned bits = 0;
320 int shift = 7;
321 for (int i = 0; i < leftOverBits; ++i, --shift) {
322 bits |= convert_8_to_1(*src++) << shift;
323 }
324 *dst++ = bits;
325 }
326 src += srcPad;
327 dst += dstPad;
328 }
329}
330
331inline SkMask::Format SkMaskFormat_for_SkColorType(SkColorType colorType) {
332 switch (colorType) {
333 case kAlpha_8_SkColorType:
334 return SkMask::kA8_Format;
335 case kN32_SkColorType:
336 return SkMask::kARGB32_Format;
337 default:
338 SkDEBUGFAIL("unsupported SkBitmap::Config");
339 return SkMask::kA8_Format;
340 }
341}
342
343inline SkColorType SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
344 switch (pixel_mode) {
345 case FT_PIXEL_MODE_MONO:
346 case FT_PIXEL_MODE_GRAY:
347 return kAlpha_8_SkColorType;
348 case FT_PIXEL_MODE_BGRA:
349 return kN32_SkColorType;
350 default:
351 SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
352 return kAlpha_8_SkColorType;
353 }
354}
355
356inline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) {
357 switch (format) {
358 case SkMask::kBW_Format:
359 case SkMask::kA8_Format:
360 case SkMask::kLCD16_Format:
361 return kAlpha_8_SkColorType;
362 case SkMask::kARGB32_Format:
363 return kN32_SkColorType;
364 default:
365 SkDEBUGFAIL("unsupported destination SkBitmap::Config");
366 return kAlpha_8_SkColorType;
367 }
368}
369
370} // namespace
371
372void SkScalerContext_FreeType_Base::generateGlyphImage(
373 FT_Face face,
374 const SkGlyph& glyph,
375 const SkMatrix& bitmapTransform)
376{
377 const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
378 const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
379
380 switch ( face->glyph->format ) {
381 case FT_GLYPH_FORMAT_OUTLINE: {
382 FT_Outline* outline = &face->glyph->outline;
383
384 int dx = 0, dy = 0;
385 if (this->isSubpixel()) {
386 dx = SkFixedToFDot6(glyph.getSubXFixed());
387 dy = SkFixedToFDot6(glyph.getSubYFixed());
388 // negate dy since freetype-y-goes-up and skia-y-goes-down
389 dy = -dy;
390 }
391
392 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
393
394#ifdef FT_COLOR_H
395 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
396 SkBitmap dstBitmap;
397 // TODO: mark this as sRGB when the blits will be sRGB.
398 dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
399 kN32_SkColorType,
400 kPremul_SkAlphaType),
401 glyph.rowBytes());
402 dstBitmap.setPixels(glyph.fImage);
403
404 // Scale unscaledBitmap into dstBitmap.
405 SkCanvas canvas(dstBitmap);
406#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
407 canvas.clear(0x33FF0000);
408#else
409 canvas.clear(SK_ColorTRANSPARENT);
410#endif
411 canvas.translate(-glyph.fLeft, -glyph.fTop);
412
413 if (this->isSubpixel()) {
414 canvas.translate(SkFixedToScalar(glyph.getSubXFixed()),
415 SkFixedToScalar(glyph.getSubYFixed()));
416 }
417
418 SkPaint paint;
419 paint.setAntiAlias(true);
420
421 FT_Color *palette;
422 FT_Error err = FT_Palette_Select(face, 0, &palette);
423 if (err) {
424 SK_TRACEFTR(err, "Could not get palette from %s fontFace.", face->family_name);
425 return;
426 }
427 FT_LayerIterator layerIterator;
428 layerIterator.p = NULL;
429 FT_Bool haveLayers = false;
430 FT_UInt layerGlyphIndex;
431 FT_UInt layerColorIndex;
432
433 while (FT_Get_Color_Glyph_Layer(face, glyph.getGlyphID(), &layerGlyphIndex,
434 &layerColorIndex,
435 &layerIterator)) {
436 haveLayers = true;
437 if (layerColorIndex == 0xFFFF) {
438 paint.setColor(SK_ColorBLACK);
439 } else {
440 SkColor color = SkColorSetARGB(palette[layerColorIndex].alpha,
441 palette[layerColorIndex].red,
442 palette[layerColorIndex].green,
443 palette[layerColorIndex].blue);
444 paint.setColor(color);
445 }
446 SkPath path;
447 if (this->generateFacePath(face, layerGlyphIndex, &path)) {
448 canvas.drawPath(path, paint);
449 }
450 }
451
452 if (!haveLayers) {
453 SK_TRACEFTR(err, "Could not get layers from %s fontFace.", face->family_name);
454 return;
455 }
456 } else
457#endif
458 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
459 FT_Outline_Translate(outline, dx, dy);
460 FT_Error err = FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V :
461 FT_RENDER_MODE_LCD);
462 if (err) {
463 SK_TRACEFTR(err, "Could not render glyph %x.", face->glyph);
464 return;
465 }
466
467 SkMask mask = glyph.mask();
468#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
469 memset(mask.fImage, 0x80, mask.fBounds.height() * mask.fRowBytes);
470#endif
471 FT_GlyphSlotRec& ftGlyph = *face->glyph;
472
473 if (!SkIRect::Intersects(mask.fBounds,
474 SkIRect::MakeXYWH( ftGlyph.bitmap_left,
475 -ftGlyph.bitmap_top,
476 ftGlyph.bitmap.width,
477 ftGlyph.bitmap.rows)))
478 {
479 return;
480 }
481
482 // If the FT_Bitmap extent is larger, discard bits of the bitmap outside the mask.
483 // If the SkMask extent is larger, shrink mask to fit bitmap (clearing discarded).
484 unsigned char* origBuffer = ftGlyph.bitmap.buffer;
485 // First align the top left (origin).
486 if (-ftGlyph.bitmap_top < mask.fBounds.fTop) {
487 int32_t topDiff = mask.fBounds.fTop - (-ftGlyph.bitmap_top);
488 ftGlyph.bitmap.buffer += ftGlyph.bitmap.pitch * topDiff;
489 ftGlyph.bitmap.rows -= topDiff;
490 ftGlyph.bitmap_top = -mask.fBounds.fTop;
491 }
492 if (ftGlyph.bitmap_left < mask.fBounds.fLeft) {
493 int32_t leftDiff = mask.fBounds.fLeft - ftGlyph.bitmap_left;
494 ftGlyph.bitmap.buffer += leftDiff;
495 ftGlyph.bitmap.width -= leftDiff;
496 ftGlyph.bitmap_left = mask.fBounds.fLeft;
497 }
498 if (mask.fBounds.fTop < -ftGlyph.bitmap_top) {
499 mask.fImage += mask.fRowBytes * (-ftGlyph.bitmap_top - mask.fBounds.fTop);
500 mask.fBounds.fTop = -ftGlyph.bitmap_top;
501 }
502 if (mask.fBounds.fLeft < ftGlyph.bitmap_left) {
503 mask.fImage += sizeof(uint16_t) * (ftGlyph.bitmap_left - mask.fBounds.fLeft);
504 mask.fBounds.fLeft = ftGlyph.bitmap_left;
505 }
506 // Origins aligned, clean up the width and height.
507 int ftVertScale = (doVert ? 3 : 1);
508 int ftHoriScale = (doVert ? 1 : 3);
509 if (mask.fBounds.height() * ftVertScale < SkToInt(ftGlyph.bitmap.rows)) {
510 ftGlyph.bitmap.rows = mask.fBounds.height() * ftVertScale;
511 }
512 if (mask.fBounds.width() * ftHoriScale < SkToInt(ftGlyph.bitmap.width)) {
513 ftGlyph.bitmap.width = mask.fBounds.width() * ftHoriScale;
514 }
515 if (SkToInt(ftGlyph.bitmap.rows) < mask.fBounds.height() * ftVertScale) {
516 mask.fBounds.fBottom = mask.fBounds.fTop + ftGlyph.bitmap.rows / ftVertScale;
517 }
518 if (SkToInt(ftGlyph.bitmap.width) < mask.fBounds.width() * ftHoriScale) {
519 mask.fBounds.fRight = mask.fBounds.fLeft + ftGlyph.bitmap.width / ftHoriScale;
520 }
521 if (fPreBlend.isApplicable()) {
522 copyFT2LCD16<true>(ftGlyph.bitmap, mask, doBGR,
523 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
524 } else {
525 copyFT2LCD16<false>(ftGlyph.bitmap, mask, doBGR,
526 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
527 }
528 // Restore the buffer pointer so FreeType can properly free it.
529 ftGlyph.bitmap.buffer = origBuffer;
530 } else {
531 FT_BBox bbox;
532 FT_Bitmap target;
533 FT_Outline_Get_CBox(outline, &bbox);
534 /*
535 what we really want to do for subpixel is
536 offset(dx, dy)
537 compute_bounds
538 offset(bbox & !63)
539 but that is two calls to offset, so we do the following, which
540 achieves the same thing with only one offset call.
541 */
542 FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
543 dy - ((bbox.yMin + dy) & ~63));
544
545 target.width = glyph.fWidth;
546 target.rows = glyph.fHeight;
547 target.pitch = glyph.rowBytes();
548 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
549 target.pixel_mode = compute_pixel_mode( (SkMask::Format)glyph.fMaskFormat);
550 target.num_grays = 256;
551
552 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
553#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
554 for (int y = 0; y < glyph.fHeight; ++y) {
555 for (int x = 0; x < glyph.fWidth; ++x) {
556 uint8_t& a = ((uint8_t*)glyph.fImage)[(glyph.rowBytes() * y) + x];
557 a = std::max<uint8_t>(a, 0x20);
558 }
559 }
560#endif
561 }
562 } break;
563
564 case FT_GLYPH_FORMAT_BITMAP: {
565 FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
566 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
567
568 // Assume that the other formats do not exist.
569 SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
570 FT_PIXEL_MODE_GRAY == pixel_mode ||
571 FT_PIXEL_MODE_BGRA == pixel_mode);
572
573 // These are the only formats this ScalerContext should request.
574 SkASSERT(SkMask::kBW_Format == maskFormat ||
575 SkMask::kA8_Format == maskFormat ||
576 SkMask::kARGB32_Format == maskFormat ||
577 SkMask::kLCD16_Format == maskFormat);
578
579 // If no scaling needed, directly copy glyph bitmap.
580 if (bitmapTransform.isIdentity()) {
581 SkMask dstMask = glyph.mask();
582 copyFTBitmap(face->glyph->bitmap, dstMask);
583 break;
584 }
585
586 // Otherwise, scale the bitmap.
587
588 // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
589 SkBitmap unscaledBitmap;
590 // TODO: mark this as sRGB when the blits will be sRGB.
591 unscaledBitmap.allocPixels(SkImageInfo::Make(face->glyph->bitmap.width,
592 face->glyph->bitmap.rows,
593 SkColorType_for_FTPixelMode(pixel_mode),
594 kPremul_SkAlphaType));
595
596 SkMask unscaledBitmapAlias;
597 unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
598 unscaledBitmapAlias.fBounds.setWH(unscaledBitmap.width(), unscaledBitmap.height());
599 unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
600 unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkColorType(unscaledBitmap.colorType());
601 copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
602
603 // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
604 // BW requires an A8 target for resizing, which can then be down sampled.
605 // LCD should use a 4x A8 target, which will then be down sampled.
606 // For simplicity, LCD uses A8 and is replicated.
607 int bitmapRowBytes = 0;
608 if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
609 bitmapRowBytes = glyph.rowBytes();
610 }
611 SkBitmap dstBitmap;
612 // TODO: mark this as sRGB when the blits will be sRGB.
613 dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
614 SkColorType_for_SkMaskFormat(maskFormat),
615 kPremul_SkAlphaType),
616 bitmapRowBytes);
617 if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
618 dstBitmap.allocPixels();
619 } else {
620 dstBitmap.setPixels(glyph.fImage);
621 }
622
623 // Scale unscaledBitmap into dstBitmap.
624 SkCanvas canvas(dstBitmap);
625#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
626 canvas.clear(0x33FF0000);
627#else
628 canvas.clear(SK_ColorTRANSPARENT);
629#endif
630 canvas.translate(-glyph.fLeft, -glyph.fTop);
631 canvas.concat(bitmapTransform);
632 canvas.translate(face->glyph->bitmap_left, -face->glyph->bitmap_top);
633
634 SkPaint paint;
635 // Using kMedium FilterQuality will cause mipmaps to be generated. Use
636 // kLow when the results will be roughly the same in order to avoid
637 // the mipmap generation cost.
638 // See skbug.com/6967
639 if (bitmapTransform.getMinScale() < 0.5) {
640 paint.setFilterQuality(kMedium_SkFilterQuality);
641 } else {
642 paint.setFilterQuality(kLow_SkFilterQuality);
643 }
644 canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
645
646 // If the destination is BW or LCD, convert from A8.
647 if (SkMask::kBW_Format == maskFormat) {
648 // Copy the A8 dstBitmap into the A1 glyph.fImage.
649 SkMask dstMask = glyph.mask();
650 packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
651 } else if (SkMask::kLCD16_Format == maskFormat) {
652 // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
653 uint8_t* src = dstBitmap.getAddr8(0, 0);
654 uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
655 for (int y = dstBitmap.height(); y --> 0;) {
656 for (int x = 0; x < dstBitmap.width(); ++x) {
657 dst[x] = grayToRGB16(src[x]);
658 }
659 dst = (uint16_t*)((char*)dst + glyph.rowBytes());
660 src += dstBitmap.rowBytes();
661 }
662 }
663
664 } break;
665
666 default:
667 SkDEBUGFAIL("unknown glyph format");
668 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
669 return;
670 }
671
672// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
673// it is optional
674#if defined(SK_GAMMA_APPLY_TO_A8)
675 if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
676 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
677 unsigned rowBytes = glyph.rowBytes();
678
679 for (int y = glyph.fHeight - 1; y >= 0; --y) {
680 for (int x = glyph.fWidth - 1; x >= 0; --x) {
681 dst[x] = fPreBlend.fG[dst[x]];
682 }
683 dst += rowBytes;
684 }
685 }
686#endif
687}
688
689///////////////////////////////////////////////////////////////////////////////
690
691namespace {
692
693class SkFTGeometrySink {
694 SkPath* fPath;
695 bool fStarted;
696 FT_Vector fCurrent;
697
698 void goingTo(const FT_Vector* pt) {
699 if (!fStarted) {
700 fStarted = true;
701 fPath->moveTo(SkFDot6ToScalar(fCurrent.x), -SkFDot6ToScalar(fCurrent.y));
702 }
703 fCurrent = *pt;
704 }
705
706 bool currentIsNot(const FT_Vector* pt) {
707 return fCurrent.x != pt->x || fCurrent.y != pt->y;
708 }
709
710 static int Move(const FT_Vector* pt, void* ctx) {
711 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
712 if (self.fStarted) {
713 self.fPath->close();
714 self.fStarted = false;
715 }
716 self.fCurrent = *pt;
717 return 0;
718 }
719
720 static int Line(const FT_Vector* pt, void* ctx) {
721 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
722 if (self.currentIsNot(pt)) {
723 self.goingTo(pt);
724 self.fPath->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
725 }
726 return 0;
727 }
728
729 static int Quad(const FT_Vector* pt0, const FT_Vector* pt1, void* ctx) {
730 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
731 if (self.currentIsNot(pt0) || self.currentIsNot(pt1)) {
732 self.goingTo(pt1);
733 self.fPath->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
734 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
735 }
736 return 0;
737 }
738
739 static int Cubic(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* pt2, void* ctx) {
740 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
741 if (self.currentIsNot(pt0) || self.currentIsNot(pt1) || self.currentIsNot(pt2)) {
742 self.goingTo(pt2);
743 self.fPath->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
744 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
745 SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
746 }
747 return 0;
748 }
749
750public:
751 SkFTGeometrySink(SkPath* path) : fPath{path}, fStarted{false}, fCurrent{0,0} {}
752
753 static constexpr const FT_Outline_Funcs Funcs{
754 /*move_to =*/ SkFTGeometrySink::Move,
755 /*line_to =*/ SkFTGeometrySink::Line,
756 /*conic_to =*/ SkFTGeometrySink::Quad,
757 /*cubic_to =*/ SkFTGeometrySink::Cubic,
758 /*shift = */ 0,
759 /*delta =*/ 0,
760 };
761};
762
763} // namespace
764
765bool SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, SkPath* path) {
766 SkFTGeometrySink sink{path};
767 FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &SkFTGeometrySink::Funcs, &sink);
768
769 if (err != 0) {
770 path->reset();
771 return false;
772 }
773
774 path->close();
775 return true;
776}
777
778bool SkScalerContext_FreeType_Base::generateFacePath(FT_Face face, SkGlyphID glyphID, SkPath* path) {
779 uint32_t flags = 0; //fLoadGlyphFlags;
780 flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
781 flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline)
782
783 FT_Error err = FT_Load_Glyph(face, glyphID, flags);
784 if (err != 0) {
785 path->reset();
786 return false;
787 }
788
789 if (!generateGlyphPath(face, path)) {
790 path->reset();
791 return false;
792 }
793 return true;
794}
795