OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2006-2012 The Android Open Source Project | 2 * Copyright 2006-2012 The Android Open Source Project |
3 * Copyright 2012 Mozilla Foundation | 3 * Copyright 2012 Mozilla Foundation |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "SkBitmap.h" | |
10 #include "SkCanvas.h" | |
11 #include "SkColor.h" | |
9 #include "SkColorPriv.h" | 12 #include "SkColorPriv.h" |
10 #include "SkFDot6.h" | 13 #include "SkFDot6.h" |
11 #include "SkFontHost_FreeType_common.h" | 14 #include "SkFontHost_FreeType_common.h" |
12 #include "SkPath.h" | 15 #include "SkPath.h" |
13 | 16 |
14 #include <ft2build.h> | 17 #include <ft2build.h> |
15 #include FT_OUTLINE_H | 18 #include FT_OUTLINE_H |
16 #include FT_BITMAP_H | 19 #include FT_BITMAP_H |
17 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file. | 20 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file. |
18 #include FT_SYNTHESIS_H | 21 #include FT_SYNTHESIS_H |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
53 } else { | 56 } else { |
54 SkASSERT(glyph.fHeight == bitmap.rows); | 57 SkASSERT(glyph.fHeight == bitmap.rows); |
55 } | 58 } |
56 | 59 |
57 uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage); | 60 uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage); |
58 const size_t dstRB = glyph.rowBytes(); | 61 const size_t dstRB = glyph.rowBytes(); |
59 const int width = glyph.fWidth; | 62 const int width = glyph.fWidth; |
60 const uint8_t* src = bitmap.buffer; | 63 const uint8_t* src = bitmap.buffer; |
61 | 64 |
62 switch (bitmap.pixel_mode) { | 65 switch (bitmap.pixel_mode) { |
63 case FT_PIXEL_MODE_MONO: { | 66 case FT_PIXEL_MODE_MONO: |
64 for (int y = 0; y < glyph.fHeight; ++y) { | 67 for (int y = 0; y < glyph.fHeight; ++y) { |
65 for (int x = 0; x < width; ++x) { | 68 for (int x = 0; x < width; ++x) { |
66 dst[x] = -bittst(src, x); | 69 dst[x] = -bittst(src, x); |
67 } | 70 } |
68 dst = (uint16_t*)((char*)dst + dstRB); | 71 dst = (uint16_t*)((char*)dst + dstRB); |
69 src += bitmap.pitch; | 72 src += bitmap.pitch; |
70 } | 73 } |
71 } break; | 74 break; |
72 case FT_PIXEL_MODE_GRAY: { | 75 case FT_PIXEL_MODE_GRAY: |
73 for (int y = 0; y < glyph.fHeight; ++y) { | 76 for (int y = 0; y < glyph.fHeight; ++y) { |
74 for (int x = 0; x < width; ++x) { | 77 for (int x = 0; x < width; ++x) { |
75 dst[x] = grayToRGB16(src[x]); | 78 dst[x] = grayToRGB16(src[x]); |
76 } | 79 } |
77 dst = (uint16_t*)((char*)dst + dstRB); | 80 dst = (uint16_t*)((char*)dst + dstRB); |
78 src += bitmap.pitch; | 81 src += bitmap.pitch; |
79 } | 82 } |
80 } break; | 83 break; |
81 default: { | 84 default: |
82 SkASSERT(lcdIsVert || (glyph.fWidth * 3 == bitmap.width)); | 85 SkASSERT(lcdIsVert || (glyph.fWidth * 3 == bitmap.width)); |
83 for (int y = 0; y < glyph.fHeight; y++) { | 86 for (int y = 0; y < glyph.fHeight; y++) { |
84 if (lcdIsVert) { // vertical stripes | 87 if (lcdIsVert) { // vertical stripes |
85 const uint8_t* srcR = src; | 88 const uint8_t* srcR = src; |
86 const uint8_t* srcG = srcR + bitmap.pitch; | 89 const uint8_t* srcG = srcR + bitmap.pitch; |
87 const uint8_t* srcB = srcG + bitmap.pitch; | 90 const uint8_t* srcB = srcG + bitmap.pitch; |
88 if (lcdIsBGR) { | 91 if (lcdIsBGR) { |
89 SkTSwap(srcR, srcB); | 92 SkTSwap(srcR, srcB); |
90 } | 93 } |
91 for (int x = 0; x < width; x++) { | 94 for (int x = 0; x < width; x++) { |
(...skipping 16 matching lines...) Expand all Loading... | |
108 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>( triple[0], tableR), | 111 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>( triple[0], tableR), |
109 sk_apply_lut_if<APPLY_PREBLEND>( triple[1], tableG), | 112 sk_apply_lut_if<APPLY_PREBLEND>( triple[1], tableG), |
110 sk_apply_lut_if<APPLY_PREBLEND>( triple[2], tableB)); | 113 sk_apply_lut_if<APPLY_PREBLEND>( triple[2], tableB)); |
111 triple += 3; | 114 triple += 3; |
112 } | 115 } |
113 } | 116 } |
114 src += bitmap.pitch; | 117 src += bitmap.pitch; |
115 } | 118 } |
116 dst = (uint16_t*)((char*)dst + dstRB); | 119 dst = (uint16_t*)((char*)dst + dstRB); |
117 } | 120 } |
118 } break; | 121 break; |
119 } | 122 } |
120 } | 123 } |
121 | 124 |
125 // copies an FT_Bitmap's pixel data into a buffer with identical dimensions | |
126 static void copyFTBitmap(const FT_Bitmap& srcFTBitmap, uint8_t* dst, uint8_t dst Format, | |
reed1
2013/11/13 20:21:46
Why are we passing uint8_t for the format type, in
reed1
2013/11/13 20:21:46
Since we are copying into a bitmap, why not pass i
violets
2013/11/19 18:38:06
SkGlyph::fMaskFormat, the value being passed into
violets
2013/11/19 18:38:06
One of the two calls to this function passes in gl
reed1
2013/11/20 21:52:12
I think that may be worth it, allowing us to have
reed1
2013/11/20 21:52:12
Ah, good point. Creating a bitmap just for that do
| |
127 size_t dstRowBytes) { | |
128 const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer); | |
129 size_t width = srcFTBitmap.width; | |
130 size_t height = srcFTBitmap.rows; | |
131 size_t srcRowBytes = srcFTBitmap.pitch; | |
132 | |
133 if ((SkMask::kA8_Format == dstFormat && | |
134 FT_PIXEL_MODE_GRAY == srcFTBitmap.pixel_mode) || | |
135 (SkMask::kBW_Format == dstFormat && | |
136 FT_PIXEL_MODE_MONO == srcFTBitmap.pixel_mode)) { | |
137 // TODO: test 1bpp bitmap font into kBW_Format glyph | |
138 size_t minRowBytes = SkMin32(srcRowBytes, dstRowBytes); | |
139 size_t extraRowBytes = dstRowBytes - minRowBytes; | |
140 for (int y = height - 1; y >= 0; --y) { | |
141 memcpy(dst, src, minRowBytes); | |
142 memset(dst + minRowBytes, 0, extraRowBytes); | |
143 src += srcRowBytes; | |
144 dst += dstRowBytes; | |
145 } | |
146 } else if (SkMask::kA8_Format == dstFormat && | |
147 FT_PIXEL_MODE_MONO == srcFTBitmap.pixel_mode) { | |
148 // TODO: test 1bpp bitmap font into kA8_Format glyph | |
149 for (size_t y = 0; y < height; ++y) { | |
150 uint8_t byte = 0; | |
151 int bits = 0; | |
152 const uint8_t* src_row = src; | |
153 uint8_t* dst_row = dst; | |
154 for (size_t x = 0; x < width; ++x) { | |
155 if (!bits) { | |
156 byte = *src_row++; | |
157 bits = 8; | |
158 } | |
159 *dst_row++ = byte & 0x80 ? 0xff : 0; | |
160 bits--; | |
161 byte <<= 1; | |
162 } | |
163 src += srcRowBytes; | |
164 dst += dstRowBytes; | |
165 } | |
166 #ifdef FT_LOAD_COLOR | |
167 } else if (SkMask::kARGB32_Format == dstFormat && | |
168 FT_PIXEL_MODE_BGRA == srcFTBitmap.pixel_mode) { | |
169 size_t minWidth = SkMin32(width, SkMin32(srcRowBytes, dstRowBytes) / 4); | |
170 size_t extraRowBytes = dstRowBytes - (4 * minWidth); | |
171 for (size_t y = 0; y < height; ++y) { | |
172 const uint8_t* src_row = src; | |
173 uint8_t* dst_row = dst; | |
174 for (size_t x = 0; x < minWidth; ++x) { | |
175 uint8_t blue = *src_row++; | |
176 uint8_t green = *src_row++; | |
177 uint8_t red = *src_row++; | |
178 uint8_t alpha = *src_row++; | |
179 *dst_row++ = red; | |
180 *dst_row++ = green; | |
181 *dst_row++ = blue; | |
182 *dst_row++ = alpha; | |
183 } | |
184 memset(dst_row, 0, extraRowBytes); | |
185 src += srcRowBytes; | |
186 dst += dstRowBytes; | |
187 } | |
188 #endif | |
189 } else { | |
190 SkDEBUGFAIL("unsupported combination of FT_PIXEL_MODE and SkMask::Format "); | |
191 } | |
192 } | |
193 | |
194 inline uint8_t skFormatForFTPixelMode(char pixel_mode) { | |
reed1
2013/11/13 20:21:46
1. Shouldn't this return SkMask::Format, instead o
violets
2013/11/19 18:38:06
1. I think that this should return the same type a
reed1
2013/11/20 21:52:12
I still vote for a named type, at least for the re
| |
195 switch (pixel_mode) { | |
196 case FT_PIXEL_MODE_GRAY: | |
197 return SkMask::kA8_Format; | |
198 case FT_PIXEL_MODE_MONO: | |
199 return SkMask::kBW_Format; | |
200 #ifdef FT_LOAD_COLOR | |
201 case FT_PIXEL_MODE_BGRA: | |
202 return SkMask::kARGB32_Format; | |
203 #endif | |
204 default: | |
205 SkDEBUGFAIL("unsupported FT_PIXEL_MODE"); | |
206 return SkMask::kA8_Format; | |
207 } | |
208 } | |
209 | |
210 inline SkBitmap::Config skConfigForFTPixelMode(char pixel_mode) { | |
reed1
2013/11/13 20:21:46
What is the type of pixel_mode? Is there an enum f
violets
2013/11/19 18:38:06
pixel_mode is type "char". There is an associated
| |
211 switch (pixel_mode) { | |
212 case FT_PIXEL_MODE_GRAY: | |
213 return SkBitmap::kA8_Config; | |
214 case FT_PIXEL_MODE_MONO: | |
215 return SkBitmap::kA1_Config; | |
216 #ifdef FT_LOAD_COLOR | |
217 case FT_PIXEL_MODE_BGRA: | |
218 return SkBitmap::kARGB_8888_Config; | |
219 #endif | |
220 default: | |
221 SkDEBUGFAIL("unsupported FT_PIXEL_MODE"); | |
222 return SkBitmap::kA8_Config; | |
223 } | |
224 } | |
225 | |
226 inline SkBitmap::Config skConfigForFormat(uint8_t format) { | |
reed1
2013/11/13 20:21:46
Can we declare format to be SkMask::Format ?
violets
2013/11/19 18:38:06
We can, but the uint8_t data that we pass into thi
reed1
2013/11/20 21:52:12
I do.
I'm also fine if we had a helper to SkGlyph
| |
227 switch (format) { | |
228 case SkMask::kA8_Format: | |
229 return SkBitmap::kA8_Config; | |
230 case SkMask::kBW_Format: | |
231 return SkBitmap::kA1_Config; | |
232 #ifdef FT_LOAD_COLOR | |
233 case SkMask::kARGB32_Format: | |
234 return SkBitmap::kARGB_8888_Config; | |
235 #endif | |
236 default: | |
237 SkDEBUGFAIL("unsupported FT_PIXEL_MODE"); | |
238 return SkBitmap::kA8_Config; | |
239 } | |
240 } | |
241 | |
122 void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGly ph& glyph) { | 242 void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGly ph& glyph) { |
123 const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Fla g); | 243 const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Fla g); |
124 const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Fl ag); | 244 const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Fl ag); |
125 | 245 |
126 switch ( face->glyph->format ) { | 246 switch ( face->glyph->format ) { |
127 case FT_GLYPH_FORMAT_OUTLINE: { | 247 case FT_GLYPH_FORMAT_OUTLINE: |
128 FT_Outline* outline = &face->glyph->outline; | 248 { |
bungeman-skia
2013/11/15 00:19:48
This introduces an unnecessary amount of indentati
violets
2013/11/19 18:38:06
Done.
| |
129 FT_BBox bbox; | 249 FT_Outline* outline = &face->glyph->outline; |
130 FT_Bitmap target; | 250 FT_BBox bbox; |
251 FT_Bitmap target; | |
131 | 252 |
132 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) { | 253 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag && |
133 emboldenOutline(face, outline); | 254 !(face->style_flags & FT_STYLE_FLAG_BOLD)) { |
255 emboldenOutline(face, outline); | |
256 } | |
257 | |
258 int dx = 0, dy = 0; | |
259 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { | |
260 dx = SkFixedToFDot6(glyph.getSubXFixed()); | |
261 dy = SkFixedToFDot6(glyph.getSubYFixed()); | |
262 // negate dy since freetype-y-goes-up and skia-y-goes-down | |
263 dy = -dy; | |
264 } | |
265 FT_Outline_Get_CBox(outline, &bbox); | |
266 /* | |
267 what we really want to do for subpixel is | |
268 offset(dx, dy) | |
269 compute_bounds | |
270 offset(bbox & !63) | |
271 but that is two calls to offset, so we do the following, whi ch | |
272 achieves the same thing with only one offset call. | |
273 */ | |
274 FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63), | |
275 dy - ((bbox.yMin + dy) & ~63)); | |
276 | |
277 if (SkMask::kLCD16_Format == glyph.fMaskFormat) { | |
278 FT_Render_Glyph(face->glyph, | |
279 doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MO DE_LCD); | |
280 if (fPreBlend.isApplicable()) { | |
281 copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, do Vert, | |
282 fPreBlend.fR, fPreBlend.fG, fPreBlend .fB); | |
283 } else { | |
284 copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, d oVert, | |
285 fPreBlend.fR, fPreBlend.fG, fPreBlen d.fB); | |
286 } | |
287 } else { | |
288 target.width = glyph.fWidth; | |
289 target.rows = glyph.fHeight; | |
290 target.pitch = glyph.rowBytes(); | |
291 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage); | |
292 target.pixel_mode = compute_pixel_mode( | |
293 (SkMask::Format)fRec.fMaskFo rmat); | |
294 target.num_grays = 256; | |
295 | |
296 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); | |
297 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target ); | |
298 } | |
299 } | |
300 break; | |
301 | |
302 case FT_GLYPH_FORMAT_BITMAP: | |
303 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag && | |
304 !(face->style_flags & FT_STYLE_FLAG_BOLD)) { | |
305 FT_GlyphSlot_Own_Bitmap(face->glyph); | |
306 FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap, k BitmapEmboldenStrength, 0); | |
134 } | 307 } |
135 | 308 |
136 int dx = 0, dy = 0; | |
137 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { | |
138 dx = SkFixedToFDot6(glyph.getSubXFixed()); | |
139 dy = SkFixedToFDot6(glyph.getSubYFixed()); | |
140 // negate dy since freetype-y-goes-up and skia-y-goes-down | |
141 dy = -dy; | |
142 } | |
143 FT_Outline_Get_CBox(outline, &bbox); | |
144 /* | |
145 what we really want to do for subpixel is | |
146 offset(dx, dy) | |
147 compute_bounds | |
148 offset(bbox & !63) | |
149 but that is two calls to offset, so we do the following, which | |
150 achieves the same thing with only one offset call. | |
151 */ | |
152 FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63), | |
153 dy - ((bbox.yMin + dy) & ~63)); | |
154 | |
155 if (SkMask::kLCD16_Format == glyph.fMaskFormat) { | 309 if (SkMask::kLCD16_Format == glyph.fMaskFormat) { |
156 FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_ RENDER_MODE_LCD); | 310 // special-case kLCD16_Format - no scaling currently supported |
311 SkASSERT_CONTINUE(glyph.fWidth == face->glyph->bitmap.width); | |
312 SkASSERT_CONTINUE(glyph.fHeight == face->glyph->bitmap.rows); | |
313 SkASSERT_CONTINUE(glyph.fTop == -face->glyph->bitmap_top); | |
314 SkASSERT_CONTINUE(glyph.fLeft == face->glyph->bitmap_left); | |
157 if (fPreBlend.isApplicable()) { | 315 if (fPreBlend.isApplicable()) { |
158 copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert , | 316 copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert , |
159 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB) ; | 317 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB) ; |
160 } else { | |
161 copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVer t, | |
162 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB ); | |
163 } | |
164 } else { | |
165 target.width = glyph.fWidth; | |
166 target.rows = glyph.fHeight; | |
167 target.pitch = glyph.rowBytes(); | |
168 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage); | |
169 target.pixel_mode = compute_pixel_mode( | |
170 (SkMask::Format)fRec.fMaskFormat ); | |
171 target.num_grays = 256; | |
172 | |
173 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); | |
174 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target); | |
175 } | |
176 } break; | |
177 | |
178 case FT_GLYPH_FORMAT_BITMAP: { | |
179 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) { | |
180 FT_GlyphSlot_Own_Bitmap(face->glyph); | |
181 FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap, k BitmapEmboldenStrength, 0); | |
182 } | |
183 SkASSERT_CONTINUE(glyph.fWidth == face->glyph->bitmap.width); | |
184 SkASSERT_CONTINUE(glyph.fHeight == face->glyph->bitmap.rows); | |
185 SkASSERT_CONTINUE(glyph.fTop == -face->glyph->bitmap_top); | |
186 SkASSERT_CONTINUE(glyph.fLeft == face->glyph->bitmap_left); | |
187 | |
188 const uint8_t* src = (const uint8_t*)face->glyph->bitmap.buffer; | |
189 uint8_t* dst = (uint8_t*)glyph.fImage; | |
190 | |
191 if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY || | |
192 (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && | |
193 glyph.fMaskFormat == SkMask::kBW_Format)) { | |
194 unsigned srcRowBytes = face->glyph->bitmap.pitch; | |
195 unsigned dstRowBytes = glyph.rowBytes(); | |
196 unsigned minRowBytes = SkMin32(srcRowBytes, dstRowBytes); | |
197 unsigned extraRowBytes = dstRowBytes - minRowBytes; | |
198 | |
199 for (int y = face->glyph->bitmap.rows - 1; y >= 0; --y) { | |
200 memcpy(dst, src, minRowBytes); | |
201 memset(dst + minRowBytes, 0, extraRowBytes); | |
202 src += srcRowBytes; | |
203 dst += dstRowBytes; | |
204 } | |
205 } else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && | |
206 glyph.fMaskFormat == SkMask::kA8_Format) { | |
207 for (int y = 0; y < face->glyph->bitmap.rows; ++y) { | |
208 uint8_t byte = 0; | |
209 int bits = 0; | |
210 const uint8_t* src_row = src; | |
211 uint8_t* dst_row = dst; | |
212 | |
213 for (int x = 0; x < face->glyph->bitmap.width; ++x) { | |
214 if (!bits) { | |
215 byte = *src_row++; | |
216 bits = 8; | |
217 } | |
218 | |
219 *dst_row++ = byte & 0x80 ? 0xff : 0; | |
220 bits--; | |
221 byte <<= 1; | |
222 } | |
223 | |
224 src += face->glyph->bitmap.pitch; | |
225 dst += glyph.rowBytes(); | |
226 } | |
227 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) { | |
228 if (fPreBlend.isApplicable()) { | |
229 copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert , | |
230 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB) ; | |
231 } else { | 318 } else { |
232 copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVer t, | 319 copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVer t, |
233 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB ); | 320 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB ); |
234 } | 321 } |
235 } else { | 322 } else { |
236 SkDEBUGFAIL("unknown glyph bitmap transform needed"); | 323 if (glyph.fWidth != face->glyph->bitmap.width || |
324 glyph.fHeight != face->glyph->bitmap.rows || | |
325 glyph.fTop != -face->glyph->bitmap_top || | |
326 glyph.fLeft != face->glyph->bitmap_left) { | |
327 // glyph image needs scaling | |
328 // start by copying FT2 image into an SkBitmap | |
329 SkBitmap unscaledBitmap; | |
330 unscaledBitmap.setConfig(skConfigForFTPixelMode(face->glyph- >bitmap.pixel_mode), | |
331 face->glyph->bitmap.width, | |
332 face->glyph->bitmap.rows); | |
333 unscaledBitmap.allocPixels(); | |
334 copyFTBitmap(face->glyph->bitmap, | |
335 reinterpret_cast<uint8_t*>(unscaledBitmap.getPi xels()), | |
336 skFormatForFTPixelMode(face->glyph->bitmap.pixe l_mode), | |
337 unscaledBitmap.rowBytes()); | |
338 // wrap the destination SkGlyph's image data into a bitmap | |
339 SkBitmap dstBitmap; | |
340 dstBitmap.setConfig(skConfigForFormat(glyph.fMaskFormat), | |
341 glyph.fWidth, glyph.fHeight, glyph.rowBytes()); | |
342 dstBitmap.setPixels(glyph.fImage); | |
343 // scale unscaledBitmap into dstBitmap | |
344 SkCanvas canvas(dstBitmap); | |
345 canvas.clear(SK_ColorTRANSPARENT); | |
346 canvas.scale(SkIntToScalar(glyph.fWidth) | |
347 / SkIntToScalar(face->glyph->bitmap.width), | |
348 SkIntToScalar(glyph.fHeight) | |
349 / SkIntToScalar(face->glyph->bitmap.rows)); | |
350 SkPaint paint; | |
351 paint.setFilterLevel(SkPaint::kLow_FilterLevel); | |
352 canvas.drawBitmap(unscaledBitmap, 0, 0, &paint); | |
353 } else { | |
354 // no scaling needed - directly copy glyph data | |
355 copyFTBitmap(face->glyph->bitmap, reinterpret_cast<uint8_t*> (glyph.fImage), | |
356 glyph.fMaskFormat, glyph.rowBytes()); | |
357 } | |
237 } | 358 } |
238 } break; | 359 break; |
239 | 360 |
240 default: | 361 default: |
241 SkDEBUGFAIL("unknown glyph format"); | 362 SkDEBUGFAIL("unknown glyph format"); |
242 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); | 363 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); |
243 return; | 364 return; |
244 } | 365 } |
245 | 366 |
246 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum, | 367 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum, |
247 // it is optional | 368 // it is optional |
248 #if defined(SK_GAMMA_APPLY_TO_A8) | 369 #if defined(SK_GAMMA_APPLY_TO_A8) |
249 if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) { | 370 if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) { |
250 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; | 371 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; |
251 unsigned rowBytes = glyph.rowBytes(); | 372 unsigned rowBytes = glyph.rowBytes(); |
252 | 373 |
253 for (int y = glyph.fHeight - 1; y >= 0; --y) { | 374 for (int y = glyph.fHeight - 1; y >= 0; --y) { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
318 path->close(); | 439 path->close(); |
319 } | 440 } |
320 | 441 |
321 void SkScalerContext_FreeType_Base::emboldenOutline(FT_Face face, FT_Outline* ou tline) | 442 void SkScalerContext_FreeType_Base::emboldenOutline(FT_Face face, FT_Outline* ou tline) |
322 { | 443 { |
323 FT_Pos strength; | 444 FT_Pos strength; |
324 strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale) | 445 strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale) |
325 / 24; | 446 / 24; |
326 FT_Outline_Embolden(outline, strength); | 447 FT_Outline_Embolden(outline, strength); |
327 } | 448 } |
OLD | NEW |