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 |
40 | const 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 | |
55 | namespace { |
56 | |
57 | FT_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 | |
69 | uint16_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 | |
78 | uint16_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 | |
85 | int 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 | */ |
99 | template<bool APPLY_PREBLEND> |
100 | void 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 | */ |
202 | void 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 | |
285 | inline 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 | |
291 | uint8_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 | |
300 | void 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 | |
331 | inline 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 | |
343 | inline 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 | |
356 | inline 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 | |
372 | void 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 | |
691 | namespace { |
692 | |
693 | class 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 | |
750 | public: |
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 | |
765 | bool 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 | |
778 | bool 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 | |