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