Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: src/ports/SkFontHost_FreeType_common.cpp

Issue 23684041: improve bitmap font support (FreeType only) (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: a round of type-specificity... Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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, SkMask& dstMask) {
127 const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
128 uint8_t* dst = dstMask.fImage;
129 const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat );
130 size_t dstRowBytes = dstMask.fRowBytes;
131 size_t width = srcFTBitmap.width;
132 size_t height = srcFTBitmap.rows;
133 size_t srcRowBytes = srcFTBitmap.pitch;
134
135 if ((SkMask::kA8_Format == dstFormat &&
136 FT_PIXEL_MODE_GRAY == srcFTBitmap.pixel_mode) ||
137 (SkMask::kBW_Format == dstFormat &&
138 FT_PIXEL_MODE_MONO == srcFTBitmap.pixel_mode)) {
139 // TODO: test 1bpp bitmap font into kBW_Format glyph
140 size_t minRowBytes = SkMin32(srcRowBytes, dstRowBytes);
141 size_t extraRowBytes = dstRowBytes - minRowBytes;
142 for (int y = height - 1; y >= 0; --y) {
143 memcpy(dst, src, minRowBytes);
144 memset(dst + minRowBytes, 0, extraRowBytes);
145 src += srcRowBytes;
146 dst += dstRowBytes;
147 }
148 } else if (SkMask::kA8_Format == dstFormat &&
149 FT_PIXEL_MODE_MONO == srcFTBitmap.pixel_mode) {
150 // TODO: test 1bpp bitmap font into kA8_Format glyph
151 for (size_t y = 0; y < height; ++y) {
152 uint8_t byte = 0;
153 int bits = 0;
154 const uint8_t* src_row = src;
155 uint8_t* dst_row = dst;
156 for (size_t x = 0; x < width; ++x) {
157 if (!bits) {
158 byte = *src_row++;
159 bits = 8;
160 }
161 *dst_row++ = byte & 0x80 ? 0xff : 0;
162 bits--;
163 byte <<= 1;
164 }
165 src += srcRowBytes;
166 dst += dstRowBytes;
167 }
168 #ifdef FT_LOAD_COLOR
bungeman-skia 2013/11/22 18:09:14 Same here (and three more instances below), should
169 } else if (SkMask::kARGB32_Format == dstFormat &&
170 FT_PIXEL_MODE_BGRA == srcFTBitmap.pixel_mode) {
171 size_t minWidth = SkMin32(width, SkMin32(srcRowBytes, dstRowBytes) / 4);
172 size_t extraRowBytes = dstRowBytes - (4 * minWidth);
173 for (size_t y = 0; y < height; ++y) {
174 const uint8_t* src_row = src;
175 uint8_t* dst_row = dst;
176 for (size_t x = 0; x < minWidth; ++x) {
177 uint8_t blue = *src_row++;
178 uint8_t green = *src_row++;
179 uint8_t red = *src_row++;
180 uint8_t alpha = *src_row++;
181 *dst_row++ = red;
182 *dst_row++ = green;
183 *dst_row++ = blue;
184 *dst_row++ = alpha;
185 }
186 memset(dst_row, 0, extraRowBytes);
187 src += srcRowBytes;
188 dst += dstRowBytes;
189 }
190 #endif
191 } else {
192 SkDEBUGFAIL("unsupported combination of FT_PIXEL_MODE and SkMask::Format ");
193 }
194 }
195
196 inline SkMask::Format skFormatForFTPixelMode(FT_Pixel_Mode pixel_mode) {
197 switch (pixel_mode) {
198 case FT_PIXEL_MODE_GRAY:
199 return SkMask::kA8_Format;
200 case FT_PIXEL_MODE_MONO:
201 return SkMask::kBW_Format;
202 #ifdef FT_LOAD_COLOR
203 case FT_PIXEL_MODE_BGRA:
204 return SkMask::kARGB32_Format;
205 #endif
206 default:
207 SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
208 return SkMask::kA8_Format;
209 }
210 }
211
212 inline SkBitmap::Config skConfigForFTPixelMode(FT_Pixel_Mode pixel_mode) {
213 switch (pixel_mode) {
214 case FT_PIXEL_MODE_GRAY:
215 return SkBitmap::kA8_Config;
216 case FT_PIXEL_MODE_MONO:
217 return SkBitmap::kA1_Config;
218 #ifdef FT_LOAD_COLOR
219 case FT_PIXEL_MODE_BGRA:
220 return SkBitmap::kARGB_8888_Config;
221 #endif
222 default:
223 SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
224 return SkBitmap::kA8_Config;
225 }
226 }
227
228 inline SkBitmap::Config skConfigForFormat(SkMask::Format format) {
229 switch (format) {
230 case SkMask::kA8_Format:
231 return SkBitmap::kA8_Config;
232 case SkMask::kBW_Format:
233 return SkBitmap::kA1_Config;
234 #ifdef FT_LOAD_COLOR
235 case SkMask::kARGB32_Format:
236 return SkBitmap::kARGB_8888_Config;
237 #endif
238 default:
239 SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
240 return SkBitmap::kA8_Config;
241 }
242 }
243
122 void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGly ph& glyph) { 244 void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGly ph& glyph) {
123 const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Fla g); 245 const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Fla g);
124 const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Fl ag); 246 const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Fl ag);
125 247
126 switch ( face->glyph->format ) { 248 switch ( face->glyph->format ) {
127 case FT_GLYPH_FORMAT_OUTLINE: { 249 case FT_GLYPH_FORMAT_OUTLINE: {
128 FT_Outline* outline = &face->glyph->outline; 250 FT_Outline* outline = &face->glyph->outline;
129 FT_BBox bbox; 251 FT_BBox bbox;
130 FT_Bitmap target; 252 FT_Bitmap target;
131 253
132 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) { 254 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
255 !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
133 emboldenOutline(face, outline); 256 emboldenOutline(face, outline);
134 } 257 }
135 258
136 int dx = 0, dy = 0; 259 int dx = 0, dy = 0;
137 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 260 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
138 dx = SkFixedToFDot6(glyph.getSubXFixed()); 261 dx = SkFixedToFDot6(glyph.getSubXFixed());
139 dy = SkFixedToFDot6(glyph.getSubYFixed()); 262 dy = SkFixedToFDot6(glyph.getSubYFixed());
140 // negate dy since freetype-y-goes-up and skia-y-goes-down 263 // negate dy since freetype-y-goes-up and skia-y-goes-down
141 dy = -dy; 264 dy = -dy;
142 } 265 }
(...skipping 16 matching lines...) Expand all
159 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB) ; 282 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB) ;
160 } else { 283 } else {
161 copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVer t, 284 copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVer t,
162 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB ); 285 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB );
163 } 286 }
164 } else { 287 } else {
165 target.width = glyph.fWidth; 288 target.width = glyph.fWidth;
166 target.rows = glyph.fHeight; 289 target.rows = glyph.fHeight;
167 target.pitch = glyph.rowBytes(); 290 target.pitch = glyph.rowBytes();
168 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage); 291 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
169 target.pixel_mode = compute_pixel_mode( 292 target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMa skFormat);
170 (SkMask::Format)fRec.fMaskFormat );
171 target.num_grays = 256; 293 target.num_grays = 256;
172 294
173 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); 295 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
174 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target); 296 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
175 } 297 }
176 } break; 298 }
299 break;
177 300
178 case FT_GLYPH_FORMAT_BITMAP: { 301 case FT_GLYPH_FORMAT_BITMAP:
179 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) { 302 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
303 !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
180 FT_GlyphSlot_Own_Bitmap(face->glyph); 304 FT_GlyphSlot_Own_Bitmap(face->glyph);
181 FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap, k BitmapEmboldenStrength, 0); 305 FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap,
306 kBitmapEmboldenStrength, 0);
182 } 307 }
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 308
188 const uint8_t* src = (const uint8_t*)face->glyph->bitmap.buffer; 309 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
189 uint8_t* dst = (uint8_t*)glyph.fImage; 310 // special-case kLCD16_Format - no scaling currently supported
190 311 SkASSERT_CONTINUE(glyph.fWidth == face->glyph->bitmap.width);
191 if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY || 312 SkASSERT_CONTINUE(glyph.fHeight == face->glyph->bitmap.rows);
192 (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && 313 SkASSERT_CONTINUE(glyph.fTop == -face->glyph->bitmap_top);
193 glyph.fMaskFormat == SkMask::kBW_Format)) { 314 SkASSERT_CONTINUE(glyph.fLeft == face->glyph->bitmap_left);
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()) { 315 if (fPreBlend.isApplicable()) {
229 copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert , 316 copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert ,
230 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB) ; 317 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 FT_Pixel_Mode pixel_mode =
331 static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel _mode);
332 unscaledBitmap.setConfig(skConfigForFTPixelMode(pixel_mode),
333 face->glyph->bitmap.width,
334 face->glyph->bitmap.rows);
335 unscaledBitmap.allocPixels();
336 SkMask dstMask;
337 dstMask.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.g etPixels());
338 dstMask.fRowBytes = unscaledBitmap.rowBytes();
339 dstMask.fFormat = skFormatForFTPixelMode(pixel_mode);
340 copyFTBitmap(face->glyph->bitmap, dstMask);
341 // wrap the destination SkGlyph's image data into a bitmap
342 SkBitmap dstBitmap;
343 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyp h.fMaskFormat);
344 dstBitmap.setConfig(skConfigForFormat(maskFormat),
345 glyph.fWidth, glyph.fHeight, glyph.rowBytes());
346 dstBitmap.setPixels(glyph.fImage);
347 // scale unscaledBitmap into dstBitmap
348 SkCanvas canvas(dstBitmap);
349 canvas.clear(SK_ColorTRANSPARENT);
350 canvas.scale(SkIntToScalar(glyph.fWidth)
351 / SkIntToScalar(face->glyph->bitmap.width),
352 SkIntToScalar(glyph.fHeight)
353 / SkIntToScalar(face->glyph->bitmap.rows));
354 SkPaint paint;
355 paint.setFilterLevel(SkPaint::kLow_FilterLevel);
356 canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
357 } else {
358 // no scaling needed - directly copy glyph data
359 SkMask dstMask;
360 glyph.toMask(&dstMask);
361 copyFTBitmap(face->glyph->bitmap, dstMask);
362 }
237 } 363 }
238 } break; 364 break;
239 365
240 default: 366 default:
241 SkDEBUGFAIL("unknown glyph format"); 367 SkDEBUGFAIL("unknown glyph format");
242 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); 368 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
243 return; 369 return;
244 } 370 }
245 371
246 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum, 372 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
247 // it is optional 373 // it is optional
248 #if defined(SK_GAMMA_APPLY_TO_A8) 374 #if defined(SK_GAMMA_APPLY_TO_A8)
249 if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) { 375 if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
250 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; 376 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
251 unsigned rowBytes = glyph.rowBytes(); 377 unsigned rowBytes = glyph.rowBytes();
252 378
253 for (int y = glyph.fHeight - 1; y >= 0; --y) { 379 for (int y = glyph.fHeight - 1; y >= 0; --y) {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 path->close(); 444 path->close();
319 } 445 }
320 446
321 void SkScalerContext_FreeType_Base::emboldenOutline(FT_Face face, FT_Outline* ou tline) 447 void SkScalerContext_FreeType_Base::emboldenOutline(FT_Face face, FT_Outline* ou tline)
322 { 448 {
323 FT_Pos strength; 449 FT_Pos strength;
324 strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale) 450 strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale)
325 / 24; 451 / 24;
326 FT_Outline_Embolden(outline, strength); 452 FT_Outline_Embolden(outline, strength);
327 } 453 }
OLDNEW
« src/ports/SkFontHost_FreeType.cpp ('K') | « src/ports/SkFontHost_FreeType.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698