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.

339 lines
11KB

  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] initWithString: juceStringToNS (chars)] autorelease];
  73. NSLayoutManager* layoutManager = [[[NSLayoutManager alloc] init] autorelease];
  74. NSTextContainer* textContainer = [[[NSTextContainer alloc] init] autorelease];
  75. [layoutManager addTextContainer: textContainer];
  76. [textStorage addLayoutManager: layoutManager];
  77. [textStorage setFont: font];
  78. unsigned int glyphIndex = [layoutManager glyphRangeForCharacterRange: NSMakeRange (1, 1)
  79. actualCharacterRange: 0].location;
  80. NSPoint p1 = [layoutManager locationForGlyphAtIndex: glyphIndex];
  81. NSPoint p2 = [layoutManager locationForGlyphAtIndex: glyphIndex + 1];
  82. kerning = p2.x - p1.x;
  83. if (ascent != 0)
  84. *ascent = this->ascent;
  85. if (descent != 0)
  86. *descent = fabsf ([font descender]);
  87. if (path != 0)
  88. {
  89. NSBezierPath* bez = [NSBezierPath bezierPath];
  90. [bez moveToPoint: NSMakePoint (0, 0)];
  91. [bez appendBezierPathWithGlyph: [layoutManager glyphAtIndex: glyphIndex]
  92. inFont: font];
  93. for (int i = 0; i < [bez elementCount]; ++i)
  94. {
  95. NSPoint p[3];
  96. switch ([bez elementAtIndex: i associatedPoints: p])
  97. {
  98. case NSMoveToBezierPathElement:
  99. path->startNewSubPath (p[0].x, -p[0].y);
  100. break;
  101. case NSLineToBezierPathElement:
  102. path->lineTo (p[0].x, -p[0].y);
  103. break;
  104. case NSCurveToBezierPathElement:
  105. path->cubicTo (p[0].x, -p[0].y, p[1].x, -p[1].y, p[2].x, -p[2].y);
  106. break;
  107. case NSClosePathBezierPathElement:
  108. path->closeSubPath();
  109. break;
  110. default:
  111. jassertfalse
  112. break;
  113. }
  114. }
  115. }
  116. return kerning != 0;
  117. }
  118. juce_wchar getDefaultChar()
  119. {
  120. return 0;
  121. }
  122. };
  123. //==============================================================================
  124. class FontHelperCache : public Timer,
  125. public DeletedAtShutdown
  126. {
  127. VoidArray cache;
  128. public:
  129. FontHelperCache()
  130. {
  131. }
  132. ~FontHelperCache()
  133. {
  134. for (int i = cache.size(); --i >= 0;)
  135. {
  136. FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
  137. delete f;
  138. }
  139. clearSingletonInstance();
  140. }
  141. FontHelper* getFont (const String& name,
  142. const bool bold,
  143. const bool italic,
  144. const float size = 1024)
  145. {
  146. for (int i = cache.size(); --i >= 0;)
  147. {
  148. FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
  149. if (f->name == name
  150. && f->isBold == bold
  151. && f->isItalic == italic
  152. && f->fontSize == size)
  153. {
  154. f->refCount++;
  155. return f;
  156. }
  157. }
  158. FontHelper* const f = new FontHelper (name, bold, italic, size);
  159. cache.add (f);
  160. return f;
  161. }
  162. void releaseFont (FontHelper* f)
  163. {
  164. for (int i = cache.size(); --i >= 0;)
  165. {
  166. FontHelper* const f2 = (FontHelper*) cache.getUnchecked(i);
  167. if (f == f2)
  168. {
  169. f->refCount--;
  170. if (f->refCount == 0)
  171. startTimer (5000);
  172. break;
  173. }
  174. }
  175. }
  176. void timerCallback()
  177. {
  178. stopTimer();
  179. for (int i = cache.size(); --i >= 0;)
  180. {
  181. FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
  182. if (f->refCount == 0)
  183. {
  184. cache.remove (i);
  185. delete f;
  186. }
  187. }
  188. if (cache.size() == 0)
  189. delete this;
  190. }
  191. juce_DeclareSingleton_SingleThreaded_Minimal (FontHelperCache)
  192. };
  193. juce_ImplementSingleton_SingleThreaded (FontHelperCache)
  194. //==============================================================================
  195. void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
  196. bool bold,
  197. bool italic,
  198. bool addAllGlyphsToFont) throw()
  199. {
  200. // This method is only safe to be called from the normal UI thread..
  201. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  202. FontHelper* const helper = FontHelperCache::getInstance()
  203. ->getFont (fontName, bold, italic);
  204. clear();
  205. setAscent (helper->ascent / helper->totalSize);
  206. setName (fontName);
  207. setDefaultCharacter (helper->getDefaultChar());
  208. setBold (bold);
  209. setItalic (italic);
  210. if (addAllGlyphsToFont)
  211. {
  212. //xxx
  213. jassertfalse
  214. }
  215. FontHelperCache::getInstance()->releaseFont (helper);
  216. }
  217. bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
  218. {
  219. // This method is only safe to be called from the normal UI thread..
  220. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  221. FontHelper* const helper = FontHelperCache::getInstance()
  222. ->getFont (getName(), isBold(), isItalic());
  223. Path path;
  224. float width;
  225. bool foundOne = false;
  226. if (helper->getPathAndKerning (character, T('I'), &path, width, 0, 0))
  227. {
  228. path.applyTransform (AffineTransform::scale (1.0f / helper->totalSize,
  229. 1.0f / helper->totalSize));
  230. addGlyph (character, path, width / helper->totalSize);
  231. for (int i = 0; i < glyphs.size(); ++i)
  232. {
  233. const TypefaceGlyphInfo* const g = (const TypefaceGlyphInfo*) glyphs.getUnchecked(i);
  234. float kerning;
  235. if (helper->getPathAndKerning (character, g->getCharacter(), 0, kerning, 0, 0))
  236. {
  237. kerning = (kerning - width) / helper->totalSize;
  238. if (kerning != 0)
  239. addKerningPair (character, g->getCharacter(), kerning);
  240. }
  241. if (helper->getPathAndKerning (g->getCharacter(), character, 0, kerning, 0, 0))
  242. {
  243. kerning = kerning / helper->totalSize - g->width;
  244. if (kerning != 0)
  245. addKerningPair (g->getCharacter(), character, kerning);
  246. }
  247. }
  248. foundOne = true;
  249. }
  250. FontHelperCache::getInstance()->releaseFont (helper);
  251. return foundOne;
  252. }
  253. //==============================================================================
  254. const StringArray Font::findAllTypefaceNames() throw()
  255. {
  256. StringArray names;
  257. const ScopedAutoReleasePool pool;
  258. NSArray* fonts = [[NSFontManager sharedFontManager] availableFontFamilies];
  259. for (int i = 0; i < [fonts count]; ++i)
  260. names.add (nsStringToJuce ((NSString*) [fonts objectAtIndex: i]));
  261. names.sort (true);
  262. return names;
  263. }
  264. void Typeface::getDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed) throw()
  265. {
  266. defaultSans = "Lucida Grande";
  267. defaultSerif = "Times New Roman";
  268. defaultFixed = "Monaco";
  269. }
  270. #endif