1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include <Carbon/Carbon.h> 11 #include "SkFontHost.h" 12 #include "SkDescriptor.h" 13 #include "SkEndian.h" 14 #include "SkFloatingPoint.h" 15 #include "SkPaint.h" 16 #include "SkPoint.h" 17 18 const char* gDefaultfont = "Arial"; // hard code for now 19 SK_DECLARE_STATIC_MUTEX(gFTMutex); 20 21 static inline SkPoint F32PtToSkPoint(const Float32Point p) { 22 SkPoint sp = { SkFloatToScalar(p.x), SkFloatToScalar(p.y) }; 23 return sp; 24 } 25 26 static inline uint32_t _rotl(uint32_t v, uint32_t r) { 27 return (v << r | v >> (32 - r)); 28 } 29 30 class SkTypeface_Mac : public SkTypeface { 31 public: 32 SkTypeface_Mac(SkTypeface::Style style, uint32_t id) 33 : SkTypeface(style, id) {} 34 }; 35 36 #pragma mark - 37 38 static uint32_t find_from_name(const char name[]) { 39 CFStringRef str = CFStringCreateWithCString(NULL, name, 40 kCFStringEncodingUTF8); 41 uint32_t fontID = ::ATSFontFindFromName(str, kATSOptionFlagsDefault); 42 CFRelease(str); 43 return fontID; 44 } 45 46 static uint32_t find_default_fontID() { 47 static const char* gDefaultNames[] = { "Arial", "Tahoma", "Helvetica" }; 48 49 uint32_t fontID; 50 for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); i++) { 51 fontID = find_from_name(gDefaultNames[i]); 52 if (fontID) { 53 return fontID; 54 } 55 } 56 sk_throw(); 57 return 0; 58 } 59 60 static SkTypeface* CreateTypeface_(const char name[], SkTypeface::Style style) { 61 uint32_t fontID = 0; 62 if (NULL != name) { 63 fontID = find_from_name(name); 64 } 65 if (0 == fontID) { 66 fontID = find_default_fontID(); 67 } 68 // we lie (for now) and report that we found the exact style bits 69 return new SkTypeface_Mac(style, fontID); 70 } 71 72 #pragma mark - 73 74 class SkScalerContext_Mac : public SkScalerContext { 75 public: 76 SkScalerContext_Mac(const SkDescriptor* desc); 77 virtual ~SkScalerContext_Mac(); 78 79 protected: 80 virtual unsigned generateGlyphCount(); 81 virtual uint16_t generateCharToGlyph(SkUnichar uni); 82 virtual void generateAdvance(SkGlyph* glyph); 83 virtual void generateMetrics(SkGlyph* glyph); 84 virtual void generateImage(const SkGlyph& glyph); 85 virtual void generatePath(const SkGlyph& glyph, SkPath* path); 86 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY); 87 88 private: 89 ATSUTextLayout fLayout; 90 ATSUStyle fStyle; 91 CGColorSpaceRef fGrayColorSpace; 92 CGAffineTransform fTransform; 93 94 static OSStatus MoveTo(const Float32Point *pt, void *cb); 95 static OSStatus Line(const Float32Point *pt, void *cb); 96 static OSStatus Curve(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *cb); 97 static OSStatus Close(void *cb); 98 }; 99 100 void SkFontHost::FilterRec(SkScalerContext::Rec* rec, SkTypeface*) { 101 // we only support 2 levels of hinting 102 SkPaint::Hinting h = rec->getHinting(); 103 if (SkPaint::kSlight_Hinting == h) { 104 h = SkPaint::kNo_Hinting; 105 } else if (SkPaint::kFull_Hinting == h) { 106 h = SkPaint::kNormal_Hinting; 107 } 108 rec->setHinting(h); 109 110 // we don't support LCD text 111 if (SkMask::kLCD16_Format == rec->fMaskFormat || 112 SkMask::kLCD32_Format == rec->fMaskFormat) { 113 rec->fMaskFormat = SkMask::kA8_Format; 114 } 115 } 116 117 SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc) 118 : SkScalerContext(desc), fLayout(0), fStyle(0) 119 { 120 SkAutoMutexAcquire ac(gFTMutex); 121 OSStatus err; 122 123 err = ::ATSUCreateStyle(&fStyle); 124 SkASSERT(0 == err); 125 126 SkMatrix m; 127 fRec.getSingleMatrix(&m); 128 129 fTransform = CGAffineTransformMake(SkScalarToFloat(m[SkMatrix::kMScaleX]), 130 SkScalarToFloat(m[SkMatrix::kMSkewX]), 131 SkScalarToFloat(m[SkMatrix::kMSkewY]), 132 SkScalarToFloat(m[SkMatrix::kMScaleY]), 133 SkScalarToFloat(m[SkMatrix::kMTransX]), 134 SkScalarToFloat(m[SkMatrix::kMTransY])); 135 136 ATSStyleRenderingOptions renderOpts = kATSStyleApplyAntiAliasing; 137 switch (fRec.getHinting()) { 138 case SkPaint::kNo_Hinting: 139 case SkPaint::kSlight_Hinting: 140 renderOpts |= kATSStyleNoHinting; 141 break; 142 case SkPaint::kNormal_Hinting: 143 case SkPaint::kFull_Hinting: 144 renderOpts |= kATSStyleApplyHints; 145 break; 146 } 147 148 ATSUFontID fontID = FMGetFontFromATSFontRef(fRec.fFontID); 149 // we put everything in the matrix, so our pt size is just 1.0 150 Fixed fixedSize = SK_Fixed1; 151 static const ATSUAttributeTag tags[] = { 152 kATSUFontTag, kATSUSizeTag, kATSUFontMatrixTag, kATSUStyleRenderingOptionsTag 153 }; 154 static const ByteCount sizes[] = { 155 sizeof(fontID), sizeof(fixedSize), sizeof(fTransform), sizeof(renderOpts) 156 }; 157 const ATSUAttributeValuePtr values[] = { 158 &fontID, &fixedSize, &fTransform, &renderOpts 159 }; 160 err = ::ATSUSetAttributes(fStyle, SK_ARRAY_COUNT(tags), 161 tags, sizes, values); 162 SkASSERT(0 == err); 163 164 err = ::ATSUCreateTextLayout(&fLayout); 165 SkASSERT(0 == err); 166 167 fGrayColorSpace = ::CGColorSpaceCreateDeviceGray(); 168 } 169 170 SkScalerContext_Mac::~SkScalerContext_Mac() { 171 ::CGColorSpaceRelease(fGrayColorSpace); 172 ::ATSUDisposeTextLayout(fLayout); 173 ::ATSUDisposeStyle(fStyle); 174 } 175 176 // man, we need to consider caching this, since it is just dependent on 177 // fFontID, and not on any of the other settings like matrix or flags 178 unsigned SkScalerContext_Mac::generateGlyphCount() { 179 // The 'maxp' table stores the number of glyphs a offset 4, in 2 bytes 180 uint16_t numGlyphs; 181 if (SkFontHost::GetTableData(fRec.fFontID, 182 SkSetFourByteTag('m', 'a', 'x', 'p'), 183 4, 2, &numGlyphs) != 2) { 184 return 0xFFFF; 185 } 186 return SkEndian_SwapBE16(numGlyphs); 187 } 188 189 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) 190 { 191 SkAutoMutexAcquire ac(gFTMutex); 192 193 OSStatus err; 194 UniChar achar = uni; 195 err = ::ATSUSetTextPointerLocation(fLayout,&achar,0,1,1); 196 err = ::ATSUSetRunStyle(fLayout,fStyle,kATSUFromTextBeginning,kATSUToTextEnd); 197 198 ATSLayoutRecord *layoutPtr; 199 ItemCount count; 200 ATSGlyphRef glyph; 201 202 err = ::ATSUDirectGetLayoutDataArrayPtrFromTextLayout(fLayout,0,kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr,&count); 203 glyph = layoutPtr->glyphID; 204 ::ATSUDirectReleaseLayoutDataArrayPtr(NULL,kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr); 205 return glyph; 206 } 207 208 static void set_glyph_metrics_on_error(SkGlyph* glyph) { 209 glyph->fRsbDelta = 0; 210 glyph->fLsbDelta = 0; 211 glyph->fWidth = 0; 212 glyph->fHeight = 0; 213 glyph->fTop = 0; 214 glyph->fLeft = 0; 215 glyph->fAdvanceX = 0; 216 glyph->fAdvanceY = 0; 217 } 218 219 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { 220 this->generateMetrics(glyph); 221 } 222 223 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { 224 GlyphID glyphID = glyph->getGlyphID(fBaseGlyphCount); 225 ATSGlyphScreenMetrics screenMetrics; 226 ATSGlyphIdealMetrics idealMetrics; 227 228 OSStatus err = ATSUGlyphGetScreenMetrics(fStyle, 1, &glyphID, 0, true, true, 229 &screenMetrics); 230 if (noErr != err) { 231 set_glyph_metrics_on_error(glyph); 232 return; 233 } 234 err = ATSUGlyphGetIdealMetrics(fStyle, 1, &glyphID, 0, &idealMetrics); 235 if (noErr != err) { 236 set_glyph_metrics_on_error(glyph); 237 return; 238 } 239 240 if ((fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) == 0) { 241 glyph->fAdvanceX = SkFloatToFixed(screenMetrics.deviceAdvance.x); 242 glyph->fAdvanceY = -SkFloatToFixed(screenMetrics.deviceAdvance.y); 243 } else { 244 glyph->fAdvanceX = SkFloatToFixed(idealMetrics.advance.x); 245 glyph->fAdvanceY = -SkFloatToFixed(idealMetrics.advance.y); 246 } 247 248 // specify an extra 1-pixel border, go tive CG room for its antialiasing 249 // i.e. without this, I was seeing some edges chopped off! 250 glyph->fWidth = screenMetrics.width + 2; 251 glyph->fHeight = screenMetrics.height + 2; 252 glyph->fLeft = sk_float_round2int(screenMetrics.topLeft.x) - 1; 253 glyph->fTop = -sk_float_round2int(screenMetrics.topLeft.y) - 1; 254 } 255 256 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) 257 { 258 SkAutoMutexAcquire ac(gFTMutex); 259 SkASSERT(fLayout); 260 261 sk_bzero(glyph.fImage, glyph.fHeight * glyph.rowBytes()); 262 CGContextRef contextRef = ::CGBitmapContextCreate(glyph.fImage, 263 glyph.fWidth, glyph.fHeight, 8, 264 glyph.rowBytes(), fGrayColorSpace, 265 kCGImageAlphaNone); 266 if (!contextRef) { 267 SkASSERT(false); 268 return; 269 } 270 271 ::CGContextSetGrayFillColor(contextRef, 1.0, 1.0); 272 ::CGContextSetTextDrawingMode(contextRef, kCGTextFill); 273 274 CGGlyph glyphID = glyph.getGlyphID(fBaseGlyphCount); 275 CGFontRef fontRef = CGFontCreateWithPlatformFont(&fRec.fFontID); 276 CGContextSetFont(contextRef, fontRef); 277 CGContextSetFontSize(contextRef, 1); 278 CGContextSetTextMatrix(contextRef, fTransform); 279 CGContextShowGlyphsAtPoint(contextRef, -glyph.fLeft, 280 glyph.fTop + glyph.fHeight, &glyphID, 1); 281 282 ::CGContextRelease(contextRef); 283 } 284 285 #if 0 286 static void convert_metrics(SkPaint::FontMetrics* dst, 287 const ATSFontMetrics& src) { 288 dst->fTop = -SkFloatToScalar(src.ascent); 289 dst->fAscent = -SkFloatToScalar(src.ascent); 290 dst->fDescent = SkFloatToScalar(src.descent); 291 dst->fBottom = SkFloatToScalar(src.descent); 292 dst->fLeading = SkFloatToScalar(src.leading); 293 } 294 #endif 295 296 static void* get_font_table(ATSFontRef fontID, uint32_t tag) { 297 ByteCount size; 298 OSStatus err = ATSFontGetTable(fontID, tag, 0, 0, NULL, &size); 299 if (err) { 300 return NULL; 301 } 302 void* data = sk_malloc_throw(size); 303 err = ATSFontGetTable(fontID, tag, 0, size, data, &size); 304 if (err) { 305 sk_free(data); 306 data = NULL; 307 } 308 return data; 309 } 310 311 static int get_be16(const void* data, size_t offset) { 312 const char* ptr = reinterpret_cast<const char*>(data); 313 uint16_t value = *reinterpret_cast<const uint16_t*>(ptr + offset); 314 int n = SkEndian_SwapBE16(value); 315 // now force it to be signed 316 return n << 16 >> 16; 317 } 318 319 #define SFNT_HEAD_UPEM_OFFSET 18 320 #define SFNT_HEAD_YMIN_OFFSET 38 321 #define SFNT_HEAD_YMAX_OFFSET 42 322 #define SFNT_HEAD_STYLE_OFFSET 44 323 324 #define SFNT_HHEA_ASCENT_OFFSET 4 325 #define SFNT_HHEA_DESCENT_OFFSET 6 326 #define SFNT_HHEA_LEADING_OFFSET 8 327 328 static bool init_vertical_metrics(ATSFontRef font, SkPoint pts[5]) { 329 void* head = get_font_table(font, 'head'); 330 if (NULL == head) { 331 return false; 332 } 333 void* hhea = get_font_table(font, 'hhea'); 334 if (NULL == hhea) { 335 sk_free(head); 336 return false; 337 } 338 339 int upem = get_be16(head, SFNT_HEAD_UPEM_OFFSET); 340 int ys[5]; 341 342 ys[0] = -get_be16(head, SFNT_HEAD_YMAX_OFFSET); 343 ys[1] = -get_be16(hhea, SFNT_HHEA_ASCENT_OFFSET); 344 ys[2] = -get_be16(hhea, SFNT_HHEA_DESCENT_OFFSET); 345 ys[3] = -get_be16(head, SFNT_HEAD_YMIN_OFFSET); 346 ys[4] = get_be16(hhea, SFNT_HHEA_LEADING_OFFSET); 347 348 // now do some cleanup, to ensure y[max,min] are really that 349 if (ys[0] > ys[1]) { 350 ys[0] = ys[1]; 351 } 352 if (ys[3] < ys[2]) { 353 ys[3] = ys[2]; 354 } 355 356 for (int i = 0; i < 5; i++) { 357 pts[i].set(0, SkIntToScalar(ys[i]) / upem); 358 } 359 360 sk_free(hhea); 361 sk_free(head); 362 return true; 363 } 364 365 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, 366 SkPaint::FontMetrics* my) { 367 SkPoint pts[5]; 368 369 if (!init_vertical_metrics(fRec.fFontID, pts)) { 370 // these are not as accurate as init_vertical_metrics :( 371 ATSFontMetrics metrics; 372 ATSFontGetVerticalMetrics(fRec.fFontID, kATSOptionFlagsDefault, 373 &metrics); 374 pts[0].set(0, -SkFloatToScalar(metrics.ascent)); 375 pts[1].set(0, -SkFloatToScalar(metrics.ascent)); 376 pts[2].set(0, -SkFloatToScalar(metrics.descent)); 377 pts[3].set(0, -SkFloatToScalar(metrics.descent)); 378 pts[4].set(0, SkFloatToScalar(metrics.leading)); //+ or -? 379 } 380 381 SkMatrix m; 382 fRec.getSingleMatrix(&m); 383 m.mapPoints(pts, 5); 384 385 if (mx) { 386 mx->fTop = pts[0].fX; 387 mx->fAscent = pts[1].fX; 388 mx->fDescent = pts[2].fX; 389 mx->fBottom = pts[3].fX; 390 mx->fLeading = pts[4].fX; 391 // FIXME: 392 mx->fAvgCharWidth = 0; 393 mx->fXMin = 0; 394 mx->fXMax = 0; 395 mx->fXHeight = 0; 396 } 397 if (my) { 398 my->fTop = pts[0].fY; 399 my->fAscent = pts[1].fY; 400 my->fDescent = pts[2].fY; 401 my->fBottom = pts[3].fY; 402 my->fLeading = pts[4].fY; 403 // FIXME: 404 my->fAvgCharWidth = 0; 405 my->fXMin = 0; 406 my->fXMax = 0; 407 my->fXHeight = 0; 408 } 409 } 410 411 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) 412 { 413 SkAutoMutexAcquire ac(gFTMutex); 414 OSStatus err,result; 415 416 err = ::ATSUGlyphGetCubicPaths( 417 fStyle,glyph.fID, 418 &SkScalerContext_Mac::MoveTo, 419 &SkScalerContext_Mac::Line, 420 &SkScalerContext_Mac::Curve, 421 &SkScalerContext_Mac::Close, 422 path,&result); 423 SkASSERT(err == noErr); 424 } 425 426 OSStatus SkScalerContext_Mac::MoveTo(const Float32Point *pt, void *cb) 427 { 428 reinterpret_cast<SkPath*>(cb)->moveTo(F32PtToSkPoint(*pt)); 429 return noErr; 430 } 431 432 OSStatus SkScalerContext_Mac::Line(const Float32Point *pt, void *cb) 433 { 434 reinterpret_cast<SkPath*>(cb)->lineTo(F32PtToSkPoint(*pt)); 435 return noErr; 436 } 437 438 OSStatus SkScalerContext_Mac::Curve(const Float32Point *pt1, 439 const Float32Point *pt2, 440 const Float32Point *pt3, void *cb) 441 { 442 reinterpret_cast<SkPath*>(cb)->cubicTo(F32PtToSkPoint(*pt1), 443 F32PtToSkPoint(*pt2), 444 F32PtToSkPoint(*pt3)); 445 return noErr; 446 } 447 448 OSStatus SkScalerContext_Mac::Close(void *cb) 449 { 450 reinterpret_cast<SkPath*>(cb)->close(); 451 return noErr; 452 } 453 454 #pragma mark - 455 456 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { 457 SkDEBUGFAIL("SkFontHost::Serialize unimplemented"); 458 } 459 460 SkTypeface* SkFontHost::Deserialize(SkStream* stream) { 461 SkDEBUGFAIL("SkFontHost::Deserialize unimplemented"); 462 return NULL; 463 } 464 465 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { 466 return NULL; 467 } 468 469 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { 470 return NULL; 471 } 472 473 // static 474 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( 475 uint32_t fontID, 476 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, 477 const uint32_t* glyphIDs, 478 uint32_t glyphIDsCount) { 479 SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented"); 480 return NULL; 481 } 482 483 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { 484 return new SkScalerContext_Mac(desc); 485 } 486 487 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { 488 uint32_t newFontID = find_default_fontID(); 489 if (newFontID == currFontID) { 490 newFontID = 0; 491 } 492 return newFontID; 493 } 494 495 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 496 const char familyName[], 497 SkTypeface::Style style) { 498 // todo: we don't know how to respect style bits 499 if (NULL == familyName && NULL != familyFace) { 500 familyFace->ref(); 501 return const_cast<SkTypeface*>(familyFace); 502 } else { 503 return CreateTypeface_(familyName, style); 504 } 505 } 506 507 /////////////////////////////////////////////////////////////////////////////// 508 509 struct SkSFNTHeader { 510 uint32_t fVersion; 511 uint16_t fNumTables; 512 uint16_t fSearchRange; 513 uint16_t fEntrySelector; 514 uint16_t fRangeShift; 515 }; 516 517 struct SkSFNTDirEntry { 518 uint32_t fTag; 519 uint32_t fChecksum; 520 uint32_t fOffset; 521 uint32_t fLength; 522 }; 523 524 struct SfntHeader { 525 SfntHeader(SkFontID fontID, bool needDir) : fCount(0), fData(NULL) { 526 ByteCount size; 527 if (ATSFontGetTableDirectory(fontID, 0, NULL, &size)) { 528 return; 529 } 530 531 SkAutoMalloc storage(size); 532 SkSFNTHeader* header = reinterpret_cast<SkSFNTHeader*>(storage.get()); 533 if (ATSFontGetTableDirectory(fontID, size, header, &size)) { 534 return; 535 } 536 537 fCount = SkEndian_SwapBE16(header->fNumTables); 538 fData = header; 539 storage.detach(); 540 } 541 542 ~SfntHeader() { 543 sk_free(fData); 544 } 545 546 int count() const { return fCount; } 547 const SkSFNTDirEntry* entries() const { 548 return reinterpret_cast<const SkSFNTDirEntry*> 549 (reinterpret_cast<char*>(fData) + sizeof(SkSFNTHeader)); 550 } 551 552 private: 553 int fCount; 554 void* fData; 555 }; 556 557 int SkFontHost::CountTables(SkFontID fontID) { 558 SfntHeader header(fontID, false); 559 return header.count(); 560 } 561 562 int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) { 563 SfntHeader header(fontID, true); 564 int count = header.count(); 565 const SkSFNTDirEntry* entry = header.entries(); 566 for (int i = 0; i < count; i++) { 567 tags[i] = SkEndian_SwapBE32(entry[i].fTag); 568 } 569 return count; 570 } 571 572 size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) { 573 ByteCount size; 574 if (ATSFontGetTable(fontID, tag, 0, 0, NULL, &size)) { 575 return 0; 576 } 577 return size; 578 } 579 580 size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag, 581 size_t offset, size_t length, void* data) { 582 ByteCount size; 583 if (ATSFontGetTable(fontID, tag, offset, length, data, &size)) { 584 return 0; 585 } 586 if (offset >= size) { 587 return 0; 588 } 589 if (offset + length > size) { 590 length = size - offset; 591 } 592 return length; 593 } 594