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.

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