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.

354 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. // (This file gets included by juce_mac_NativeCode.mm, rather than being
  19. // compiled on its own).
  20. #ifdef JUCE_INCLUDED_FILE
  21. //==============================================================================
  22. class FontHelper
  23. {
  24. NSFont* font;
  25. public:
  26. String name;
  27. bool isBold, isItalic, needsItalicTransform;
  28. float fontSize, totalSize, ascent;
  29. int refCount;
  30. NSMutableDictionary* attributes;
  31. FontHelper (const String& name_,
  32. const bool bold_,
  33. const bool italic_,
  34. const float size_)
  35. : font (0),
  36. name (name_),
  37. isBold (bold_),
  38. isItalic (italic_),
  39. needsItalicTransform (false),
  40. fontSize (size_),
  41. refCount (1)
  42. {
  43. attributes = [[NSMutableDictionary dictionaryWithObject: [NSNumber numberWithInt: 0]
  44. forKey: NSLigatureAttributeName] retain];
  45. font = [NSFont fontWithName: juceStringToNS (name_) size: size_];
  46. if (italic_)
  47. {
  48. NSFont* newFont = [[NSFontManager sharedFontManager] convertFont: font toHaveTrait: NSItalicFontMask];
  49. if (newFont == font)
  50. needsItalicTransform = true; // couldn't find a proper italic version, so fake it with a transform..
  51. font = newFont;
  52. }
  53. if (bold_)
  54. font = [[NSFontManager sharedFontManager] convertFont: font toHaveTrait: NSBoldFontMask];
  55. [font retain];
  56. ascent = fabsf ([font ascender]);
  57. totalSize = ascent + fabsf ([font descender]);
  58. }
  59. ~FontHelper()
  60. {
  61. [font release];
  62. [attributes release];
  63. }
  64. bool getPathAndKerning (const juce_wchar char1,
  65. const juce_wchar char2,
  66. Path* path,
  67. float& kerning,
  68. float* ascent,
  69. float* descent)
  70. {
  71. const ScopedAutoReleasePool pool;
  72. if (font == 0
  73. || ! [[font coveredCharacterSet] longCharacterIsMember: (UTF32Char) char1])
  74. return false;
  75. String chars;
  76. chars << ' ' << char1 << char2;
  77. NSTextStorage* textStorage = [[[NSTextStorage alloc] initWithString: juceStringToNS (chars)
  78. attributes: attributes] autorelease];
  79. NSLayoutManager* layoutManager = [[[NSLayoutManager alloc] init] autorelease];
  80. NSTextContainer* textContainer = [[[NSTextContainer alloc] init] autorelease];
  81. [layoutManager addTextContainer: textContainer];
  82. [textStorage addLayoutManager: layoutManager];
  83. [textStorage setFont: font];
  84. unsigned int glyphIndex = [layoutManager glyphRangeForCharacterRange: NSMakeRange (1, 1)
  85. actualCharacterRange: 0].location;
  86. NSPoint p1 = [layoutManager locationForGlyphAtIndex: glyphIndex];
  87. NSPoint p2 = [layoutManager locationForGlyphAtIndex: glyphIndex + 1];
  88. kerning = p2.x - p1.x;
  89. if (ascent != 0)
  90. *ascent = this->ascent;
  91. if (descent != 0)
  92. *descent = fabsf ([font descender]);
  93. if (path != 0)
  94. {
  95. NSBezierPath* bez = [NSBezierPath bezierPath];
  96. [bez moveToPoint: NSMakePoint (0, 0)];
  97. [bez appendBezierPathWithGlyph: [layoutManager glyphAtIndex: glyphIndex]
  98. inFont: font];
  99. for (int i = 0; i < [bez elementCount]; ++i)
  100. {
  101. NSPoint p[3];
  102. switch ([bez elementAtIndex: i associatedPoints: p])
  103. {
  104. case NSMoveToBezierPathElement:
  105. path->startNewSubPath (p[0].x, -p[0].y);
  106. break;
  107. case NSLineToBezierPathElement:
  108. path->lineTo (p[0].x, -p[0].y);
  109. break;
  110. case NSCurveToBezierPathElement:
  111. path->cubicTo (p[0].x, -p[0].y, p[1].x, -p[1].y, p[2].x, -p[2].y);
  112. break;
  113. case NSClosePathBezierPathElement:
  114. path->closeSubPath();
  115. break;
  116. default:
  117. jassertfalse
  118. break;
  119. }
  120. }
  121. if (needsItalicTransform)
  122. path->applyTransform (AffineTransform::identity.sheared (-0.15, 0));
  123. }
  124. return kerning != 0;
  125. }
  126. juce_wchar getDefaultChar()
  127. {
  128. return 0;
  129. }
  130. };
  131. //==============================================================================
  132. class FontHelperCache : public Timer,
  133. public DeletedAtShutdown
  134. {
  135. VoidArray cache;
  136. public:
  137. FontHelperCache()
  138. {
  139. }
  140. ~FontHelperCache()
  141. {
  142. for (int i = cache.size(); --i >= 0;)
  143. {
  144. FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
  145. delete f;
  146. }
  147. clearSingletonInstance();
  148. }
  149. FontHelper* getFont (const String& name,
  150. const bool bold,
  151. const bool italic,
  152. const float size = 1024)
  153. {
  154. for (int i = cache.size(); --i >= 0;)
  155. {
  156. FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
  157. if (f->name == name
  158. && f->isBold == bold
  159. && f->isItalic == italic
  160. && f->fontSize == size)
  161. {
  162. f->refCount++;
  163. return f;
  164. }
  165. }
  166. FontHelper* const f = new FontHelper (name, bold, italic, size);
  167. cache.add (f);
  168. return f;
  169. }
  170. void releaseFont (FontHelper* f)
  171. {
  172. for (int i = cache.size(); --i >= 0;)
  173. {
  174. FontHelper* const f2 = (FontHelper*) cache.getUnchecked(i);
  175. if (f == f2)
  176. {
  177. f->refCount--;
  178. if (f->refCount == 0)
  179. startTimer (5000);
  180. break;
  181. }
  182. }
  183. }
  184. void timerCallback()
  185. {
  186. stopTimer();
  187. for (int i = cache.size(); --i >= 0;)
  188. {
  189. FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
  190. if (f->refCount == 0)
  191. {
  192. cache.remove (i);
  193. delete f;
  194. }
  195. }
  196. if (cache.size() == 0)
  197. delete this;
  198. }
  199. juce_DeclareSingleton_SingleThreaded_Minimal (FontHelperCache)
  200. };
  201. juce_ImplementSingleton_SingleThreaded (FontHelperCache)
  202. //==============================================================================
  203. void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
  204. bool bold,
  205. bool italic,
  206. bool addAllGlyphsToFont) throw()
  207. {
  208. // This method is only safe to be called from the normal UI thread..
  209. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  210. FontHelper* const helper = FontHelperCache::getInstance()
  211. ->getFont (fontName, bold, italic);
  212. clear();
  213. setAscent (helper->ascent / helper->totalSize);
  214. setName (fontName);
  215. setDefaultCharacter (helper->getDefaultChar());
  216. setBold (bold);
  217. setItalic (italic);
  218. if (addAllGlyphsToFont)
  219. {
  220. //xxx
  221. jassertfalse
  222. }
  223. FontHelperCache::getInstance()->releaseFont (helper);
  224. }
  225. bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
  226. {
  227. // This method is only safe to be called from the normal UI thread..
  228. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  229. if (character == 0)
  230. return false;
  231. FontHelper* const helper = FontHelperCache::getInstance()
  232. ->getFont (getName(), isBold(), isItalic());
  233. Path path;
  234. float width;
  235. bool foundOne = false;
  236. if (helper->getPathAndKerning (character, T('I'), &path, width, 0, 0))
  237. {
  238. path.applyTransform (AffineTransform::scale (1.0f / helper->totalSize,
  239. 1.0f / helper->totalSize));
  240. addGlyph (character, path, width / helper->totalSize);
  241. for (int i = 0; i < glyphs.size(); ++i)
  242. {
  243. const TypefaceGlyphInfo* const g = (const TypefaceGlyphInfo*) glyphs.getUnchecked(i);
  244. float kerning;
  245. if (helper->getPathAndKerning (character, g->getCharacter(), 0, kerning, 0, 0))
  246. {
  247. kerning = (kerning - width) / helper->totalSize;
  248. if (kerning != 0)
  249. addKerningPair (character, g->getCharacter(), kerning);
  250. }
  251. if (helper->getPathAndKerning (g->getCharacter(), character, 0, kerning, 0, 0))
  252. {
  253. kerning = kerning / helper->totalSize - g->width;
  254. if (kerning != 0)
  255. addKerningPair (g->getCharacter(), character, kerning);
  256. }
  257. }
  258. foundOne = true;
  259. }
  260. FontHelperCache::getInstance()->releaseFont (helper);
  261. return foundOne;
  262. }
  263. //==============================================================================
  264. const StringArray Font::findAllTypefaceNames() throw()
  265. {
  266. StringArray names;
  267. const ScopedAutoReleasePool pool;
  268. NSArray* fonts = [[NSFontManager sharedFontManager] availableFontFamilies];
  269. for (unsigned int i = 0; i < [fonts count]; ++i)
  270. names.add (nsStringToJuce ((NSString*) [fonts objectAtIndex: i]));
  271. names.sort (true);
  272. return names;
  273. }
  274. void Typeface::getDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed) throw()
  275. {
  276. defaultSans = "Lucida Grande";
  277. defaultSerif = "Times New Roman";
  278. defaultFixed = "Monaco";
  279. }
  280. #endif