OLD | NEW |
| (Empty) |
1 /* libs/graphics/ports/SkFontHost_FreeType.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkScalerContext.h" | |
19 #include "SkBitmap.h" | |
20 #include "SkCanvas.h" | |
21 #include "SkDescriptor.h" | |
22 #include "SkFDot6.h" | |
23 #include "SkFontHost.h" | |
24 #include "SkMask.h" | |
25 #include "SkStream.h" | |
26 #include "SkString.h" | |
27 #include "SkThread.h" | |
28 #include "SkTemplates.h" | |
29 | |
30 #include <ft2build.h> | |
31 #include FT_FREETYPE_H | |
32 #include FT_OUTLINE_H | |
33 #include FT_SIZES_H | |
34 #include FT_TRUETYPE_TABLES_H | |
35 #ifdef FT_ADVANCES_H | |
36 #include FT_ADVANCES_H | |
37 #endif | |
38 | |
39 #if 0 | |
40 // Also include the files by name for build tools which require this. | |
41 #include <freetype/freetype.h> | |
42 #include <freetype/ftoutln.h> | |
43 #include <freetype/ftsizes.h> | |
44 #include <freetype/tttables.h> | |
45 #include <freetype/ftadvanc.h> | |
46 #endif | |
47 | |
48 //#define ENABLE_GLYPH_SPEW // for tracing calls | |
49 //#define DUMP_STRIKE_CREATION | |
50 | |
51 #ifdef SK_DEBUG | |
52 #define SkASSERT_CONTINUE(pred)
\ | |
53 do {
\ | |
54 if (!(pred))
\ | |
55 SkDebugf("file %s:%d: assert failed '" #pred "'\n", __FILE__, __
LINE__); \ | |
56 } while (false) | |
57 #else | |
58 #define SkASSERT_CONTINUE(pred) | |
59 #endif | |
60 | |
61 ////////////////////////////////////////////////////////////////////////// | |
62 | |
63 struct SkFaceRec; | |
64 | |
65 static SkMutex gFTMutex; | |
66 static int gFTCount; | |
67 static FT_Library gFTLibrary; | |
68 static SkFaceRec* gFaceRecHead; | |
69 | |
70 ///////////////////////////////////////////////////////////////////////// | |
71 | |
72 class SkScalerContext_FreeType : public SkScalerContext { | |
73 public: | |
74 SkScalerContext_FreeType(const SkDescriptor* desc); | |
75 virtual ~SkScalerContext_FreeType(); | |
76 | |
77 bool success() const { | |
78 return fFaceRec != NULL && fFTSize != NULL; | |
79 } | |
80 | |
81 protected: | |
82 virtual unsigned generateGlyphCount() const; | |
83 virtual uint16_t generateCharToGlyph(SkUnichar uni); | |
84 virtual void generateAdvance(SkGlyph* glyph); | |
85 virtual void generateMetrics(SkGlyph* glyph); | |
86 virtual void generateImage(const SkGlyph& glyph); | |
87 virtual void generatePath(const SkGlyph& glyph, SkPath* path); | |
88 virtual void generateFontMetrics(SkPaint::FontMetrics* mx, | |
89 SkPaint::FontMetrics* my); | |
90 | |
91 private: | |
92 SkFaceRec* fFaceRec; | |
93 FT_Face fFace; // reference to shared face in gFaceRecHead | |
94 FT_Size fFTSize; // our own copy | |
95 SkFixed fScaleX, fScaleY; | |
96 FT_Matrix fMatrix22; | |
97 uint32_t fLoadGlyphFlags; | |
98 | |
99 FT_Error setupSize(); | |
100 }; | |
101 | |
102 /////////////////////////////////////////////////////////////////////////// | |
103 /////////////////////////////////////////////////////////////////////////// | |
104 | |
105 #include "SkStream.h" | |
106 | |
107 struct SkFaceRec { | |
108 SkFaceRec* fNext; | |
109 FT_Face fFace; | |
110 FT_StreamRec fFTStream; | |
111 SkStream* fSkStream; | |
112 uint32_t fRefCnt; | |
113 uint32_t fFontID; | |
114 | |
115 // assumes ownership of the stream, will call unref() when its done | |
116 SkFaceRec(SkStream* strm, uint32_t fontID); | |
117 ~SkFaceRec() { | |
118 fSkStream->unref(); | |
119 } | |
120 }; | |
121 | |
122 extern "C" { | |
123 static unsigned long sk_stream_read(FT_Stream stream, | |
124 unsigned long offset, | |
125 unsigned char* buffer, | |
126 unsigned long count ) { | |
127 SkStream* str = (SkStream*)stream->descriptor.pointer; | |
128 | |
129 if (count) { | |
130 if (!str->rewind()) { | |
131 return 0; | |
132 } else { | |
133 unsigned long ret; | |
134 if (offset) { | |
135 ret = str->read(NULL, offset); | |
136 if (ret != offset) { | |
137 return 0; | |
138 } | |
139 } | |
140 ret = str->read(buffer, count); | |
141 if (ret != count) { | |
142 return 0; | |
143 } | |
144 count = ret; | |
145 } | |
146 } | |
147 return count; | |
148 } | |
149 | |
150 static void sk_stream_close( FT_Stream stream) {} | |
151 } | |
152 | |
153 SkFaceRec::SkFaceRec(SkStream* strm, uint32_t fontID) | |
154 : fSkStream(strm), fFontID(fontID) { | |
155 // SkDEBUGF(("SkFaceRec: opening %s (%p)\n", key.c_str(), strm)); | |
156 | |
157 bzero(&fFTStream, sizeof(fFTStream)); | |
158 fFTStream.size = fSkStream->getLength(); | |
159 fFTStream.descriptor.pointer = fSkStream; | |
160 fFTStream.read = sk_stream_read; | |
161 fFTStream.close = sk_stream_close; | |
162 } | |
163 | |
164 // Will return 0 on failure | |
165 static SkFaceRec* ref_ft_face(uint32_t fontID) { | |
166 SkFaceRec* rec = gFaceRecHead; | |
167 while (rec) { | |
168 if (rec->fFontID == fontID) { | |
169 SkASSERT(rec->fFace); | |
170 rec->fRefCnt += 1; | |
171 return rec; | |
172 } | |
173 rec = rec->fNext; | |
174 } | |
175 | |
176 SkStream* strm = SkFontHost::OpenStream(fontID); | |
177 if (NULL == strm) { | |
178 SkDEBUGF(("SkFontHost::OpenStream failed opening %x\n", fontID)); | |
179 return 0; | |
180 } | |
181 | |
182 // this passes ownership of strm to the rec | |
183 rec = SkNEW_ARGS(SkFaceRec, (strm, fontID)); | |
184 | |
185 FT_Open_Args args; | |
186 memset(&args, 0, sizeof(args)); | |
187 const void* memoryBase = strm->getMemoryBase(); | |
188 | |
189 if (NULL != memoryBase) { | |
190 //printf("mmap(%s)\n", keyString.c_str()); | |
191 args.flags = FT_OPEN_MEMORY; | |
192 args.memory_base = (const FT_Byte*)memoryBase; | |
193 args.memory_size = strm->getLength(); | |
194 } else { | |
195 //printf("fopen(%s)\n", keyString.c_str()); | |
196 args.flags = FT_OPEN_STREAM; | |
197 args.stream = &rec->fFTStream; | |
198 } | |
199 | |
200 FT_Error err = FT_Open_Face(gFTLibrary, &args, 0, &rec->fFace); | |
201 | |
202 if (err) { // bad filename, try the default font | |
203 fprintf(stderr, "ERROR: unable to open font '%x'\n", fontID); | |
204 SkDELETE(rec); | |
205 return 0; | |
206 } else { | |
207 SkASSERT(rec->fFace); | |
208 //fprintf(stderr, "Opened font '%s'\n", filename.c_str()); | |
209 rec->fNext = gFaceRecHead; | |
210 gFaceRecHead = rec; | |
211 rec->fRefCnt = 1; | |
212 return rec; | |
213 } | |
214 } | |
215 | |
216 static void unref_ft_face(FT_Face face) { | |
217 SkFaceRec* rec = gFaceRecHead; | |
218 SkFaceRec* prev = NULL; | |
219 while (rec) { | |
220 SkFaceRec* next = rec->fNext; | |
221 if (rec->fFace == face) { | |
222 if (--rec->fRefCnt == 0) { | |
223 if (prev) { | |
224 prev->fNext = next; | |
225 } else { | |
226 gFaceRecHead = next; | |
227 } | |
228 FT_Done_Face(face); | |
229 SkDELETE(rec); | |
230 } | |
231 return; | |
232 } | |
233 prev = rec; | |
234 rec = next; | |
235 } | |
236 SkASSERT("shouldn't get here, face not in list"); | |
237 } | |
238 | |
239 /////////////////////////////////////////////////////////////////////////// | |
240 | |
241 SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) | |
242 : SkScalerContext(desc) { | |
243 SkAutoMutexAcquire ac(gFTMutex); | |
244 | |
245 FT_Error err; | |
246 | |
247 if (gFTCount == 0) { | |
248 err = FT_Init_FreeType(&gFTLibrary); | |
249 // SkDEBUGF(("FT_Init_FreeType returned %d\n", err)); | |
250 SkASSERT(err == 0); | |
251 } | |
252 ++gFTCount; | |
253 | |
254 // load the font file | |
255 fFTSize = NULL; | |
256 fFace = NULL; | |
257 fFaceRec = ref_ft_face(fRec.fFontID); | |
258 if (NULL == fFaceRec) { | |
259 return; | |
260 } | |
261 fFace = fFaceRec->fFace; | |
262 | |
263 // compute our factors from the record | |
264 | |
265 SkMatrix m; | |
266 | |
267 fRec.getSingleMatrix(&m); | |
268 | |
269 #ifdef DUMP_STRIKE_CREATION | |
270 SkString keyString; | |
271 SkFontHost::GetDescriptorKeyString(desc, &keyString); | |
272 printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n",
SkScalarToFloat(fRec.fTextSize), | |
273 SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX), | |
274 SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0
][1]), | |
275 SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1
][1]), | |
276 fRec.fHints, fRec.fMaskFormat, keyString.c_str()); | |
277 #endif | |
278 | |
279 // now compute our scale factors | |
280 SkScalar sx = m.getScaleX(); | |
281 SkScalar sy = m.getScaleY(); | |
282 | |
283 if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) { | |
284 // sort of give up on hinting | |
285 sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX())); | |
286 sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy)); | |
287 sx = sy = SkScalarAve(sx, sy); | |
288 | |
289 SkScalar inv = SkScalarInvert(sx); | |
290 | |
291 // flip the skew elements to go from our Y-down system to FreeType's | |
292 fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv)); | |
293 fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv)); | |
294 fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv)); | |
295 fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv)); | |
296 } else { | |
297 fMatrix22.xx = fMatrix22.yy = SK_Fixed1; | |
298 fMatrix22.xy = fMatrix22.yx = 0; | |
299 } | |
300 | |
301 fScaleX = SkScalarToFixed(sx); | |
302 fScaleY = SkScalarToFixed(sy); | |
303 | |
304 // compute the flags we send to Load_Glyph | |
305 { | |
306 uint32_t flags = FT_LOAD_DEFAULT; | |
307 uint32_t render_flags = FT_LOAD_TARGET_NORMAL; | |
308 | |
309 // we force autohinting at the moment | |
310 | |
311 switch (fRec.fHints) { | |
312 case kNo_Hints: | |
313 flags |= FT_LOAD_NO_HINTING; | |
314 break; | |
315 case kSubpixel_Hints: | |
316 flags |= FT_LOAD_FORCE_AUTOHINT; | |
317 render_flags = FT_LOAD_TARGET_LIGHT; | |
318 break; | |
319 case kNormal_Hints: | |
320 #ifdef ANDROID | |
321 // The following line disables the font's hinting tables. For | |
322 // Chromium we want font hinting on so that we can generate | |
323 // baselines that look at little like Firefox. It's expected that | |
324 // Mike Reed will rework this code sometime soon so we don't wish | |
325 // to make more extensive changes. | |
326 flags |= FT_LOAD_FORCE_AUTOHINT; | |
327 /* Switch to light hinting (vertical only) to address some chars | |
328 that behaved poorly with NORMAL. In the future we could consider | |
329 making this choice exposed at runtime to the caller. | |
330 */ | |
331 render_flags = FT_LOAD_TARGET_LIGHT; | |
332 #endif | |
333 break; | |
334 } | |
335 | |
336 if (SkMask::kBW_Format == fRec.fMaskFormat) | |
337 render_flags = FT_LOAD_TARGET_MONO; | |
338 else if (SkMask::kLCD_Format == fRec.fMaskFormat) | |
339 render_flags = FT_LOAD_TARGET_LCD; | |
340 | |
341 fLoadGlyphFlags = flags | render_flags; | |
342 } | |
343 | |
344 // now create the FT_Size | |
345 | |
346 { | |
347 FT_Error err; | |
348 | |
349 err = FT_New_Size(fFace, &fFTSize); | |
350 if (err != 0) { | |
351 SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Si
ze(0x%x, 0x%x) returned 0x%x\n", | |
352 fFaceRec->fFontID, fScaleX, fScaleY, err)); | |
353 fFace = NULL; | |
354 return; | |
355 } | |
356 | |
357 err = FT_Activate_Size(fFTSize); | |
358 if (err != 0) { | |
359 SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x
) returned 0x%x\n", | |
360 fFaceRec->fFontID, fScaleX, fScaleY, err)); | |
361 fFTSize = NULL; | |
362 } | |
363 | |
364 err = FT_Set_Char_Size( fFace, | |
365 SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY)
, | |
366 72, 72); | |
367 if (err != 0) { | |
368 SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x
) returned 0x%x\n", | |
369 fFaceRec->fFontID, fScaleX, fScaleY, err)); | |
370 fFace = NULL; | |
371 return; | |
372 } | |
373 | |
374 FT_Set_Transform( fFace, &fMatrix22, NULL); | |
375 } | |
376 } | |
377 | |
378 SkScalerContext_FreeType::~SkScalerContext_FreeType() { | |
379 if (fFTSize != NULL) { | |
380 FT_Done_Size(fFTSize); | |
381 } | |
382 | |
383 SkAutoMutexAcquire ac(gFTMutex); | |
384 | |
385 if (fFace != NULL) { | |
386 unref_ft_face(fFace); | |
387 } | |
388 if (--gFTCount == 0) { | |
389 // SkDEBUGF(("FT_Done_FreeType\n")); | |
390 FT_Done_FreeType(gFTLibrary); | |
391 SkDEBUGCODE(gFTLibrary = NULL;) | |
392 } | |
393 } | |
394 | |
395 /* We call this before each use of the fFace, since we may be sharing | |
396 this face with other context (at different sizes). | |
397 */ | |
398 FT_Error SkScalerContext_FreeType::setupSize() { | |
399 if (SkFontHost::ResolveTypeface(fRec.fFontID) == NULL) { | |
400 return (FT_Error)-1; | |
401 } | |
402 | |
403 FT_Error err = FT_Activate_Size(fFTSize); | |
404 | |
405 if (err != 0) { | |
406 SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) re
turned 0x%x\n", | |
407 fFaceRec->fFontID, fScaleX, fScaleY, err)); | |
408 fFTSize = NULL; | |
409 } else { | |
410 // seems we need to reset this every time (not sure why, but without it | |
411 // I get random italics from some other fFTSize) | |
412 FT_Set_Transform( fFace, &fMatrix22, NULL); | |
413 } | |
414 return err; | |
415 } | |
416 | |
417 unsigned SkScalerContext_FreeType::generateGlyphCount() const { | |
418 return fFace->num_glyphs; | |
419 } | |
420 | |
421 uint16_t SkScalerContext_FreeType::generateCharToGlyph(SkUnichar uni) { | |
422 return SkToU16(FT_Get_Char_Index( fFace, uni )); | |
423 } | |
424 | |
425 static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) { | |
426 switch (format) { | |
427 case SkMask::kBW_Format: | |
428 return FT_PIXEL_MODE_MONO; | |
429 case SkMask::kLCD_Format: | |
430 return FT_PIXEL_MODE_LCD; | |
431 case SkMask::kA8_Format: | |
432 default: | |
433 return FT_PIXEL_MODE_GRAY; | |
434 } | |
435 } | |
436 | |
437 void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) { | |
438 #ifdef FT_ADVANCES_H | |
439 /* unhinted and light hinted text have linearly scaled advances | |
440 * which are very cheap to compute with some font formats... | |
441 */ | |
442 { | |
443 SkAutoMutexAcquire ac(gFTMutex); | |
444 | |
445 if (this->setupSize()) { | |
446 glyph->zeroMetrics(); | |
447 return; | |
448 } | |
449 | |
450 FT_Error error; | |
451 FT_Fixed advance; | |
452 | |
453 error = FT_Get_Advance( fFace, glyph->getGlyphID(fBaseGlyphCount), | |
454 fLoadGlyphFlags | FT_ADVANCE_FLAG_FAST_ONLY, | |
455 &advance ); | |
456 if (0 == error) { | |
457 glyph->fRsbDelta = 0; | |
458 glyph->fLsbDelta = 0; | |
459 glyph->fAdvanceX = advance; // advance *2/3; //DEBUG | |
460 glyph->fAdvanceY = 0; | |
461 return; | |
462 } | |
463 } | |
464 #endif /* FT_ADVANCES_H */ | |
465 /* otherwise, we need to load/hint the glyph, which is slower */ | |
466 this->generateMetrics(glyph); | |
467 return; | |
468 } | |
469 | |
470 void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { | |
471 SkAutoMutexAcquire ac(gFTMutex); | |
472 | |
473 glyph->fRsbDelta = 0; | |
474 glyph->fLsbDelta = 0; | |
475 | |
476 FT_Error err; | |
477 | |
478 if (this->setupSize()) { | |
479 goto ERROR; | |
480 } | |
481 | |
482 err = FT_Load_Glyph( fFace, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFl
ags ); | |
483 if (err != 0) { | |
484 SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%x): FT_Load_Glyph(
glyph:%d flags:%d) returned 0x%x\n", | |
485 fFaceRec->fFontID, glyph->getGlyphID(fBaseGlyphCount), fLoad
GlyphFlags, err)); | |
486 ERROR: | |
487 glyph->zeroMetrics(); | |
488 return; | |
489 } | |
490 | |
491 switch ( fFace->glyph->format ) { | |
492 case FT_GLYPH_FORMAT_OUTLINE: | |
493 FT_BBox bbox; | |
494 | |
495 FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox); | |
496 | |
497 if (kSubpixel_Hints == fRec.fHints) { | |
498 int dx = glyph->getSubXFixed() >> 10; | |
499 int dy = glyph->getSubYFixed() >> 10; | |
500 // negate dy since freetype-y-goes-up and skia-y-goes-down | |
501 bbox.xMin += dx; | |
502 bbox.yMin -= dy; | |
503 bbox.xMax += dx; | |
504 bbox.yMax -= dy; | |
505 } | |
506 | |
507 bbox.xMin &= ~63; | |
508 bbox.yMin &= ~63; | |
509 bbox.xMax = (bbox.xMax + 63) & ~63; | |
510 bbox.yMax = (bbox.yMax + 63) & ~63; | |
511 | |
512 glyph->fWidth = SkToU16((bbox.xMax - bbox.xMin) >> 6); | |
513 glyph->fHeight = SkToU16((bbox.yMax - bbox.yMin) >> 6); | |
514 glyph->fTop = -SkToS16(bbox.yMax >> 6); | |
515 glyph->fLeft = SkToS16(bbox.xMin >> 6); | |
516 break; | |
517 | |
518 case FT_GLYPH_FORMAT_BITMAP: | |
519 glyph->fWidth = SkToU16(fFace->glyph->bitmap.width); | |
520 glyph->fHeight = SkToU16(fFace->glyph->bitmap.rows); | |
521 glyph->fTop = -SkToS16(fFace->glyph->bitmap_top); | |
522 glyph->fLeft = SkToS16(fFace->glyph->bitmap_left); | |
523 break; | |
524 | |
525 default: | |
526 SkASSERT(!"unknown glyph format"); | |
527 goto ERROR; | |
528 } | |
529 | |
530 if (kNormal_Hints == fRec.fHints) { | |
531 glyph->fAdvanceX = SkFDot6ToFixed(fFace->glyph->advance.x); | |
532 glyph->fAdvanceY = -SkFDot6ToFixed(fFace->glyph->advance.y); | |
533 if (fRec.fFlags & kDevKernText_Flag) { | |
534 glyph->fRsbDelta = SkToS8(fFace->glyph->rsb_delta); | |
535 glyph->fLsbDelta = SkToS8(fFace->glyph->lsb_delta); | |
536 } | |
537 } else { | |
538 glyph->fAdvanceX = SkFixedMul(fMatrix22.xx, fFace->glyph->linearHoriAdva
nce); | |
539 glyph->fAdvanceY = -SkFixedMul(fMatrix22.yx, fFace->glyph->linearHoriAdv
ance); | |
540 } | |
541 | |
542 #ifdef ENABLE_GLYPH_SPEW | |
543 SkDEBUGF(("FT_Set_Char_Size(this:%p sx:%x sy:%x ", this, fScaleX, fScaleY)); | |
544 SkDEBUGF(("Metrics(glyph:%d flags:0x%x) w:%d\n", glyph->getGlyphID(fBaseGlyp
hCount), fLoadGlyphFlags, glyph->fWidth)); | |
545 #endif | |
546 } | |
547 | |
548 void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) { | |
549 SkAutoMutexAcquire ac(gFTMutex); | |
550 | |
551 FT_Error err; | |
552 | |
553 if (this->setupSize()) { | |
554 goto ERROR; | |
555 } | |
556 | |
557 err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFla
gs); | |
558 if (err != 0) { | |
559 SkDEBUGF(("SkScalerContext_FreeType::generateImage: FT_Load_Glyph(glyph:
%d width:%d height:%d rb:%d flags:%d) returned 0x%x\n", | |
560 glyph.getGlyphID(fBaseGlyphCount), glyph.fWidth, glyph.fHeig
ht, glyph.rowBytes(), fLoadGlyphFlags, err)); | |
561 ERROR: | |
562 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); | |
563 return; | |
564 } | |
565 | |
566 switch ( fFace->glyph->format ) { | |
567 case FT_GLYPH_FORMAT_OUTLINE: { | |
568 FT_Outline* outline = &fFace->glyph->outline; | |
569 FT_BBox bbox; | |
570 FT_Bitmap target; | |
571 | |
572 int dx = 0, dy = 0; | |
573 if (kSubpixel_Hints == fRec.fHints) { | |
574 dx = glyph.getSubXFixed() >> 10; | |
575 dy = glyph.getSubYFixed() >> 10; | |
576 // negate dy since freetype-y-goes-up and skia-y-goes-down | |
577 dy = -dy; | |
578 } | |
579 FT_Outline_Get_CBox(outline, &bbox); | |
580 /* | |
581 what we really want to do for subpixel is | |
582 offset(dx, dy) | |
583 compute_bounds | |
584 offset(bbox & !63) | |
585 but that is two calls to offset, so we do the following, which | |
586 achieves the same thing with only one offset call. | |
587 */ | |
588 FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63), | |
589 dy - ((bbox.yMin + dy) & ~63)); | |
590 | |
591 target.width = glyph.fWidth; | |
592 target.rows = glyph.fHeight; | |
593 target.pitch = glyph.rowBytes(); | |
594 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage); | |
595 target.pixel_mode = compute_pixel_mode( | |
596 (SkMask::Format)fRec.fMaskFormat); | |
597 target.num_grays = 256; | |
598 | |
599 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); | |
600 FT_Outline_Get_Bitmap(gFTLibrary, outline, &target); | |
601 } break; | |
602 | |
603 case FT_GLYPH_FORMAT_BITMAP: { | |
604 SkASSERT_CONTINUE(glyph.fWidth == fFace->glyph->bitmap.width); | |
605 SkASSERT_CONTINUE(glyph.fHeight == fFace->glyph->bitmap.rows); | |
606 SkASSERT_CONTINUE(glyph.fTop == -fFace->glyph->bitmap_top); | |
607 SkASSERT_CONTINUE(glyph.fLeft == fFace->glyph->bitmap_left); | |
608 | |
609 const uint8_t* src = (const uint8_t*)fFace->glyph->bitmap.buffer; | |
610 uint8_t* dst = (uint8_t*)glyph.fImage; | |
611 | |
612 if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { | |
613 unsigned srcRowBytes = fFace->glyph->bitmap.pitch; | |
614 unsigned dstRowBytes = glyph.rowBytes(); | |
615 unsigned minRowBytes = SkMin32(srcRowBytes, dstRowBytes); | |
616 unsigned extraRowBytes = dstRowBytes - minRowBytes; | |
617 | |
618 for (int y = fFace->glyph->bitmap.rows - 1; y >= 0; --y) { | |
619 memcpy(dst, src, minRowBytes); | |
620 memset(dst + minRowBytes, 0, extraRowBytes); | |
621 src += srcRowBytes; | |
622 dst += dstRowBytes; | |
623 } | |
624 } else if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { | |
625 for (int y = 0; y < fFace->glyph->bitmap.rows; ++y) { | |
626 uint8_t byte = 0; | |
627 int bits = 0; | |
628 const uint8_t* src_row = src; | |
629 uint8_t* dst_row = dst; | |
630 | |
631 for (int x = 0; x < fFace->glyph->bitmap.width; ++x) { | |
632 if (!bits) { | |
633 byte = *src_row++; | |
634 bits = 8; | |
635 } | |
636 | |
637 *dst_row++ = byte & 0x80 ? 0xff : 0; | |
638 bits--; | |
639 byte <<= 1; | |
640 } | |
641 | |
642 src += fFace->glyph->bitmap.pitch; | |
643 dst += glyph.rowBytes(); | |
644 } | |
645 } | |
646 } break; | |
647 | |
648 default: | |
649 SkASSERT(!"unknown glyph format"); | |
650 goto ERROR; | |
651 } | |
652 } | |
653 | |
654 /////////////////////////////////////////////////////////////////////////////// | |
655 | |
656 #define ft2sk(x) SkFixedToScalar((x) << 10) | |
657 | |
658 #if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 2 | |
659 #define CONST_PARAM const | |
660 #else // older freetype doesn't use const here | |
661 #define CONST_PARAM | |
662 #endif | |
663 | |
664 static int move_proc(CONST_PARAM FT_Vector* pt, void* ctx) { | |
665 SkPath* path = (SkPath*)ctx; | |
666 path->close(); // to close the previous contour (if any) | |
667 path->moveTo(ft2sk(pt->x), -ft2sk(pt->y)); | |
668 return 0; | |
669 } | |
670 | |
671 static int line_proc(CONST_PARAM FT_Vector* pt, void* ctx) { | |
672 SkPath* path = (SkPath*)ctx; | |
673 path->lineTo(ft2sk(pt->x), -ft2sk(pt->y)); | |
674 return 0; | |
675 } | |
676 | |
677 static int quad_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1, | |
678 void* ctx) { | |
679 SkPath* path = (SkPath*)ctx; | |
680 path->quadTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), -ft2sk(pt1->y)); | |
681 return 0; | |
682 } | |
683 | |
684 static int cubic_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1, | |
685 CONST_PARAM FT_Vector* pt2, void* ctx) { | |
686 SkPath* path = (SkPath*)ctx; | |
687 path->cubicTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), | |
688 -ft2sk(pt1->y), ft2sk(pt2->x), -ft2sk(pt2->y)); | |
689 return 0; | |
690 } | |
691 | |
692 void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, | |
693 SkPath* path) { | |
694 SkAutoMutexAcquire ac(gFTMutex); | |
695 | |
696 SkASSERT(&glyph && path); | |
697 | |
698 if (this->setupSize()) { | |
699 path->reset(); | |
700 return; | |
701 } | |
702 | |
703 uint32_t flags = fLoadGlyphFlags; | |
704 flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get
the outline | |
705 flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline) | |
706 | |
707 FT_Error err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), flag
s); | |
708 | |
709 if (err != 0) { | |
710 SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(glyph:%
d flags:%d) returned 0x%x\n", | |
711 glyph.getGlyphID(fBaseGlyphCount), flags, err)); | |
712 path->reset(); | |
713 return; | |
714 } | |
715 | |
716 FT_Outline_Funcs funcs; | |
717 | |
718 funcs.move_to = move_proc; | |
719 funcs.line_to = line_proc; | |
720 funcs.conic_to = quad_proc; | |
721 funcs.cubic_to = cubic_proc; | |
722 funcs.shift = 0; | |
723 funcs.delta = 0; | |
724 | |
725 err = FT_Outline_Decompose(&fFace->glyph->outline, &funcs, path); | |
726 | |
727 if (err != 0) { | |
728 SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(glyph:%
d flags:%d) returned 0x%x\n", | |
729 glyph.getGlyphID(fBaseGlyphCount), flags, err)); | |
730 path->reset(); | |
731 return; | |
732 } | |
733 | |
734 path->close(); | |
735 } | |
736 | |
737 void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, | |
738 SkPaint::FontMetrics* my) { | |
739 if (NULL == mx && NULL == my) { | |
740 return; | |
741 } | |
742 | |
743 SkAutoMutexAcquire ac(gFTMutex); | |
744 | |
745 if (this->setupSize()) { | |
746 if (mx) { | |
747 bzero(mx, sizeof(SkPaint::FontMetrics)); | |
748 } | |
749 if (my) { | |
750 bzero(my, sizeof(SkPaint::FontMetrics)); | |
751 } | |
752 return; | |
753 } | |
754 | |
755 SkPoint pts[6]; | |
756 SkFixed ys[6]; | |
757 FT_Face face = fFace; | |
758 int upem = face->units_per_EM; | |
759 SkFixed scaleY = fScaleY; | |
760 SkFixed mxy = fMatrix22.xy; | |
761 SkFixed myy = fMatrix22.yy; | |
762 SkScalar xmin = SkIntToScalar(face->bbox.xMin) / upem; | |
763 SkScalar xmax = SkIntToScalar(face->bbox.xMax) / upem; | |
764 | |
765 int leading = face->height - (face->ascender + -face->descender); | |
766 if (leading < 0) { | |
767 leading = 0; | |
768 } | |
769 | |
770 // Try to get the OS/2 table from the font. This contains the specific | |
771 // average font width metrics which Windows uses. | |
772 TT_OS2* os2 = (TT_OS2*) FT_Get_Sfnt_Table(face, ft_sfnt_os2); | |
773 | |
774 ys[0] = -face->bbox.yMax; | |
775 ys[1] = -face->ascender; | |
776 ys[2] = -face->descender; | |
777 ys[3] = -face->bbox.yMin; | |
778 ys[4] = leading; | |
779 ys[5] = os2 ? os2->xAvgCharWidth : 0; | |
780 | |
781 SkScalar x_height; | |
782 if (os2 && os2->sxHeight) { | |
783 x_height = SkFixedToScalar(SkMulDiv(fScaleX, os2->sxHeight, upem)); | |
784 } else { | |
785 const FT_UInt x_glyph = FT_Get_Char_Index(fFace, 'x'); | |
786 if (x_glyph) { | |
787 FT_BBox bbox; | |
788 FT_Load_Glyph(fFace, x_glyph, fLoadGlyphFlags); | |
789 FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox); | |
790 x_height = SkIntToScalar(bbox.yMax) / 64; | |
791 } else { | |
792 x_height = 0; | |
793 } | |
794 } | |
795 | |
796 // convert upem-y values into scalar points | |
797 for (int i = 0; i < 6; i++) { | |
798 SkFixed y = SkMulDiv(scaleY, ys[i], upem); | |
799 SkFixed x = SkFixedMul(mxy, y); | |
800 y = SkFixedMul(myy, y); | |
801 pts[i].set(SkFixedToScalar(x), SkFixedToScalar(y)); | |
802 } | |
803 | |
804 if (mx) { | |
805 mx->fTop = pts[0].fX; | |
806 mx->fAscent = pts[1].fX; | |
807 mx->fDescent = pts[2].fX; | |
808 mx->fBottom = pts[3].fX; | |
809 mx->fLeading = pts[4].fX; | |
810 mx->fAvgCharWidth = pts[5].fX; | |
811 mx->fXMin = xmin; | |
812 mx->fXMax = xmax; | |
813 mx->fXHeight = x_height; | |
814 } | |
815 if (my) { | |
816 my->fTop = pts[0].fY; | |
817 my->fAscent = pts[1].fY; | |
818 my->fDescent = pts[2].fY; | |
819 my->fBottom = pts[3].fY; | |
820 my->fLeading = pts[4].fY; | |
821 my->fAvgCharWidth = pts[5].fY; | |
822 my->fXMin = xmin; | |
823 my->fXMax = xmax; | |
824 my->fXHeight = x_height; | |
825 } | |
826 } | |
827 | |
828 //////////////////////////////////////////////////////////////////////// | |
829 //////////////////////////////////////////////////////////////////////// | |
830 | |
831 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { | |
832 SkScalerContext_FreeType* c = SkNEW_ARGS(SkScalerContext_FreeType, (desc)); | |
833 if (!c->success()) { | |
834 SkDELETE(c); | |
835 c = NULL; | |
836 } | |
837 return c; | |
838 } | |
839 | |
840 /////////////////////////////////////////////////////////////////////////////// | |
841 | |
842 /* Export this so that other parts of our FonttHost port can make use of our | |
843 ability to extract the name+style from a stream, using FreeType's api. | |
844 */ | |
845 SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name) { | |
846 FT_Library library; | |
847 if (FT_Init_FreeType(&library)) { | |
848 name->set(NULL); | |
849 return SkTypeface::kNormal; | |
850 } | |
851 | |
852 FT_Open_Args args; | |
853 memset(&args, 0, sizeof(args)); | |
854 | |
855 const void* memoryBase = stream->getMemoryBase(); | |
856 FT_StreamRec streamRec; | |
857 | |
858 if (NULL != memoryBase) { | |
859 args.flags = FT_OPEN_MEMORY; | |
860 args.memory_base = (const FT_Byte*)memoryBase; | |
861 args.memory_size = stream->getLength(); | |
862 } else { | |
863 memset(&streamRec, 0, sizeof(streamRec)); | |
864 streamRec.size = stream->read(NULL, 0); | |
865 streamRec.descriptor.pointer = stream; | |
866 streamRec.read = sk_stream_read; | |
867 streamRec.close = sk_stream_close; | |
868 | |
869 args.flags = FT_OPEN_STREAM; | |
870 args.stream = &streamRec; | |
871 } | |
872 | |
873 FT_Face face; | |
874 if (FT_Open_Face(library, &args, 0, &face)) { | |
875 FT_Done_FreeType(library); | |
876 name->set(NULL); | |
877 return SkTypeface::kNormal; | |
878 } | |
879 | |
880 name->set(face->family_name); | |
881 int style = SkTypeface::kNormal; | |
882 | |
883 if (face->style_flags & FT_STYLE_FLAG_BOLD) { | |
884 style |= SkTypeface::kBold; | |
885 } | |
886 if (face->style_flags & FT_STYLE_FLAG_ITALIC) { | |
887 style |= SkTypeface::kItalic; | |
888 } | |
889 | |
890 FT_Done_Face(face); | |
891 FT_Done_FreeType(library); | |
892 return (SkTypeface::Style)style; | |
893 } | |
894 | |
OLD | NEW |