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.

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