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