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, |
| 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) { |
| 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) { |
| 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) { |
| 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 { |
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 |