Blindly add a few stuff from VST
[juce-lv2.git] / juce / source / src / native / linux / juce_linux_Fonts.cpp
blob440022c2365631c3b238353ddfa8769bfb57c079
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 // (This file gets included by juce_linux_NativeCode.cpp, rather than being
27 // compiled on its own).
28 #if JUCE_INCLUDED_FILE
31 //==============================================================================
32 class FreeTypeFontFace
34 public:
35 //==============================================================================
36 enum FontStyle
38 Plain = 0,
39 Bold = 1,
40 Italic = 2
43 //==============================================================================
44 FreeTypeFontFace (const String& familyName)
45 : hasSerif (false),
46 monospaced (false)
48 family = familyName;
51 void setFileName (const String& name, const int faceIndex, FontStyle style)
53 if (names [(int) style].fileName.isEmpty())
55 names [(int) style].fileName = name;
56 names [(int) style].faceIndex = faceIndex;
60 const String& getFamilyName() const noexcept { return family; }
62 const String& getFileName (const int style, int& faceIndex) const noexcept
64 faceIndex = names[style].faceIndex;
65 return names[style].fileName;
68 void setMonospaced (bool mono) noexcept { monospaced = mono; }
69 bool getMonospaced() const noexcept { return monospaced; }
71 void setSerif (const bool serif) noexcept { hasSerif = serif; }
72 bool getSerif() const noexcept { return hasSerif; }
74 private:
75 //==============================================================================
76 String family;
78 struct FontNameIndex
80 String fileName;
81 int faceIndex;
84 FontNameIndex names[4];
85 bool hasSerif, monospaced;
88 //==============================================================================
89 class LinuxFontFileIterator
91 public:
92 LinuxFontFileIterator()
93 : index (0)
95 fontDirs.addTokens (CharPointer_UTF8 (getenv ("JUCE_FONT_PATH")), ";,", String::empty);
96 fontDirs.removeEmptyStrings (true);
98 if (fontDirs.size() == 0)
100 const ScopedPointer<XmlElement> fontsInfo (XmlDocument::parse (File ("/etc/fonts/fonts.conf")));
102 if (fontsInfo != nullptr)
104 forEachXmlChildElementWithTagName (*fontsInfo, e, "dir")
106 fontDirs.add (e->getAllSubText().trim());
111 if (fontDirs.size() == 0)
112 fontDirs.add ("/usr/X11R6/lib/X11/fonts");
114 fontDirs.removeEmptyStrings (true);
117 bool next()
119 if (iter != nullptr)
121 while (iter->next())
122 if (getFile().hasFileExtension ("ttf;pfb;pcf"))
123 return true;
126 if (index >= fontDirs.size())
127 return false;
129 iter = new DirectoryIterator (fontDirs [index++], true);
130 return next();
133 File getFile() const { jassert (iter != nullptr); return iter->getFile(); }
135 private:
136 StringArray fontDirs;
137 int index;
138 ScopedPointer<DirectoryIterator> iter;
142 //==============================================================================
143 class FreeTypeInterface : public DeletedAtShutdown
145 public:
146 //==============================================================================
147 FreeTypeInterface()
148 : ftLib (0),
149 lastFace (0),
150 lastBold (false),
151 lastItalic (false)
153 if (FT_Init_FreeType (&ftLib) != 0)
155 ftLib = 0;
156 DBG ("Failed to initialize FreeType");
159 LinuxFontFileIterator fontFileIterator;
161 while (fontFileIterator.next())
163 FT_Face face;
164 int faceIndex = 0;
165 int numFaces = 0;
169 if (FT_New_Face (ftLib, fontFileIterator.getFile().getFullPathName().toUTF8(),
170 faceIndex, &face) == 0)
172 if (faceIndex == 0)
173 numFaces = face->num_faces;
175 if ((face->face_flags & FT_FACE_FLAG_SCALABLE) != 0)
177 FreeTypeFontFace* const newFace = findOrCreate (face->family_name, true);
178 int style = (int) FreeTypeFontFace::Plain;
180 if ((face->style_flags & FT_STYLE_FLAG_BOLD) != 0)
181 style |= (int) FreeTypeFontFace::Bold;
183 if ((face->style_flags & FT_STYLE_FLAG_ITALIC) != 0)
184 style |= (int) FreeTypeFontFace::Italic;
186 newFace->setFileName (fontFileIterator.getFile().getFullPathName(),
187 faceIndex, (FreeTypeFontFace::FontStyle) style);
188 newFace->setMonospaced ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0);
190 // Surely there must be a better way to do this?
191 const String name (face->family_name);
192 newFace->setSerif (! (name.containsIgnoreCase ("Sans")
193 || name.containsIgnoreCase ("Verdana")
194 || name.containsIgnoreCase ("Arial")));
196 //DBG (fontFileIterator.getFile().getFullPathName() << " - " << name);
199 FT_Done_Face (face);
202 ++faceIndex;
204 while (faceIndex < numFaces);
208 ~FreeTypeInterface()
210 if (lastFace != 0)
211 FT_Done_Face (lastFace);
213 if (ftLib != 0)
214 FT_Done_FreeType (ftLib);
216 clearSingletonInstance();
219 //==============================================================================
220 FreeTypeFontFace* findOrCreate (const String& familyName, const bool create = false)
222 for (int i = 0; i < faces.size(); i++)
223 if (faces[i]->getFamilyName() == familyName)
224 return faces[i];
226 if (! create)
227 return nullptr;
229 FreeTypeFontFace* newFace = new FreeTypeFontFace (familyName);
230 faces.add (newFace);
232 return newFace;
235 // Create a FreeType face object for a given font
236 FT_Face createFT_Face (const String& fontName, const bool bold, const bool italic)
238 FT_Face face = 0;
240 if (fontName == lastFontName && bold == lastBold && italic == lastItalic)
242 face = lastFace;
244 else
246 if (lastFace != 0)
248 FT_Done_Face (lastFace);
249 lastFace = 0;
252 lastFontName = fontName;
253 lastBold = bold;
254 lastItalic = italic;
256 FreeTypeFontFace* const ftFace = findOrCreate (fontName);
258 if (ftFace != 0)
260 int style = (int) FreeTypeFontFace::Plain;
262 if (bold)
263 style |= (int) FreeTypeFontFace::Bold;
265 if (italic)
266 style |= (int) FreeTypeFontFace::Italic;
268 int faceIndex;
269 String fileName (ftFace->getFileName (style, faceIndex));
271 if (fileName.isEmpty())
273 style ^= (int) FreeTypeFontFace::Bold;
275 fileName = ftFace->getFileName (style, faceIndex);
277 if (fileName.isEmpty())
279 style ^= (int) FreeTypeFontFace::Bold;
280 style ^= (int) FreeTypeFontFace::Italic;
282 fileName = ftFace->getFileName (style, faceIndex);
284 if (! fileName.length())
286 style ^= (int) FreeTypeFontFace::Bold;
287 fileName = ftFace->getFileName (style, faceIndex);
292 if (! FT_New_Face (ftLib, fileName.toUTF8(), faceIndex, &lastFace))
294 face = lastFace;
296 // If there isn't a unicode charmap then select the first one.
297 if (FT_Select_Charmap (face, ft_encoding_unicode))
298 FT_Set_Charmap (face, face->charmaps[0]);
303 return face;
306 bool addGlyph (FT_Face face, CustomTypeface& dest, uint32 character)
308 const unsigned int glyphIndex = FT_Get_Char_Index (face, character);
309 const float height = (float) (face->ascender - face->descender);
310 const float scaleX = 1.0f / height;
311 const float scaleY = -1.0f / height;
312 Path destShape;
314 if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM) != 0
315 || face->glyph->format != ft_glyph_format_outline)
317 return false;
320 const FT_Outline* const outline = &face->glyph->outline;
321 const short* const contours = outline->contours;
322 const char* const tags = outline->tags;
323 FT_Vector* const points = outline->points;
325 for (int c = 0; c < outline->n_contours; c++)
327 const int startPoint = (c == 0) ? 0 : contours [c - 1] + 1;
328 const int endPoint = contours[c];
330 for (int p = startPoint; p <= endPoint; p++)
332 const float x = scaleX * points[p].x;
333 const float y = scaleY * points[p].y;
335 if (p == startPoint)
337 if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
339 float x2 = scaleX * points [endPoint].x;
340 float y2 = scaleY * points [endPoint].y;
342 if (FT_CURVE_TAG (tags[endPoint]) != FT_Curve_Tag_On)
344 x2 = (x + x2) * 0.5f;
345 y2 = (y + y2) * 0.5f;
348 destShape.startNewSubPath (x2, y2);
350 else
352 destShape.startNewSubPath (x, y);
356 if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_On)
358 if (p != startPoint)
359 destShape.lineTo (x, y);
361 else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
363 const int nextIndex = (p == endPoint) ? startPoint : p + 1;
364 float x2 = scaleX * points [nextIndex].x;
365 float y2 = scaleY * points [nextIndex].y;
367 if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic)
369 x2 = (x + x2) * 0.5f;
370 y2 = (y + y2) * 0.5f;
372 else
374 ++p;
377 destShape.quadraticTo (x, y, x2, y2);
379 else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Cubic)
381 if (p >= endPoint)
382 return false;
384 const int next1 = p + 1;
385 const int next2 = (p == (endPoint - 1)) ? startPoint : p + 2;
387 const float x2 = scaleX * points [next1].x;
388 const float y2 = scaleY * points [next1].y;
389 const float x3 = scaleX * points [next2].x;
390 const float y3 = scaleY * points [next2].y;
392 if (FT_CURVE_TAG (tags[next1]) != FT_Curve_Tag_Cubic
393 || FT_CURVE_TAG (tags[next2]) != FT_Curve_Tag_On)
394 return false;
396 destShape.cubicTo (x, y, x2, y2, x3, y3);
397 p += 2;
401 destShape.closeSubPath();
404 dest.addGlyph (character, destShape, face->glyph->metrics.horiAdvance / height);
406 if ((face->face_flags & FT_FACE_FLAG_KERNING) != 0)
407 addKerning (face, dest, character, glyphIndex);
409 return true;
412 void addKerning (FT_Face face, CustomTypeface& dest, const uint32 character, const uint32 glyphIndex)
414 const float height = (float) (face->ascender - face->descender);
416 uint32 rightGlyphIndex;
417 uint32 rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
419 while (rightGlyphIndex != 0)
421 FT_Vector kerning;
423 if (FT_Get_Kerning (face, glyphIndex, rightGlyphIndex, ft_kerning_unscaled, &kerning) == 0)
425 if (kerning.x != 0)
426 dest.addKerningPair (character, rightCharCode, kerning.x / height);
429 rightCharCode = FT_Get_Next_Char (face, rightCharCode, &rightGlyphIndex);
433 // Add a glyph to a font
434 bool addGlyphToFont (const uint32 character, const String& fontName,
435 bool bold, bool italic, CustomTypeface& dest)
437 FT_Face face = createFT_Face (fontName, bold, italic);
439 return face != 0 && addGlyph (face, dest, character);
442 //==============================================================================
443 void getFamilyNames (StringArray& familyNames) const
445 for (int i = 0; i < faces.size(); i++)
446 familyNames.add (faces[i]->getFamilyName());
449 void getMonospacedNames (StringArray& monoSpaced) const
451 for (int i = 0; i < faces.size(); i++)
452 if (faces[i]->getMonospaced())
453 monoSpaced.add (faces[i]->getFamilyName());
456 void getSerifNames (StringArray& serif) const
458 for (int i = 0; i < faces.size(); i++)
459 if (faces[i]->getSerif())
460 serif.add (faces[i]->getFamilyName());
463 void getSansSerifNames (StringArray& sansSerif) const
465 for (int i = 0; i < faces.size(); i++)
466 if (! faces[i]->getSerif())
467 sansSerif.add (faces[i]->getFamilyName());
470 juce_DeclareSingleton_SingleThreaded_Minimal (FreeTypeInterface);
472 private:
473 //==============================================================================
474 FT_Library ftLib;
475 FT_Face lastFace;
476 String lastFontName;
477 bool lastBold, lastItalic;
478 OwnedArray<FreeTypeFontFace> faces;
481 juce_ImplementSingleton_SingleThreaded (FreeTypeInterface)
484 //==============================================================================
485 class FreetypeTypeface : public CustomTypeface
487 public:
488 FreetypeTypeface (const Font& font)
490 FT_Face face = FreeTypeInterface::getInstance()
491 ->createFT_Face (font.getTypefaceName(), font.isBold(), font.isItalic());
493 if (face == 0)
495 #if JUCE_DEBUG
496 String msg ("Failed to create typeface: ");
497 msg << font.getTypefaceName() << " " << (font.isBold() ? 'B' : ' ') << (font.isItalic() ? 'I' : ' ');
498 DBG (msg);
499 #endif
501 else
503 setCharacteristics (font.getTypefaceName(),
504 face->ascender / (float) (face->ascender - face->descender),
505 font.isBold(), font.isItalic(),
506 L' ');
510 bool loadGlyphIfPossible (juce_wchar character)
512 return FreeTypeInterface::getInstance()
513 ->addGlyphToFont (character, name, isBold, isItalic, *this);
517 Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
519 return new FreetypeTypeface (font);
522 //==============================================================================
523 StringArray Font::findAllTypefaceNames()
525 StringArray s;
526 FreeTypeInterface::getInstance()->getFamilyNames (s);
527 s.sort (true);
528 return s;
531 namespace LinuxFontHelpers
533 String pickBestFont (const StringArray& names,
534 const char* const* choicesString)
536 const StringArray choices (choicesString);
538 int i, j;
539 for (j = 0; j < choices.size(); ++j)
540 if (names.contains (choices[j], true))
541 return choices[j];
543 for (j = 0; j < choices.size(); ++j)
544 for (i = 0; i < names.size(); i++)
545 if (names[i].startsWithIgnoreCase (choices[j]))
546 return names[i];
548 for (j = 0; j < choices.size(); ++j)
549 for (i = 0; i < names.size(); i++)
550 if (names[i].containsIgnoreCase (choices[j]))
551 return names[i];
553 return names[0];
556 String getDefaultSansSerifFontName()
558 StringArray allFonts;
559 FreeTypeInterface::getInstance()->getSansSerifNames (allFonts);
561 const char* targets[] = { "Verdana", "Bitstream Vera Sans", "Luxi Sans", "Sans", 0 };
562 return pickBestFont (allFonts, targets);
565 String getDefaultSerifFontName()
567 StringArray allFonts;
568 FreeTypeInterface::getInstance()->getSerifNames (allFonts);
570 const char* targets[] = { "Bitstream Vera Serif", "Times", "Nimbus Roman", "Serif", 0 };
571 return pickBestFont (allFonts, targets);
574 String getDefaultMonospacedFontName()
576 StringArray allFonts;
577 FreeTypeInterface::getInstance()->getMonospacedNames (allFonts);
579 const char* targets[] = { "Bitstream Vera Sans Mono", "Courier", "Sans Mono", "Mono", 0 };
580 return pickBestFont (allFonts, targets);
584 void Font::getPlatformDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed, String& /*defaultFallback*/)
586 defaultSans = LinuxFontHelpers::getDefaultSansSerifFontName();
587 defaultSerif = LinuxFontHelpers::getDefaultSerifFontName();
588 defaultFixed = LinuxFontHelpers::getDefaultMonospacedFontName();
591 #endif