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.

545 lines
18KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 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. struct FTLibWrapper : public ReferenceCountedObject
  19. {
  20. FTLibWrapper() : library (0)
  21. {
  22. if (FT_Init_FreeType (&library) != 0)
  23. {
  24. library = 0;
  25. DBG ("Failed to initialize FreeType");
  26. }
  27. }
  28. ~FTLibWrapper()
  29. {
  30. if (library != 0)
  31. FT_Done_FreeType (library);
  32. }
  33. FT_Library library;
  34. typedef ReferenceCountedObjectPtr <FTLibWrapper> Ptr;
  35. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTLibWrapper);
  36. };
  37. //==============================================================================
  38. struct FTFaceWrapper : public ReferenceCountedObject
  39. {
  40. FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const File& file, int faceIndex)
  41. : face (0), library (ftLib)
  42. {
  43. if (FT_New_Face (ftLib->library, file.getFullPathName().toUTF8(), faceIndex, &face) != 0)
  44. face = 0;
  45. }
  46. ~FTFaceWrapper()
  47. {
  48. if (face != 0)
  49. FT_Done_Face (face);
  50. }
  51. FT_Face face;
  52. FTLibWrapper::Ptr library;
  53. typedef ReferenceCountedObjectPtr <FTFaceWrapper> Ptr;
  54. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTFaceWrapper);
  55. };
  56. //==============================================================================
  57. class LinuxFontFileIterator
  58. {
  59. public:
  60. LinuxFontFileIterator()
  61. : index (0)
  62. {
  63. fontDirs.addTokens (CharPointer_UTF8 (getenv ("JUCE_FONT_PATH")), ";,", String::empty);
  64. fontDirs.removeEmptyStrings (true);
  65. if (fontDirs.size() == 0)
  66. {
  67. const ScopedPointer<XmlElement> fontsInfo (XmlDocument::parse (File ("/etc/fonts/fonts.conf")));
  68. if (fontsInfo != nullptr)
  69. {
  70. forEachXmlChildElementWithTagName (*fontsInfo, e, "dir")
  71. {
  72. fontDirs.add (e->getAllSubText().trim());
  73. }
  74. }
  75. }
  76. if (fontDirs.size() == 0)
  77. fontDirs.add ("/usr/X11R6/lib/X11/fonts");
  78. fontDirs.removeEmptyStrings (true);
  79. }
  80. bool next()
  81. {
  82. if (iter != nullptr)
  83. {
  84. while (iter->next())
  85. if (getFile().hasFileExtension ("ttf;pfb;pcf"))
  86. return true;
  87. }
  88. if (index >= fontDirs.size())
  89. return false;
  90. iter = new DirectoryIterator (fontDirs [index++], true);
  91. return next();
  92. }
  93. File getFile() const { jassert (iter != nullptr); return iter->getFile(); }
  94. private:
  95. StringArray fontDirs;
  96. int index;
  97. ScopedPointer<DirectoryIterator> iter;
  98. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LinuxFontFileIterator);
  99. };
  100. //==============================================================================
  101. class FTTypefaceList : public DeletedAtShutdown
  102. {
  103. public:
  104. FTTypefaceList()
  105. : library (new FTLibWrapper())
  106. {
  107. LinuxFontFileIterator fontFileIterator;
  108. while (fontFileIterator.next())
  109. {
  110. int faceIndex = 0;
  111. int numFaces = 0;
  112. do
  113. {
  114. FTFaceWrapper face (library, fontFileIterator.getFile(), faceIndex);
  115. if (face.face != 0)
  116. {
  117. if (faceIndex == 0)
  118. numFaces = face.face->num_faces;
  119. if ((face.face->face_flags & FT_FACE_FLAG_SCALABLE) != 0)
  120. faces.add (new KnownTypeface (fontFileIterator.getFile(), faceIndex, face));
  121. }
  122. ++faceIndex;
  123. }
  124. while (faceIndex < numFaces);
  125. }
  126. }
  127. ~FTTypefaceList()
  128. {
  129. clearSingletonInstance();
  130. }
  131. //==============================================================================
  132. struct KnownTypeface
  133. {
  134. KnownTypeface (const File& file_, const int faceIndex_, const FTFaceWrapper& face)
  135. : file (file_),
  136. family (face.face->family_name),
  137. faceIndex (faceIndex_),
  138. isBold ((face.face->style_flags & FT_STYLE_FLAG_BOLD) != 0),
  139. isItalic ((face.face->style_flags & FT_STYLE_FLAG_ITALIC) != 0),
  140. isMonospaced ((face.face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0),
  141. isSansSerif (isFaceSansSerif (family))
  142. {
  143. }
  144. const File file;
  145. const String family;
  146. const int faceIndex;
  147. const bool isBold, isItalic, isMonospaced, isSansSerif;
  148. JUCE_DECLARE_NON_COPYABLE (KnownTypeface);
  149. };
  150. //==============================================================================
  151. FTFaceWrapper::Ptr createFace (const String& fontName, const bool bold, const bool italic)
  152. {
  153. const KnownTypeface* ftFace = matchTypeface (fontName, bold, italic);
  154. if (ftFace == nullptr)
  155. {
  156. ftFace = matchTypeface (fontName, ! bold, italic);
  157. if (ftFace == nullptr)
  158. {
  159. ftFace = matchTypeface (fontName, bold, ! italic);
  160. if (ftFace == nullptr)
  161. ftFace = matchTypeface (fontName, ! bold, ! italic);
  162. }
  163. }
  164. if (ftFace != nullptr)
  165. {
  166. FTFaceWrapper::Ptr face (new FTFaceWrapper (library, ftFace->file, ftFace->faceIndex));
  167. if (face->face != 0)
  168. {
  169. // If there isn't a unicode charmap then select the first one.
  170. if (FT_Select_Charmap (face->face, ft_encoding_unicode) != 0)
  171. FT_Set_Charmap (face->face, face->face->charmaps[0]);
  172. return face;
  173. }
  174. }
  175. return nullptr;
  176. }
  177. //==============================================================================
  178. void getFamilyNames (StringArray& familyNames) const
  179. {
  180. for (int i = 0; i < faces.size(); i++)
  181. familyNames.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
  182. }
  183. void getMonospacedNames (StringArray& monoSpaced) const
  184. {
  185. for (int i = 0; i < faces.size(); i++)
  186. if (faces.getUnchecked(i)->isMonospaced)
  187. monoSpaced.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
  188. }
  189. void getSerifNames (StringArray& serif) const
  190. {
  191. for (int i = 0; i < faces.size(); i++)
  192. if (! faces.getUnchecked(i)->isSansSerif)
  193. serif.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
  194. }
  195. void getSansSerifNames (StringArray& sansSerif) const
  196. {
  197. for (int i = 0; i < faces.size(); i++)
  198. if (faces.getUnchecked(i)->isSansSerif)
  199. sansSerif.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
  200. }
  201. juce_DeclareSingleton_SingleThreaded_Minimal (FTTypefaceList);
  202. private:
  203. FTLibWrapper::Ptr library;
  204. OwnedArray<KnownTypeface> faces;
  205. const KnownTypeface* matchTypeface (const String& familyName, const bool wantBold, const bool wantItalic) const noexcept
  206. {
  207. for (int i = 0; i < faces.size(); ++i)
  208. {
  209. const KnownTypeface* const face = faces.getUnchecked(i);
  210. if (face->family == familyName
  211. && face->isBold == wantBold
  212. && face->isItalic == wantItalic)
  213. return face;
  214. }
  215. return nullptr;
  216. }
  217. static bool isFaceSansSerif (const String& family)
  218. {
  219. const char* sansNames[] = { "Sans", "Verdana", "Arial", "Ubuntu" };
  220. for (int i = 0; i < numElementsInArray (sansNames); ++i)
  221. if (family.containsIgnoreCase (sansNames[i]))
  222. return true;
  223. return false;
  224. }
  225. JUCE_DECLARE_NON_COPYABLE (FTTypefaceList);
  226. };
  227. juce_ImplementSingleton_SingleThreaded (FTTypefaceList)
  228. //==============================================================================
  229. class FreeTypeTypeface : public CustomTypeface
  230. {
  231. public:
  232. FreeTypeTypeface (const Font& font)
  233. : faceWrapper (FTTypefaceList::getInstance()
  234. ->createFace (font.getTypefaceName(), font.isBold(), font.isItalic()))
  235. {
  236. if (faceWrapper != nullptr)
  237. {
  238. setCharacteristics (font.getTypefaceName(),
  239. faceWrapper->face->ascender / (float) (faceWrapper->face->ascender - faceWrapper->face->descender),
  240. font.isBold(), font.isItalic(),
  241. L' ');
  242. }
  243. else
  244. {
  245. DBG ("Failed to create typeface: " << font.getTypefaceName() << " "
  246. << (font.isBold() ? 'B' : ' ') << (font.isItalic() ? 'I' : ' '));
  247. }
  248. }
  249. bool loadGlyphIfPossible (const juce_wchar character)
  250. {
  251. if (faceWrapper != nullptr)
  252. {
  253. FT_Face face = faceWrapper->face;
  254. const unsigned int glyphIndex = FT_Get_Char_Index (face, character);
  255. if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM) == 0
  256. && face->glyph->format == ft_glyph_format_outline)
  257. {
  258. const float scale = 1.0f / (float) (face->ascender - face->descender);
  259. Path destShape;
  260. if (getGlyphShape (destShape, face->glyph->outline, scale))
  261. {
  262. addGlyph (character, destShape, face->glyph->metrics.horiAdvance * scale);
  263. if ((face->face_flags & FT_FACE_FLAG_KERNING) != 0)
  264. addKerning (face, character, glyphIndex);
  265. return true;
  266. }
  267. }
  268. }
  269. return false;
  270. }
  271. private:
  272. FTFaceWrapper::Ptr faceWrapper;
  273. bool getGlyphShape (Path& destShape, const FT_Outline& outline, const float scaleX)
  274. {
  275. const float scaleY = -scaleX;
  276. const short* const contours = outline.contours;
  277. const char* const tags = outline.tags;
  278. const FT_Vector* const points = outline.points;
  279. for (int c = 0; c < outline.n_contours; ++c)
  280. {
  281. const int startPoint = (c == 0) ? 0 : contours [c - 1] + 1;
  282. const int endPoint = contours[c];
  283. for (int p = startPoint; p <= endPoint; ++p)
  284. {
  285. const float x = scaleX * points[p].x;
  286. const float y = scaleY * points[p].y;
  287. if (p == startPoint)
  288. {
  289. if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
  290. {
  291. float x2 = scaleX * points [endPoint].x;
  292. float y2 = scaleY * points [endPoint].y;
  293. if (FT_CURVE_TAG (tags[endPoint]) != FT_Curve_Tag_On)
  294. {
  295. x2 = (x + x2) * 0.5f;
  296. y2 = (y + y2) * 0.5f;
  297. }
  298. destShape.startNewSubPath (x2, y2);
  299. }
  300. else
  301. {
  302. destShape.startNewSubPath (x, y);
  303. }
  304. }
  305. if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_On)
  306. {
  307. if (p != startPoint)
  308. destShape.lineTo (x, y);
  309. }
  310. else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
  311. {
  312. const int nextIndex = (p == endPoint) ? startPoint : p + 1;
  313. float x2 = scaleX * points [nextIndex].x;
  314. float y2 = scaleY * points [nextIndex].y;
  315. if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic)
  316. {
  317. x2 = (x + x2) * 0.5f;
  318. y2 = (y + y2) * 0.5f;
  319. }
  320. else
  321. {
  322. ++p;
  323. }
  324. destShape.quadraticTo (x, y, x2, y2);
  325. }
  326. else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Cubic)
  327. {
  328. const int next1 = p + 1;
  329. const int next2 = (p == (endPoint - 1)) ? startPoint : (p + 2);
  330. if (p >= endPoint
  331. || FT_CURVE_TAG (tags[next1]) != FT_Curve_Tag_Cubic
  332. || FT_CURVE_TAG (tags[next2]) != FT_Curve_Tag_On)
  333. return false;
  334. const float x2 = scaleX * points [next1].x;
  335. const float y2 = scaleY * points [next1].y;
  336. const float x3 = scaleX * points [next2].x;
  337. const float y3 = scaleY * points [next2].y;
  338. destShape.cubicTo (x, y, x2, y2, x3, y3);
  339. p += 2;
  340. }
  341. }
  342. destShape.closeSubPath();
  343. }
  344. return true;
  345. }
  346. void addKerning (FT_Face face, const uint32 character, const uint32 glyphIndex)
  347. {
  348. const float height = (float) (face->ascender - face->descender);
  349. uint32 rightGlyphIndex;
  350. uint32 rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
  351. while (rightGlyphIndex != 0)
  352. {
  353. FT_Vector kerning;
  354. if (FT_Get_Kerning (face, glyphIndex, rightGlyphIndex, ft_kerning_unscaled, &kerning) == 0
  355. && kerning.x != 0)
  356. addKerningPair (character, rightCharCode, kerning.x / height);
  357. rightCharCode = FT_Get_Next_Char (face, rightCharCode, &rightGlyphIndex);
  358. }
  359. }
  360. JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface);
  361. };
  362. //==============================================================================
  363. Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
  364. {
  365. return new FreeTypeTypeface (font);
  366. }
  367. StringArray Font::findAllTypefaceNames()
  368. {
  369. StringArray s;
  370. FTTypefaceList::getInstance()->getFamilyNames (s);
  371. s.sort (true);
  372. return s;
  373. }
  374. //==============================================================================
  375. struct DefaultFontNames
  376. {
  377. DefaultFontNames()
  378. : defaultSans (getDefaultSansSerifFontName()),
  379. defaultSerif (getDefaultSerifFontName()),
  380. defaultFixed (getDefaultMonospacedFontName())
  381. {
  382. }
  383. String defaultSans, defaultSerif, defaultFixed;
  384. private:
  385. static String pickBestFont (const StringArray& names, const char* const* choicesArray)
  386. {
  387. const StringArray choices (choicesArray);
  388. int j;
  389. for (j = 0; j < choices.size(); ++j)
  390. if (names.contains (choices[j], true))
  391. return choices[j];
  392. for (j = 0; j < choices.size(); ++j)
  393. for (int i = 0; i < names.size(); ++i)
  394. if (names[i].startsWithIgnoreCase (choices[j]))
  395. return names[i];
  396. for (j = 0; j < choices.size(); ++j)
  397. for (int i = 0; i < names.size(); ++i)
  398. if (names[i].containsIgnoreCase (choices[j]))
  399. return names[i];
  400. return names[0];
  401. }
  402. static String getDefaultSansSerifFontName()
  403. {
  404. StringArray allFonts;
  405. FTTypefaceList::getInstance()->getSansSerifNames (allFonts);
  406. const char* targets[] = { "Verdana", "Bitstream Vera Sans", "Luxi Sans", "Sans", 0 };
  407. return pickBestFont (allFonts, targets);
  408. }
  409. static String getDefaultSerifFontName()
  410. {
  411. StringArray allFonts;
  412. FTTypefaceList::getInstance()->getSerifNames (allFonts);
  413. const char* targets[] = { "Bitstream Vera Serif", "Times", "Nimbus Roman", "Serif", 0 };
  414. return pickBestFont (allFonts, targets);
  415. }
  416. static String getDefaultMonospacedFontName()
  417. {
  418. StringArray allFonts;
  419. FTTypefaceList::getInstance()->getMonospacedNames (allFonts);
  420. const char* targets[] = { "Bitstream Vera Sans Mono", "Courier", "Sans Mono", "Mono", 0 };
  421. return pickBestFont (allFonts, targets);
  422. }
  423. JUCE_DECLARE_NON_COPYABLE (DefaultFontNames);
  424. };
  425. Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
  426. {
  427. static DefaultFontNames defaultNames;
  428. String faceName (font.getTypefaceName());
  429. if (faceName == getDefaultSansSerifFontName()) faceName = defaultNames.defaultSans;
  430. else if (faceName == getDefaultSerifFontName()) faceName = defaultNames.defaultSerif;
  431. else if (faceName == getDefaultMonospacedFontName()) faceName = defaultNames.defaultFixed;
  432. Font f (font);
  433. f.setTypefaceName (faceName);
  434. return Typeface::createSystemTypefaceFor (f);
  435. }