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.

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