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.

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