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.

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