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.

625 lines
20KB

  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. #include "../../../juce_Config.h"
  24. #if JUCE_BUILD_GUI_CLASSES
  25. #include "linuxincludes.h"
  26. #include <ft2build.h>
  27. #include FT_FREETYPE_H
  28. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  29. BEGIN_JUCE_NAMESPACE
  30. #include "../../../src/juce_appframework/gui/graphics/fonts/juce_Font.h"
  31. #include "../../../src/juce_core/basics/juce_Singleton.h"
  32. #include "../../../src/juce_core/io/streams/juce_MemoryInputStream.h"
  33. #include "../../../src/juce_core/io/files/juce_DirectoryIterator.h"
  34. #include "../../../src/juce_core/text/juce_XmlDocument.h"
  35. #include "../../../src/juce_appframework/application/juce_DeletedAtShutdown.h"
  36. //==============================================================================
  37. class FreeTypeFontFace
  38. {
  39. public:
  40. //==============================================================================
  41. enum FontStyle
  42. {
  43. Plain = 0,
  44. Bold = 1,
  45. Italic = 2
  46. };
  47. struct FontNameIndex
  48. {
  49. String fileName;
  50. int faceIndex;
  51. };
  52. //==============================================================================
  53. FreeTypeFontFace (const String& familyName)
  54. : hasSerif (false),
  55. monospaced (false)
  56. {
  57. family = familyName;
  58. }
  59. void setFileName (const String& name,
  60. const int faceIndex,
  61. FontStyle style)
  62. {
  63. if (names[(int) style].fileName.isEmpty())
  64. {
  65. names[(int) style].fileName = name;
  66. names[(int) style].faceIndex = faceIndex;
  67. }
  68. }
  69. const String& getFamilyName() const throw()
  70. {
  71. return family;
  72. }
  73. const String& getFileName (int style, int* faceIndex) const throw()
  74. {
  75. *faceIndex = names [style].faceIndex;
  76. return names[style].fileName;
  77. }
  78. void setMonospaced (bool mono) { monospaced = mono; }
  79. bool getMonospaced () const throw() { return monospaced; }
  80. void setSerif (const bool serif) { hasSerif = serif; }
  81. bool getSerif () const throw() { return hasSerif; }
  82. private:
  83. //==============================================================================
  84. String family;
  85. FontNameIndex names[4];
  86. bool hasSerif, monospaced;
  87. };
  88. //==============================================================================
  89. class FreeTypeInterface : public DeletedAtShutdown
  90. {
  91. public:
  92. //==============================================================================
  93. FreeTypeInterface()
  94. : lastFace (0),
  95. lastBold (false),
  96. lastItalic (false)
  97. {
  98. if (FT_Init_FreeType (&ftLib) != 0)
  99. {
  100. ftLib = 0;
  101. DBG (T("Failed to initialize FreeType"));
  102. }
  103. StringArray fontDirs;
  104. fontDirs.addTokens (String (getenv ("JUCE_FONT_PATH")), T(";,"), 0);
  105. fontDirs.removeEmptyStrings (true);
  106. if (fontDirs.size() == 0)
  107. {
  108. XmlDocument fontsConfig (File ("/etc/fonts/fonts.conf"));
  109. XmlElement* const fontsInfo = fontsConfig.getDocumentElement();
  110. if (fontsInfo != 0)
  111. {
  112. forEachXmlChildElementWithTagName (*fontsInfo, e, T("dir"))
  113. {
  114. fontDirs.add (e->getAllSubText().trim());
  115. }
  116. delete fontsInfo;
  117. }
  118. }
  119. if (fontDirs.size() == 0)
  120. fontDirs.add ("/usr/X11R6/lib/X11/fonts");
  121. for (int i = 0; i < fontDirs.size(); ++i)
  122. enumerateFaces (fontDirs[i]);
  123. }
  124. ~FreeTypeInterface()
  125. {
  126. if (lastFace != 0)
  127. FT_Done_Face (lastFace);
  128. if (ftLib != 0)
  129. FT_Done_FreeType (ftLib);
  130. clearSingletonInstance();
  131. }
  132. //==============================================================================
  133. FreeTypeFontFace* findOrCreate (const String& familyName,
  134. const bool create = false)
  135. {
  136. for (int i = 0; i < faces.size(); i++)
  137. if (faces[i]->getFamilyName() == familyName)
  138. return faces[i];
  139. if (! create)
  140. return NULL;
  141. FreeTypeFontFace* newFace = new FreeTypeFontFace (familyName);
  142. faces.add (newFace);
  143. return newFace;
  144. }
  145. // Enumerate all font faces available in a given directory
  146. void enumerateFaces (const String& path)
  147. {
  148. File dirPath (path);
  149. if (path.isEmpty() || ! dirPath.isDirectory())
  150. return;
  151. DirectoryIterator di (dirPath, true);
  152. while (di.next())
  153. {
  154. File possible (di.getFile());
  155. if (possible.hasFileExtension (T("ttf"))
  156. || possible.hasFileExtension (T("pfb"))
  157. || possible.hasFileExtension (T("pcf")))
  158. {
  159. FT_Face face;
  160. int faceIndex = 0;
  161. int numFaces = 0;
  162. do
  163. {
  164. if (FT_New_Face (ftLib,
  165. possible.getFullPathName(),
  166. faceIndex,
  167. &face) == 0)
  168. {
  169. if (faceIndex == 0)
  170. numFaces = face->num_faces;
  171. if ((face->face_flags & FT_FACE_FLAG_SCALABLE) != 0)
  172. {
  173. FreeTypeFontFace* const newFace = findOrCreate (face->family_name, true);
  174. int style = (int) FreeTypeFontFace::Plain;
  175. if ((face->style_flags & FT_STYLE_FLAG_BOLD) != 0)
  176. style |= (int) FreeTypeFontFace::Bold;
  177. if ((face->style_flags & FT_STYLE_FLAG_ITALIC) != 0)
  178. style |= (int) FreeTypeFontFace::Italic;
  179. newFace->setFileName (possible.getFullPathName(), faceIndex, (FreeTypeFontFace::FontStyle) style);
  180. if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
  181. newFace->setMonospaced (true);
  182. else
  183. newFace->setMonospaced (false);
  184. // Surely there must be a better way to do this?
  185. if (String (face->family_name).containsIgnoreCase (T("Sans"))
  186. || String (face->family_name).containsIgnoreCase (T("Verdana"))
  187. || String (face->family_name).containsIgnoreCase (T("Arial")))
  188. {
  189. newFace->setSerif (false);
  190. }
  191. else
  192. {
  193. newFace->setSerif (true);
  194. }
  195. }
  196. FT_Done_Face (face);
  197. }
  198. ++faceIndex;
  199. }
  200. while (faceIndex < numFaces);
  201. }
  202. }
  203. }
  204. // Create a FreeType face object for a given font
  205. FT_Face createFT_Face (const String& fontName,
  206. const bool bold,
  207. const bool italic)
  208. {
  209. FT_Face face = NULL;
  210. if (fontName == lastFontName && bold == lastBold && italic == lastItalic)
  211. {
  212. face = lastFace;
  213. }
  214. else
  215. {
  216. if (lastFace)
  217. {
  218. FT_Done_Face (lastFace);
  219. lastFace = NULL;
  220. }
  221. lastFontName = fontName;
  222. lastBold = bold;
  223. lastItalic = italic;
  224. FreeTypeFontFace* const ftFace = findOrCreate (fontName);
  225. if (ftFace != 0)
  226. {
  227. int style = (int) FreeTypeFontFace::Plain;
  228. if (bold)
  229. style |= (int) FreeTypeFontFace::Bold;
  230. if (italic)
  231. style |= (int) FreeTypeFontFace::Italic;
  232. int faceIndex;
  233. String fileName (ftFace->getFileName (style, &faceIndex));
  234. if (fileName.isEmpty())
  235. {
  236. style ^= (int) FreeTypeFontFace::Bold;
  237. fileName = ftFace->getFileName (style, &faceIndex);
  238. if (fileName.isEmpty())
  239. {
  240. style ^= (int) FreeTypeFontFace::Bold;
  241. style ^= (int) FreeTypeFontFace::Italic;
  242. fileName = ftFace->getFileName (style, &faceIndex);
  243. if (! fileName.length())
  244. {
  245. style ^= (int) FreeTypeFontFace::Bold;
  246. fileName = ftFace->getFileName (style, &faceIndex);
  247. }
  248. }
  249. }
  250. if (! FT_New_Face (ftLib, (const char*) fileName, faceIndex, &lastFace))
  251. {
  252. face = lastFace;
  253. // If there isn't a unicode charmap then select the first one.
  254. if (FT_Select_Charmap (face, ft_encoding_unicode))
  255. FT_Set_Charmap (face, face->charmaps[0]);
  256. }
  257. }
  258. }
  259. return face;
  260. }
  261. void addGlyph (FT_Face face, Typeface& dest, uint32 character)
  262. {
  263. const unsigned int glyphIndex = FT_Get_Char_Index (face, character);
  264. const float height = (float) (face->ascender - face->descender);
  265. const float scaleX = 1.0f / height;
  266. const float scaleY = -1.0f / height;
  267. Path destShape;
  268. #define CONVERTX(val) (scaleX * (val).x)
  269. #define CONVERTY(val) (scaleY * (val).y)
  270. if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE
  271. | FT_LOAD_NO_BITMAP
  272. | FT_LOAD_IGNORE_TRANSFORM) != 0
  273. || face->glyph->format != ft_glyph_format_outline)
  274. {
  275. return;
  276. }
  277. const FT_Outline* const outline = &face->glyph->outline;
  278. const short* const contours = outline->contours;
  279. const char* const tags = outline->tags;
  280. FT_Vector* const points = outline->points;
  281. for (int c = 0; c < outline->n_contours; c++)
  282. {
  283. const int startPoint = (c == 0) ? 0 : contours [c - 1] + 1;
  284. const int endPoint = contours[c];
  285. for (int p = startPoint; p <= endPoint; p++)
  286. {
  287. const float x = CONVERTX (points[p]);
  288. const float y = CONVERTY (points[p]);
  289. if (p == startPoint)
  290. {
  291. destShape.startNewSubPath (x, y);
  292. }
  293. else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_On)
  294. {
  295. destShape.lineTo (x, y);
  296. }
  297. else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
  298. {
  299. const int nextIndex = (p == endPoint) ? startPoint : p + 1;
  300. float x2 = CONVERTX (points [nextIndex]);
  301. float y2 = CONVERTY (points [nextIndex]);
  302. if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic)
  303. {
  304. x2 = (x + x2) * 0.5f;
  305. y2 = (y + y2) * 0.5f;
  306. }
  307. else
  308. {
  309. ++p;
  310. }
  311. destShape.quadraticTo (x, y, x2, y2);
  312. }
  313. else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Cubic)
  314. {
  315. if (p > endPoint-1)
  316. return;
  317. const int next1 = p + 1;
  318. const int next2 = (p == (endPoint - 1)) ? startPoint : p + 2;
  319. float x2 = CONVERTX (points [next1]);
  320. float y2 = CONVERTY (points [next1]);
  321. float x3 = CONVERTX (points [next2]);
  322. float y3 = CONVERTY (points [next2]);
  323. if (FT_CURVE_TAG(tags[next1]) != FT_Curve_Tag_Cubic)
  324. return;
  325. if (FT_CURVE_TAG(tags[next2]) != FT_Curve_Tag_On)
  326. return;
  327. destShape.cubicTo (x, y, x2, y2, x3, y3);
  328. p += 2;
  329. }
  330. }
  331. destShape.closeSubPath();
  332. }
  333. dest.addGlyph (character, destShape, face->glyph->metrics.horiAdvance/height);
  334. if ((face->face_flags & FT_FACE_FLAG_KERNING) != 0)
  335. addKerning (face, dest, character, glyphIndex);
  336. }
  337. void addKerning (FT_Face face, Typeface& dest, const uint32 character, const uint32 glyphIndex)
  338. {
  339. const float height = (float) (face->ascender - face->descender);
  340. uint32 rightGlyphIndex;
  341. uint32 rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
  342. while (rightGlyphIndex != 0)
  343. {
  344. FT_Vector kerning;
  345. if (FT_Get_Kerning (face, glyphIndex, rightGlyphIndex, ft_kerning_unscaled, &kerning) == 0)
  346. {
  347. if (kerning.x != 0)
  348. dest.addKerningPair (character, rightCharCode, kerning.x / height);
  349. }
  350. rightCharCode = FT_Get_Next_Char (face, rightCharCode, &rightGlyphIndex);
  351. }
  352. }
  353. // Add a glyph to a font
  354. bool addGlyphToFont (const uint32 character,
  355. const tchar* fontName, bool bold, bool italic,
  356. Typeface& dest)
  357. {
  358. FT_Face face = createFT_Face (fontName, bold, italic);
  359. if (face != 0)
  360. {
  361. addGlyph (face, dest, character);
  362. return true;
  363. }
  364. return false;
  365. }
  366. // Create a Typeface object for given name/style
  367. bool createTypeface (const String& fontName,
  368. const bool bold, const bool italic,
  369. Typeface& dest,
  370. const bool addAllGlyphs)
  371. {
  372. dest.clear();
  373. dest.setName (fontName);
  374. dest.setBold (bold);
  375. dest.setItalic (italic);
  376. FT_Face face = createFT_Face (fontName, bold, italic);
  377. if (face == 0)
  378. {
  379. #ifdef JUCE_DEBUG
  380. String msg (T("Failed to create typeface: "));
  381. msg << fontName << " " << (bold ? 'B' : ' ') << (italic ? 'I' : ' ');
  382. DBG (msg);
  383. #endif
  384. return face;
  385. }
  386. const float height = (float) (face->ascender - face->descender);
  387. dest.setAscent (face->ascender / height);
  388. dest.setDefaultCharacter (L' ');
  389. if (addAllGlyphs)
  390. {
  391. uint32 glyphIndex;
  392. uint32 charCode = FT_Get_First_Char (face, &glyphIndex);
  393. while (glyphIndex != 0)
  394. {
  395. addGlyph (face, dest, charCode);
  396. charCode = FT_Get_Next_Char (face, charCode, &glyphIndex);
  397. }
  398. }
  399. return true;
  400. }
  401. //==============================================================================
  402. void getFamilyNames (StringArray& familyNames) const
  403. {
  404. for (int i = 0; i < faces.size(); i++)
  405. familyNames.add (faces[i]->getFamilyName());
  406. }
  407. void getMonospacedNames (StringArray& monoSpaced) const
  408. {
  409. for (int i = 0; i < faces.size(); i++)
  410. if (faces[i]->getMonospaced())
  411. monoSpaced.add (faces[i]->getFamilyName());
  412. }
  413. void getSerifNames (StringArray& serif) const
  414. {
  415. for (int i = 0; i < faces.size(); i++)
  416. if (faces[i]->getSerif())
  417. serif.add (faces[i]->getFamilyName());
  418. }
  419. void getSansSerifNames (StringArray& sansSerif) const
  420. {
  421. for (int i = 0; i < faces.size(); i++)
  422. if (! faces[i]->getSerif())
  423. sansSerif.add (faces[i]->getFamilyName());
  424. }
  425. juce_DeclareSingleton_SingleThreaded_Minimal (FreeTypeInterface)
  426. private:
  427. //==============================================================================
  428. FT_Library ftLib;
  429. FT_Face lastFace;
  430. String lastFontName;
  431. bool lastBold, lastItalic;
  432. OwnedArray<FreeTypeFontFace> faces;
  433. };
  434. juce_ImplementSingleton_SingleThreaded (FreeTypeInterface)
  435. //==============================================================================
  436. void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
  437. bool bold, bool italic,
  438. bool addAllGlyphsToFont) throw()
  439. {
  440. FreeTypeInterface::getInstance()
  441. ->createTypeface (fontName, bold, italic, *this, addAllGlyphsToFont);
  442. }
  443. void Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
  444. {
  445. FreeTypeInterface::getInstance()
  446. ->addGlyphToFont (character, getName(), isBold(), isItalic(), *this);
  447. }
  448. const StringArray Font::findAllTypefaceNames()
  449. {
  450. StringArray s;
  451. FreeTypeInterface::getInstance()->getFamilyNames (s);
  452. s.sort (true);
  453. return s;
  454. }
  455. static const String pickBestFont (const StringArray& names,
  456. const char* const choicesString)
  457. {
  458. StringArray choices;
  459. choices.addTokens (String (choicesString), T(","), 0);
  460. choices.trim();
  461. choices.removeEmptyStrings();
  462. int i, j;
  463. for (j = 0; j < choices.size(); ++j)
  464. if (names.contains (choices[j], true))
  465. return choices[j];
  466. for (j = 0; j < choices.size(); ++j)
  467. for (i = 0; i < names.size(); i++)
  468. if (names[i].startsWithIgnoreCase (choices[j]))
  469. return names[i];
  470. for (j = 0; j < choices.size(); ++j)
  471. for (i = 0; i < names.size(); i++)
  472. if (names[i].containsIgnoreCase (choices[j]))
  473. return names[i];
  474. return names[0];
  475. }
  476. static const String linux_getDefaultSansSerifFontName()
  477. {
  478. StringArray allFonts;
  479. FreeTypeInterface::getInstance()->getSansSerifNames (allFonts);
  480. return pickBestFont (allFonts, "Verdana, Bitstream Vera Sans, Luxi Sans, Sans");
  481. }
  482. static const String linux_getDefaultSerifFontName()
  483. {
  484. StringArray allFonts;
  485. FreeTypeInterface::getInstance()->getSerifNames (allFonts);
  486. return pickBestFont (allFonts, "Bitstream Vera Serif, Times, Nimbus Roman, Serif");
  487. }
  488. static const String linux_getDefaultMonospacedFontName()
  489. {
  490. StringArray allFonts;
  491. FreeTypeInterface::getInstance()->getMonospacedNames (allFonts);
  492. return pickBestFont (allFonts, "Bitstream Vera Sans Mono, Courier, Sans Mono, Mono");
  493. }
  494. void Font::getDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed)
  495. {
  496. defaultSans = linux_getDefaultSansSerifFontName();
  497. defaultSerif = linux_getDefaultSerifFontName();
  498. defaultFixed = linux_getDefaultMonospacedFontName();
  499. }
  500. END_JUCE_NAMESPACE
  501. #endif