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.

574 lines
19KB

  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. String fontPath (e->getAllSubText().trim());
  73. if (fontPath.isNotEmpty())
  74. {
  75. if (e->getStringAttribute ("prefix") == "xdg")
  76. {
  77. String xdgDataHome (SystemStats::getEnvironmentVariable ("XDG_DATA_HOME", String::empty));
  78. if (xdgDataHome.trimStart().isEmpty())
  79. xdgDataHome = "~/.local/share";
  80. fontPath = File (xdgDataHome).getChildFile (fontPath).getFullPathName();
  81. }
  82. fontDirs.add (fontPath);
  83. }
  84. }
  85. }
  86. }
  87. if (fontDirs.size() == 0)
  88. fontDirs.add ("/usr/X11R6/lib/X11/fonts");
  89. fontDirs.removeDuplicates (false);
  90. }
  91. bool next()
  92. {
  93. if (iter != nullptr)
  94. {
  95. while (iter->next())
  96. if (getFile().hasFileExtension ("ttf;pfb;pcf"))
  97. return true;
  98. }
  99. if (index >= fontDirs.size())
  100. return false;
  101. iter = new DirectoryIterator (File::getCurrentWorkingDirectory()
  102. .getChildFile (fontDirs [index++]), true);
  103. return next();
  104. }
  105. File getFile() const { jassert (iter != nullptr); return iter->getFile(); }
  106. private:
  107. StringArray fontDirs;
  108. int index;
  109. ScopedPointer<DirectoryIterator> iter;
  110. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LinuxFontFileIterator)
  111. };
  112. //==============================================================================
  113. class FTTypefaceList : private DeletedAtShutdown
  114. {
  115. public:
  116. FTTypefaceList()
  117. : library (new FTLibWrapper())
  118. {
  119. LinuxFontFileIterator fontFileIterator;
  120. while (fontFileIterator.next())
  121. {
  122. int faceIndex = 0;
  123. int numFaces = 0;
  124. do
  125. {
  126. FTFaceWrapper face (library, fontFileIterator.getFile(), faceIndex);
  127. if (face.face != 0)
  128. {
  129. if (faceIndex == 0)
  130. numFaces = face.face->num_faces;
  131. if ((face.face->face_flags & FT_FACE_FLAG_SCALABLE) != 0)
  132. faces.add (new KnownTypeface (fontFileIterator.getFile(), faceIndex, face));
  133. }
  134. ++faceIndex;
  135. }
  136. while (faceIndex < numFaces);
  137. }
  138. }
  139. ~FTTypefaceList()
  140. {
  141. clearSingletonInstance();
  142. }
  143. //==============================================================================
  144. struct KnownTypeface
  145. {
  146. KnownTypeface (const File& f, const int index, const FTFaceWrapper& face)
  147. : file (f),
  148. family (face.face->family_name),
  149. style (face.face->style_name),
  150. faceIndex (index),
  151. isMonospaced ((face.face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0),
  152. isSansSerif (isFaceSansSerif (family))
  153. {
  154. }
  155. const File file;
  156. const String family, style;
  157. const int faceIndex;
  158. const bool isMonospaced, isSansSerif;
  159. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownTypeface)
  160. };
  161. //==============================================================================
  162. FTFaceWrapper::Ptr createFace (const String& fontName, const String& fontStyle)
  163. {
  164. const KnownTypeface* ftFace = matchTypeface (fontName, fontStyle);
  165. if (ftFace == nullptr) ftFace = matchTypeface (fontName, "Regular");
  166. if (ftFace == nullptr) ftFace = matchTypeface (fontName, String::empty);
  167. if (ftFace != nullptr)
  168. {
  169. if (FTFaceWrapper::Ptr face = new FTFaceWrapper (library, ftFace->file, ftFace->faceIndex))
  170. {
  171. // If there isn't a unicode charmap then select the first one.
  172. if (FT_Select_Charmap (face->face, ft_encoding_unicode) != 0)
  173. FT_Set_Charmap (face->face, face->face->charmaps[0]);
  174. return face;
  175. }
  176. }
  177. return nullptr;
  178. }
  179. //==============================================================================
  180. StringArray findAllFamilyNames() const
  181. {
  182. StringArray s;
  183. for (int i = 0; i < faces.size(); i++)
  184. s.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
  185. return s;
  186. }
  187. StringArray findAllTypefaceStyles (const String& family) const
  188. {
  189. StringArray s;
  190. for (int i = 0; i < faces.size(); i++)
  191. {
  192. const KnownTypeface* const face = faces.getUnchecked(i);
  193. if (face->family == family)
  194. s.addIfNotAlreadyThere (face->style);
  195. }
  196. return s;
  197. }
  198. void getMonospacedNames (StringArray& monoSpaced) const
  199. {
  200. for (int i = 0; i < faces.size(); i++)
  201. if (faces.getUnchecked(i)->isMonospaced)
  202. monoSpaced.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
  203. }
  204. void getSerifNames (StringArray& serif) const
  205. {
  206. for (int i = 0; i < faces.size(); i++)
  207. if (! faces.getUnchecked(i)->isSansSerif)
  208. serif.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
  209. }
  210. void getSansSerifNames (StringArray& sansSerif) const
  211. {
  212. for (int i = 0; i < faces.size(); i++)
  213. if (faces.getUnchecked(i)->isSansSerif)
  214. sansSerif.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
  215. }
  216. juce_DeclareSingleton_SingleThreaded_Minimal (FTTypefaceList);
  217. private:
  218. FTLibWrapper::Ptr library;
  219. OwnedArray<KnownTypeface> faces;
  220. const KnownTypeface* matchTypeface (const String& familyName, const String& style) const noexcept
  221. {
  222. for (int i = 0; i < faces.size(); ++i)
  223. {
  224. const KnownTypeface* const face = faces.getUnchecked(i);
  225. if (face->family == familyName
  226. && (face->style.equalsIgnoreCase (style) || style.isEmpty()))
  227. return face;
  228. }
  229. return nullptr;
  230. }
  231. static bool isFaceSansSerif (const String& family)
  232. {
  233. const char* sansNames[] = { "Sans", "Verdana", "Arial", "Ubuntu" };
  234. for (int i = 0; i < numElementsInArray (sansNames); ++i)
  235. if (family.containsIgnoreCase (sansNames[i]))
  236. return true;
  237. return false;
  238. }
  239. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTTypefaceList)
  240. };
  241. juce_ImplementSingleton_SingleThreaded (FTTypefaceList)
  242. //==============================================================================
  243. class FreeTypeTypeface : public CustomTypeface
  244. {
  245. public:
  246. FreeTypeTypeface (const Font& font)
  247. : faceWrapper (FTTypefaceList::getInstance()
  248. ->createFace (font.getTypefaceName(), font.getTypefaceStyle()))
  249. {
  250. if (faceWrapper != nullptr)
  251. {
  252. setCharacteristics (font.getTypefaceName(),
  253. font.getTypefaceStyle(),
  254. faceWrapper->face->ascender / (float) (faceWrapper->face->ascender - faceWrapper->face->descender),
  255. L' ');
  256. }
  257. else
  258. {
  259. DBG ("Failed to create typeface: " << font.toString());
  260. }
  261. }
  262. bool loadGlyphIfPossible (const juce_wchar character)
  263. {
  264. if (faceWrapper != nullptr)
  265. {
  266. FT_Face face = faceWrapper->face;
  267. const unsigned int glyphIndex = FT_Get_Char_Index (face, character);
  268. if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM) == 0
  269. && face->glyph->format == ft_glyph_format_outline)
  270. {
  271. const float scale = 1.0f / (float) (face->ascender - face->descender);
  272. Path destShape;
  273. if (getGlyphShape (destShape, face->glyph->outline, scale))
  274. {
  275. addGlyph (character, destShape, face->glyph->metrics.horiAdvance * scale);
  276. if ((face->face_flags & FT_FACE_FLAG_KERNING) != 0)
  277. addKerning (face, character, glyphIndex);
  278. return true;
  279. }
  280. }
  281. }
  282. return false;
  283. }
  284. private:
  285. FTFaceWrapper::Ptr faceWrapper;
  286. bool getGlyphShape (Path& destShape, const FT_Outline& outline, const float scaleX)
  287. {
  288. const float scaleY = -scaleX;
  289. const short* const contours = outline.contours;
  290. const char* const tags = outline.tags;
  291. const FT_Vector* const points = outline.points;
  292. for (int c = 0; c < outline.n_contours; ++c)
  293. {
  294. const int startPoint = (c == 0) ? 0 : contours [c - 1] + 1;
  295. const int endPoint = contours[c];
  296. for (int p = startPoint; p <= endPoint; ++p)
  297. {
  298. const float x = scaleX * points[p].x;
  299. const float y = scaleY * points[p].y;
  300. if (p == startPoint)
  301. {
  302. if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
  303. {
  304. float x2 = scaleX * points [endPoint].x;
  305. float y2 = scaleY * points [endPoint].y;
  306. if (FT_CURVE_TAG (tags[endPoint]) != FT_Curve_Tag_On)
  307. {
  308. x2 = (x + x2) * 0.5f;
  309. y2 = (y + y2) * 0.5f;
  310. }
  311. destShape.startNewSubPath (x2, y2);
  312. }
  313. else
  314. {
  315. destShape.startNewSubPath (x, y);
  316. }
  317. }
  318. if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_On)
  319. {
  320. if (p != startPoint)
  321. destShape.lineTo (x, y);
  322. }
  323. else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
  324. {
  325. const int nextIndex = (p == endPoint) ? startPoint : p + 1;
  326. float x2 = scaleX * points [nextIndex].x;
  327. float y2 = scaleY * points [nextIndex].y;
  328. if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic)
  329. {
  330. x2 = (x + x2) * 0.5f;
  331. y2 = (y + y2) * 0.5f;
  332. }
  333. else
  334. {
  335. ++p;
  336. }
  337. destShape.quadraticTo (x, y, x2, y2);
  338. }
  339. else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Cubic)
  340. {
  341. const int next1 = p + 1;
  342. const int next2 = (p == (endPoint - 1)) ? startPoint : (p + 2);
  343. if (p >= endPoint
  344. || FT_CURVE_TAG (tags[next1]) != FT_Curve_Tag_Cubic
  345. || FT_CURVE_TAG (tags[next2]) != FT_Curve_Tag_On)
  346. return false;
  347. const float x2 = scaleX * points [next1].x;
  348. const float y2 = scaleY * points [next1].y;
  349. const float x3 = scaleX * points [next2].x;
  350. const float y3 = scaleY * points [next2].y;
  351. destShape.cubicTo (x, y, x2, y2, x3, y3);
  352. p += 2;
  353. }
  354. }
  355. destShape.closeSubPath();
  356. }
  357. return true;
  358. }
  359. void addKerning (FT_Face face, const uint32 character, const uint32 glyphIndex)
  360. {
  361. const float height = (float) (face->ascender - face->descender);
  362. uint32 rightGlyphIndex;
  363. uint32 rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
  364. while (rightGlyphIndex != 0)
  365. {
  366. FT_Vector kerning;
  367. if (FT_Get_Kerning (face, glyphIndex, rightGlyphIndex, ft_kerning_unscaled, &kerning) == 0
  368. && kerning.x != 0)
  369. addKerningPair (character, rightCharCode, kerning.x / height);
  370. rightCharCode = FT_Get_Next_Char (face, rightCharCode, &rightGlyphIndex);
  371. }
  372. }
  373. JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface)
  374. };
  375. //==============================================================================
  376. Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
  377. {
  378. return new FreeTypeTypeface (font);
  379. }
  380. StringArray Font::findAllTypefaceNames()
  381. {
  382. return FTTypefaceList::getInstance()->findAllFamilyNames();
  383. }
  384. StringArray Font::findAllTypefaceStyles (const String& family)
  385. {
  386. return FTTypefaceList::getInstance()->findAllTypefaceStyles (family);
  387. }
  388. //==============================================================================
  389. struct DefaultFontNames
  390. {
  391. DefaultFontNames()
  392. : defaultSans (getDefaultSansSerifFontName()),
  393. defaultSerif (getDefaultSerifFontName()),
  394. defaultFixed (getDefaultMonospacedFontName())
  395. {
  396. }
  397. String defaultSans, defaultSerif, defaultFixed;
  398. private:
  399. static String pickBestFont (const StringArray& names, const char* const* choicesArray)
  400. {
  401. const StringArray choices (choicesArray);
  402. for (int j = 0; j < choices.size(); ++j)
  403. if (names.contains (choices[j], true))
  404. return choices[j];
  405. for (int j = 0; j < choices.size(); ++j)
  406. for (int i = 0; i < names.size(); ++i)
  407. if (names[i].startsWithIgnoreCase (choices[j]))
  408. return names[i];
  409. for (int j = 0; j < choices.size(); ++j)
  410. for (int i = 0; i < names.size(); ++i)
  411. if (names[i].containsIgnoreCase (choices[j]))
  412. return names[i];
  413. return names[0];
  414. }
  415. static String getDefaultSansSerifFontName()
  416. {
  417. StringArray allFonts;
  418. FTTypefaceList::getInstance()->getSansSerifNames (allFonts);
  419. const char* targets[] = { "Verdana", "Bitstream Vera Sans", "Luxi Sans",
  420. "Liberation Sans", "DejaVu Sans", "Sans", 0 };
  421. return pickBestFont (allFonts, targets);
  422. }
  423. static String getDefaultSerifFontName()
  424. {
  425. StringArray allFonts;
  426. FTTypefaceList::getInstance()->getSerifNames (allFonts);
  427. const char* targets[] = { "Bitstream Vera Serif", "Times", "Nimbus Roman",
  428. "Liberation Serif", "DejaVu Serif", "Serif", 0 };
  429. return pickBestFont (allFonts, targets);
  430. }
  431. static String getDefaultMonospacedFontName()
  432. {
  433. StringArray allFonts;
  434. FTTypefaceList::getInstance()->getMonospacedNames (allFonts);
  435. const char* targets[] = { "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Sans Mono",
  436. "Liberation Mono", "Courier", "DejaVu Mono", "Mono", 0 };
  437. return pickBestFont (allFonts, targets);
  438. }
  439. JUCE_DECLARE_NON_COPYABLE (DefaultFontNames)
  440. };
  441. Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
  442. {
  443. static DefaultFontNames defaultNames;
  444. String faceName (font.getTypefaceName());
  445. if (faceName == getDefaultSansSerifFontName()) faceName = defaultNames.defaultSans;
  446. else if (faceName == getDefaultSerifFontName()) faceName = defaultNames.defaultSerif;
  447. else if (faceName == getDefaultMonospacedFontName()) faceName = defaultNames.defaultFixed;
  448. Font f (font);
  449. f.setTypefaceName (faceName);
  450. return Typeface::createSystemTypefaceFor (f);
  451. }
  452. bool TextLayout::createNativeLayout (const AttributedString&)
  453. {
  454. return false;
  455. }