The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

781 lines
29KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #if (JUCE_MAC && defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 \
  19. && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5) \
  20. || (JUCE_IOS && defined (__IPHONE_3_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2)
  21. #define JUCE_CORETEXT_AVAILABLE 1
  22. #endif
  23. #if JUCE_CORETEXT_AVAILABLE
  24. //==============================================================================
  25. class OSXTypeface : public Typeface
  26. {
  27. public:
  28. OSXTypeface (const Font& font)
  29. : Typeface (font.getTypefaceName()),
  30. fontRef (nullptr),
  31. fontHeightToCGSizeFactor (1.0f),
  32. renderingTransform (CGAffineTransformIdentity),
  33. ctFontRef (nullptr),
  34. attributedStringAtts (nullptr),
  35. ascent (0.0f),
  36. unitsToHeightScaleFactor (0.0f)
  37. {
  38. CFStringRef cfName = font.getTypefaceName().toCFString();
  39. ctFontRef = CTFontCreateWithName (cfName, 1024, nullptr);
  40. CFRelease (cfName);
  41. if (ctFontRef != nullptr)
  42. {
  43. bool needsItalicTransform = false;
  44. if (font.isItalic())
  45. {
  46. CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits (ctFontRef, 0.0f, nullptr,
  47. kCTFontItalicTrait, kCTFontItalicTrait);
  48. if (newFont != nullptr)
  49. {
  50. CFRelease (ctFontRef);
  51. ctFontRef = newFont;
  52. }
  53. else
  54. {
  55. needsItalicTransform = true; // couldn't find a proper italic version, so fake it with a transform..
  56. }
  57. }
  58. if (font.isBold())
  59. {
  60. CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits (ctFontRef, 0.0f, nullptr,
  61. kCTFontBoldTrait, kCTFontBoldTrait);
  62. if (newFont != nullptr)
  63. {
  64. CFRelease (ctFontRef);
  65. ctFontRef = newFont;
  66. }
  67. }
  68. ascent = std::abs ((float) CTFontGetAscent (ctFontRef));
  69. const float totalSize = ascent + std::abs ((float) CTFontGetDescent (ctFontRef));
  70. ascent /= totalSize;
  71. pathTransform = AffineTransform::identity.scale (1.0f / totalSize, 1.0f / totalSize);
  72. if (needsItalicTransform)
  73. {
  74. pathTransform = pathTransform.sheared (-0.15f, 0.0f);
  75. renderingTransform.c = 0.15f;
  76. }
  77. fontRef = CTFontCopyGraphicsFont (ctFontRef, nullptr);
  78. const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
  79. const float ctTotalHeight = abs (CTFontGetAscent (ctFontRef)) + abs (CTFontGetDescent (ctFontRef));
  80. unitsToHeightScaleFactor = 1.0f / ctTotalHeight;
  81. fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
  82. const short zero = 0;
  83. CFNumberRef numberRef = CFNumberCreate (0, kCFNumberShortType, &zero);
  84. CFStringRef keys[] = { kCTFontAttributeName, kCTLigatureAttributeName };
  85. CFTypeRef values[] = { ctFontRef, numberRef };
  86. attributedStringAtts = CFDictionaryCreate (nullptr, (const void**) &keys, (const void**) &values, numElementsInArray (keys),
  87. &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  88. CFRelease (numberRef);
  89. }
  90. }
  91. ~OSXTypeface()
  92. {
  93. if (attributedStringAtts != nullptr)
  94. CFRelease (attributedStringAtts);
  95. if (fontRef != nullptr)
  96. CGFontRelease (fontRef);
  97. if (ctFontRef != nullptr)
  98. CFRelease (ctFontRef);
  99. }
  100. float getAscent() const { return ascent; }
  101. float getDescent() const { return 1.0f - ascent; }
  102. float getStringWidth (const String& text)
  103. {
  104. float x = 0;
  105. if (ctFontRef != nullptr && text.isNotEmpty())
  106. {
  107. CFStringRef cfText = text.toCFString();
  108. CFAttributedStringRef attribString = CFAttributedStringCreate (kCFAllocatorDefault, cfText, attributedStringAtts);
  109. CFRelease (cfText);
  110. CTLineRef line = CTLineCreateWithAttributedString (attribString);
  111. CFArrayRef runArray = CTLineGetGlyphRuns (line);
  112. for (CFIndex i = 0; i < CFArrayGetCount (runArray); ++i)
  113. {
  114. CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (runArray, i);
  115. CFIndex length = CTRunGetGlyphCount (run);
  116. HeapBlock <CGSize> advances (length);
  117. CTRunGetAdvances (run, CFRangeMake (0, 0), advances);
  118. for (int j = 0; j < length; ++j)
  119. x += (float) advances[j].width;
  120. }
  121. CFRelease (line);
  122. CFRelease (attribString);
  123. x *= unitsToHeightScaleFactor;
  124. }
  125. return x;
  126. }
  127. void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
  128. {
  129. xOffsets.add (0);
  130. if (ctFontRef != nullptr && text.isNotEmpty())
  131. {
  132. float x = 0;
  133. CFStringRef cfText = text.toCFString();
  134. CFAttributedStringRef attribString = CFAttributedStringCreate (kCFAllocatorDefault, cfText, attributedStringAtts);
  135. CFRelease (cfText);
  136. CTLineRef line = CTLineCreateWithAttributedString (attribString);
  137. CFArrayRef runArray = CTLineGetGlyphRuns (line);
  138. for (CFIndex i = 0; i < CFArrayGetCount (runArray); ++i)
  139. {
  140. CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (runArray, i);
  141. CFIndex length = CTRunGetGlyphCount (run);
  142. HeapBlock <CGSize> advances (length);
  143. CTRunGetAdvances (run, CFRangeMake (0, 0), advances);
  144. HeapBlock <CGGlyph> glyphs (length);
  145. CTRunGetGlyphs (run, CFRangeMake (0, 0), glyphs);
  146. for (int j = 0; j < length; ++j)
  147. {
  148. x += (float) advances[j].width;
  149. xOffsets.add (x * unitsToHeightScaleFactor);
  150. resultGlyphs.add (glyphs[j]);
  151. }
  152. }
  153. CFRelease (line);
  154. CFRelease (attribString);
  155. }
  156. }
  157. EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform)
  158. {
  159. Path path;
  160. if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty())
  161. return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0),
  162. path, transform);
  163. return nullptr;
  164. }
  165. bool getOutlineForGlyph (int glyphNumber, Path& path)
  166. {
  167. jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty
  168. CGPathRef pathRef = CTFontCreatePathForGlyph (ctFontRef, (CGGlyph) glyphNumber, &renderingTransform);
  169. if (pathRef == 0)
  170. return false;
  171. CGPathApply (pathRef, &path, pathApplier);
  172. CFRelease (pathRef);
  173. if (! pathTransform.isIdentity())
  174. path.applyTransform (pathTransform);
  175. return true;
  176. }
  177. //==============================================================================
  178. CGFontRef fontRef;
  179. float fontHeightToCGSizeFactor;
  180. CGAffineTransform renderingTransform;
  181. private:
  182. CTFontRef ctFontRef;
  183. CFDictionaryRef attributedStringAtts;
  184. float ascent, unitsToHeightScaleFactor;
  185. AffineTransform pathTransform;
  186. static void pathApplier (void* info, const CGPathElement* const element)
  187. {
  188. Path& path = *static_cast<Path*> (info);
  189. const CGPoint* const p = element->points;
  190. switch (element->type)
  191. {
  192. case kCGPathElementMoveToPoint: path.startNewSubPath ((float) p[0].x, (float) -p[0].y); break;
  193. case kCGPathElementAddLineToPoint: path.lineTo ((float) p[0].x, (float) -p[0].y); break;
  194. case kCGPathElementAddQuadCurveToPoint: path.quadraticTo ((float) p[0].x, (float) -p[0].y,
  195. (float) p[1].x, (float) -p[1].y); break;
  196. case kCGPathElementAddCurveToPoint: path.cubicTo ((float) p[0].x, (float) -p[0].y,
  197. (float) p[1].x, (float) -p[1].y,
  198. (float) p[2].x, (float) -p[2].y); break;
  199. case kCGPathElementCloseSubpath: path.closeSubPath(); break;
  200. default: jassertfalse; break;
  201. }
  202. }
  203. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface);
  204. };
  205. #else
  206. //==============================================================================
  207. // The stuff that follows is a mash-up that supports pre-OSX 10.5 and pre-iOS 3.2 APIs.
  208. // (Hopefully all of this can be ditched at some point in the future).
  209. //==============================================================================
  210. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  211. #define SUPPORT_10_4_FONTS 1
  212. #define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)
  213. #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
  214. #define SUPPORT_ONLY_10_4_FONTS 1
  215. #endif
  216. END_JUCE_NAMESPACE
  217. @interface NSFont (PrivateHack)
  218. - (NSGlyph) _defaultGlyphForChar: (unichar) theChar;
  219. @end
  220. BEGIN_JUCE_NAMESPACE
  221. #endif
  222. //==============================================================================
  223. class OSXTypeface : public Typeface
  224. {
  225. public:
  226. OSXTypeface (const Font& font)
  227. : Typeface (font.getTypefaceName())
  228. {
  229. JUCE_AUTORELEASEPOOL
  230. renderingTransform = CGAffineTransformIdentity;
  231. bool needsItalicTransform = false;
  232. #if JUCE_IOS
  233. NSString* fontName = juceStringToNS (font.getTypefaceName());
  234. if (font.isItalic() || font.isBold())
  235. {
  236. NSArray* familyFonts = [UIFont fontNamesForFamilyName: juceStringToNS (font.getTypefaceName())];
  237. for (NSString* i in familyFonts)
  238. {
  239. const String fn (nsStringToJuce (i));
  240. const String afterDash (fn.fromFirstOccurrenceOf ("-", false, false));
  241. const bool probablyBold = afterDash.containsIgnoreCase ("bold") || fn.endsWithIgnoreCase ("bold");
  242. const bool probablyItalic = afterDash.containsIgnoreCase ("oblique")
  243. || afterDash.containsIgnoreCase ("italic")
  244. || fn.endsWithIgnoreCase ("oblique")
  245. || fn.endsWithIgnoreCase ("italic");
  246. if (probablyBold == font.isBold()
  247. && probablyItalic == font.isItalic())
  248. {
  249. fontName = i;
  250. needsItalicTransform = false;
  251. break;
  252. }
  253. else if (probablyBold && (! probablyItalic) && probablyBold == font.isBold())
  254. {
  255. fontName = i;
  256. needsItalicTransform = true; // not ideal, so carry on in case we find a better one
  257. }
  258. }
  259. if (needsItalicTransform)
  260. renderingTransform.c = 0.15f;
  261. }
  262. fontRef = CGFontCreateWithFontName ((CFStringRef) fontName);
  263. if (fontRef == 0)
  264. {
  265. // Sometimes, UIFont manages to handle names that CGFontCreateWithFontName fails on...
  266. UIFont* uiFont = [UIFont fontWithName: fontName size: 12];
  267. fontRef = CGFontCreateWithFontName ((CFStringRef) uiFont.fontName);
  268. }
  269. const int ascender = abs (CGFontGetAscent (fontRef));
  270. const float totalHeight = ascender + abs (CGFontGetDescent (fontRef));
  271. ascent = ascender / totalHeight;
  272. unitsToHeightScaleFactor = 1.0f / totalHeight;
  273. fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / totalHeight;
  274. #else
  275. nsFont = [NSFont fontWithName: juceStringToNS (font.getTypefaceName()) size: 1024];
  276. if (font.isItalic())
  277. {
  278. NSFont* newFont = [[NSFontManager sharedFontManager] convertFont: nsFont
  279. toHaveTrait: NSItalicFontMask];
  280. if (newFont == nsFont)
  281. needsItalicTransform = true; // couldn't find a proper italic version, so fake it with a transform..
  282. nsFont = newFont;
  283. }
  284. if (font.isBold())
  285. nsFont = [[NSFontManager sharedFontManager] convertFont: nsFont toHaveTrait: NSBoldFontMask];
  286. [nsFont retain];
  287. ascent = std::abs ((float) [nsFont ascender]);
  288. float totalSize = ascent + std::abs ((float) [nsFont descender]);
  289. ascent /= totalSize;
  290. pathTransform = AffineTransform::identity.scale (1.0f / totalSize, 1.0f / totalSize);
  291. if (needsItalicTransform)
  292. {
  293. pathTransform = pathTransform.sheared (-0.15f, 0.0f);
  294. renderingTransform.c = 0.15f;
  295. }
  296. #if SUPPORT_ONLY_10_4_FONTS
  297. ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
  298. if (atsFont == 0)
  299. atsFont = ATSFontFindFromPostScriptName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
  300. fontRef = CGFontCreateWithPlatformFont (&atsFont);
  301. const float totalHeight = std::abs ([nsFont ascender]) + std::abs ([nsFont descender]);
  302. unitsToHeightScaleFactor = 1.0f / totalHeight;
  303. fontHeightToCGSizeFactor = 1024.0f / totalHeight;
  304. #else
  305. #if SUPPORT_10_4_FONTS
  306. if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
  307. {
  308. ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
  309. if (atsFont == 0)
  310. atsFont = ATSFontFindFromPostScriptName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
  311. fontRef = CGFontCreateWithPlatformFont (&atsFont);
  312. const float totalHeight = std::abs ([nsFont ascender]) + std::abs ([nsFont descender]);
  313. unitsToHeightScaleFactor = 1.0f / totalHeight;
  314. fontHeightToCGSizeFactor = 1024.0f / totalHeight;
  315. }
  316. else
  317. #endif
  318. {
  319. fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
  320. const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
  321. unitsToHeightScaleFactor = 1.0f / totalHeight;
  322. fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
  323. }
  324. #endif
  325. #endif
  326. }
  327. ~OSXTypeface()
  328. {
  329. #if ! JUCE_IOS
  330. [nsFont release];
  331. #endif
  332. if (fontRef != 0)
  333. CGFontRelease (fontRef);
  334. }
  335. float getAscent() const { return ascent; }
  336. float getDescent() const { return 1.0f - ascent; }
  337. float getStringWidth (const String& text)
  338. {
  339. if (fontRef == 0 || text.isEmpty())
  340. return 0;
  341. const int length = text.length();
  342. HeapBlock <CGGlyph> glyphs;
  343. createGlyphsForString (text.getCharPointer(), length, glyphs);
  344. float x = 0;
  345. #if SUPPORT_ONLY_10_4_FONTS
  346. HeapBlock <NSSize> advances (length);
  347. [nsFont getAdvancements: advances forGlyphs: reinterpret_cast <NSGlyph*> (glyphs.getData()) count: length];
  348. for (int i = 0; i < length; ++i)
  349. x += advances[i].width;
  350. #else
  351. #if SUPPORT_10_4_FONTS
  352. if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
  353. {
  354. HeapBlock <NSSize> advances (length);
  355. [nsFont getAdvancements: advances forGlyphs: reinterpret_cast<NSGlyph*> (glyphs.getData()) count: length];
  356. for (int i = 0; i < length; ++i)
  357. x += advances[i].width;
  358. }
  359. else
  360. #endif
  361. {
  362. HeapBlock <int> advances (length);
  363. if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
  364. for (int i = 0; i < length; ++i)
  365. x += advances[i];
  366. }
  367. #endif
  368. return x * unitsToHeightScaleFactor;
  369. }
  370. void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
  371. {
  372. xOffsets.add (0);
  373. if (fontRef == 0 || text.isEmpty())
  374. return;
  375. const int length = text.length();
  376. HeapBlock <CGGlyph> glyphs;
  377. createGlyphsForString (text.getCharPointer(), length, glyphs);
  378. #if SUPPORT_ONLY_10_4_FONTS
  379. HeapBlock <NSSize> advances (length);
  380. [nsFont getAdvancements: advances forGlyphs: reinterpret_cast <NSGlyph*> (glyphs.getData()) count: length];
  381. int x = 0;
  382. for (int i = 0; i < length; ++i)
  383. {
  384. x += advances[i].width;
  385. xOffsets.add (x * unitsToHeightScaleFactor);
  386. resultGlyphs.add (reinterpret_cast <NSGlyph*> (glyphs.getData())[i]);
  387. }
  388. #else
  389. #if SUPPORT_10_4_FONTS
  390. if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
  391. {
  392. HeapBlock <NSSize> advances (length);
  393. NSGlyph* const nsGlyphs = reinterpret_cast<NSGlyph*> (glyphs.getData());
  394. [nsFont getAdvancements: advances forGlyphs: nsGlyphs count: length];
  395. float x = 0;
  396. for (int i = 0; i < length; ++i)
  397. {
  398. x += advances[i].width;
  399. xOffsets.add (x * unitsToHeightScaleFactor);
  400. resultGlyphs.add (nsGlyphs[i]);
  401. }
  402. }
  403. else
  404. #endif
  405. {
  406. HeapBlock <int> advances (length);
  407. if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
  408. {
  409. int x = 0;
  410. for (int i = 0; i < length; ++i)
  411. {
  412. x += advances [i];
  413. xOffsets.add (x * unitsToHeightScaleFactor);
  414. resultGlyphs.add (glyphs[i]);
  415. }
  416. }
  417. }
  418. #endif
  419. }
  420. EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform)
  421. {
  422. Path path;
  423. if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty())
  424. return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0),
  425. path, transform);
  426. return nullptr;
  427. }
  428. bool getOutlineForGlyph (int glyphNumber, Path& path)
  429. {
  430. #if JUCE_IOS
  431. return false;
  432. #else
  433. if (nsFont == nil)
  434. return false;
  435. // we might need to apply a transform to the path, so it mustn't have anything else in it
  436. jassert (path.isEmpty());
  437. JUCE_AUTORELEASEPOOL
  438. NSBezierPath* bez = [NSBezierPath bezierPath];
  439. [bez moveToPoint: NSMakePoint (0, 0)];
  440. [bez appendBezierPathWithGlyph: (NSGlyph) glyphNumber
  441. inFont: nsFont];
  442. for (int i = 0; i < [bez elementCount]; ++i)
  443. {
  444. NSPoint p[3];
  445. switch ([bez elementAtIndex: i associatedPoints: p])
  446. {
  447. case NSMoveToBezierPathElement: path.startNewSubPath ((float) p[0].x, (float) -p[0].y); break;
  448. case NSLineToBezierPathElement: path.lineTo ((float) p[0].x, (float) -p[0].y); break;
  449. case NSCurveToBezierPathElement: path.cubicTo ((float) p[0].x, (float) -p[0].y,
  450. (float) p[1].x, (float) -p[1].y,
  451. (float) p[2].x, (float) -p[2].y); break;
  452. case NSClosePathBezierPathElement: path.closeSubPath(); break;
  453. default: jassertfalse; break;
  454. }
  455. }
  456. path.applyTransform (pathTransform);
  457. return true;
  458. #endif
  459. }
  460. //==============================================================================
  461. CGFontRef fontRef;
  462. float fontHeightToCGSizeFactor;
  463. CGAffineTransform renderingTransform;
  464. private:
  465. float ascent, unitsToHeightScaleFactor;
  466. #if ! JUCE_IOS
  467. NSFont* nsFont;
  468. AffineTransform pathTransform;
  469. #endif
  470. void createGlyphsForString (String::CharPointerType text, const int length, HeapBlock <CGGlyph>& glyphs)
  471. {
  472. #if SUPPORT_10_4_FONTS
  473. #if ! SUPPORT_ONLY_10_4_FONTS
  474. if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
  475. #endif
  476. {
  477. glyphs.malloc (sizeof (NSGlyph) * length, 1);
  478. NSGlyph* const nsGlyphs = reinterpret_cast<NSGlyph*> (glyphs.getData());
  479. for (int i = 0; i < length; ++i)
  480. nsGlyphs[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text.getAndAdvance()];
  481. return;
  482. }
  483. #endif
  484. #if ! SUPPORT_ONLY_10_4_FONTS
  485. if (charToGlyphMapper == nullptr)
  486. charToGlyphMapper = new CharToGlyphMapper (fontRef);
  487. glyphs.malloc (length);
  488. for (int i = 0; i < length; ++i)
  489. glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text.getAndAdvance());
  490. #endif
  491. }
  492. #if ! SUPPORT_ONLY_10_4_FONTS
  493. // Reads a CGFontRef's character map table to convert unicode into glyph numbers
  494. class CharToGlyphMapper
  495. {
  496. public:
  497. CharToGlyphMapper (CGFontRef fontRef)
  498. : segCount (0), endCode (0), startCode (0), idDelta (0),
  499. idRangeOffset (0), glyphIndexes (0)
  500. {
  501. CFDataRef cmapTable = CGFontCopyTableForTag (fontRef, 'cmap');
  502. if (cmapTable != 0)
  503. {
  504. const int numSubtables = getValue16 (cmapTable, 2);
  505. for (int i = 0; i < numSubtables; ++i)
  506. {
  507. if (getValue16 (cmapTable, i * 8 + 4) == 0) // check for platform ID of 0
  508. {
  509. const int offset = getValue32 (cmapTable, i * 8 + 8);
  510. if (getValue16 (cmapTable, offset) == 4) // check that it's format 4..
  511. {
  512. const int length = getValue16 (cmapTable, offset + 2);
  513. const int segCountX2 = getValue16 (cmapTable, offset + 6);
  514. segCount = segCountX2 / 2;
  515. const int endCodeOffset = offset + 14;
  516. const int startCodeOffset = endCodeOffset + 2 + segCountX2;
  517. const int idDeltaOffset = startCodeOffset + segCountX2;
  518. const int idRangeOffsetOffset = idDeltaOffset + segCountX2;
  519. const int glyphIndexesOffset = idRangeOffsetOffset + segCountX2;
  520. endCode = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + endCodeOffset, segCountX2);
  521. startCode = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + startCodeOffset, segCountX2);
  522. idDelta = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + idDeltaOffset, segCountX2);
  523. idRangeOffset = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + idRangeOffsetOffset, segCountX2);
  524. glyphIndexes = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + glyphIndexesOffset, offset + length - glyphIndexesOffset);
  525. }
  526. break;
  527. }
  528. }
  529. CFRelease (cmapTable);
  530. }
  531. }
  532. ~CharToGlyphMapper()
  533. {
  534. if (endCode != 0)
  535. {
  536. CFRelease (endCode);
  537. CFRelease (startCode);
  538. CFRelease (idDelta);
  539. CFRelease (idRangeOffset);
  540. CFRelease (glyphIndexes);
  541. }
  542. }
  543. int getGlyphForCharacter (const juce_wchar c) const
  544. {
  545. for (int i = 0; i < segCount; ++i)
  546. {
  547. if (getValue16 (endCode, i * 2) >= c)
  548. {
  549. const int start = getValue16 (startCode, i * 2);
  550. if (start > c)
  551. break;
  552. const int delta = getValue16 (idDelta, i * 2);
  553. const int rangeOffset = getValue16 (idRangeOffset, i * 2);
  554. if (rangeOffset == 0)
  555. return delta + c;
  556. else
  557. return getValue16 (glyphIndexes, 2 * ((rangeOffset / 2) + (c - start) - (segCount - i)));
  558. }
  559. }
  560. // If we failed to find it "properly", this dodgy fall-back seems to do the trick for most fonts!
  561. return jmax (-1, (int) c - 29);
  562. }
  563. private:
  564. int segCount;
  565. CFDataRef endCode, startCode, idDelta, idRangeOffset, glyphIndexes;
  566. static uint16 getValue16 (CFDataRef data, const int index)
  567. {
  568. return CFSwapInt16BigToHost (*(UInt16*) (CFDataGetBytePtr (data) + index));
  569. }
  570. static uint32 getValue32 (CFDataRef data, const int index)
  571. {
  572. return CFSwapInt32BigToHost (*(UInt32*) (CFDataGetBytePtr (data) + index));
  573. }
  574. };
  575. ScopedPointer <CharToGlyphMapper> charToGlyphMapper;
  576. #endif
  577. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface);
  578. };
  579. #endif
  580. //==============================================================================
  581. Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
  582. {
  583. return new OSXTypeface (font);
  584. }
  585. StringArray Font::findAllTypefaceNames()
  586. {
  587. StringArray names;
  588. JUCE_AUTORELEASEPOOL
  589. #if JUCE_IOS
  590. NSArray* fonts = [UIFont familyNames];
  591. #else
  592. NSArray* fonts = [[NSFontManager sharedFontManager] availableFontFamilies];
  593. #endif
  594. for (unsigned int i = 0; i < [fonts count]; ++i)
  595. names.add (nsStringToJuce ((NSString*) [fonts objectAtIndex: i]));
  596. names.sort (true);
  597. return names;
  598. }
  599. struct DefaultFontNames
  600. {
  601. DefaultFontNames()
  602. #if JUCE_IOS
  603. : defaultSans ("Helvetica"),
  604. defaultSerif ("Times New Roman"),
  605. defaultFixed ("Courier New"),
  606. #else
  607. : defaultSans ("Lucida Grande"),
  608. defaultSerif ("Times New Roman"),
  609. defaultFixed ("Monaco"),
  610. #endif
  611. defaultFallback ("Arial Unicode MS")
  612. {
  613. }
  614. String defaultSans, defaultSerif, defaultFixed, defaultFallback;
  615. };
  616. Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
  617. {
  618. static DefaultFontNames defaultNames;
  619. String faceName (font.getTypefaceName());
  620. if (faceName == Font::getDefaultSansSerifFontName()) faceName = defaultNames.defaultSans;
  621. else if (faceName == Font::getDefaultSerifFontName()) faceName = defaultNames.defaultSerif;
  622. else if (faceName == Font::getDefaultMonospacedFontName()) faceName = defaultNames.defaultFixed;
  623. Font f (font);
  624. f.setTypefaceName (faceName);
  625. return Typeface::createSystemTypefaceFor (f);
  626. }