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