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.

342 lines
10KB

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