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

Side by Side Diff: skia/ports/SkFontHost_FreeType.cpp

Issue 113827: Remove the remainder of the skia source code from the Chromium repo.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « skia/ports/SkFontHost_FONTPATH.cpp ('k') | skia/ports/SkFontHost_android.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « skia/ports/SkFontHost_FONTPATH.cpp ('k') | skia/ports/SkFontHost_android.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698