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.

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