92 scanFontPaths (getDefaultFontDirectories());
97 clearSingletonInstance();
105 family (face.face->family_name),
106 style (face.face->style_name),
108 isMonospaced ((face.face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0),
109 isSansSerif (isFaceSansSerif (family))
114 const String family, style;
116 const bool isMonospaced, isSansSerif;
125 if (FT_Select_Charmap (face->face, ft_encoding_unicode) != 0)
126 FT_Set_Charmap (face->face, face->face->charmaps[0]);
133 return selectUnicodeCharmap (
new FTFaceWrapper (library, data, dataSize, index));
136 FTFaceWrapper::Ptr createFace (
const File& file,
int index)
138 return selectUnicodeCharmap (
new FTFaceWrapper (library, file, index));
141 FTFaceWrapper::Ptr createFace (
const String& fontName,
const String& fontStyle)
143 auto ftFace = matchTypeface (fontName, fontStyle);
145 if (ftFace ==
nullptr) ftFace = matchTypeface (fontName,
"Regular");
146 if (ftFace ==
nullptr) ftFace = matchTypeface (fontName, {});
148 if (ftFace !=
nullptr)
149 return createFace (ftFace->file, ftFace->faceIndex);
155 StringArray findAllFamilyNames()
const
159 for (
auto* face : faces)
160 set.insert (face->family);
164 for (
const auto& family : set)
170 StringArray findAllTypefaceStyles (
const String& family)
const
174 for (
auto* face : faces)
175 if (face->family == family)
176 s.addIfNotAlreadyThere (face->style);
182 void scanFontPaths (
const StringArray& paths)
184 for (
auto& path : paths)
186 for (
const auto& iter : RangedDirectoryIterator (File::getCurrentWorkingDirectory().getChildFile (path), true))
188 if (iter.getFile().hasFileExtension (
"ttf;pfb;pcf;otf"))
189 scanFont (iter.getFile());
193 std::sort (faces.begin(), faces.end(), [] (
const auto* a,
const auto* b)
195 const auto tie = [] (const KnownTypeface& t)
198 const auto computeStyleNormalcy = [] (const String& style)
200 if (style ==
"Regular")
203 if (style ==
"Roman")
209 if (style.containsIgnoreCase (
"Bold"))
212 if (style.containsIgnoreCase (
"Italic"))
218 return std::make_tuple (t.family,
219 computeStyleNormalcy (t.style),
227 return tie (*a) <
tie (*b);
231 void getMonospacedNames (StringArray& monoSpaced)
const
233 for (
auto* face : faces)
234 if (face->isMonospaced)
235 monoSpaced.addIfNotAlreadyThere (face->family);
238 void getSerifNames (StringArray& serif)
const
240 for (
auto* face : faces)
241 if (! (face->isSansSerif || face->isMonospaced))
242 serif.addIfNotAlreadyThere (face->family);
245 void getSansSerifNames (StringArray& sansSerif)
const
247 for (
auto* face : faces)
248 if (face->isSansSerif)
249 sansSerif.addIfNotAlreadyThere (face->family);
255 FTLibWrapper::Ptr library;
256 OwnedArray<KnownTypeface> faces;
258 static StringArray getDefaultFontDirectories();
260 void scanFont (
const File& file)
267 FTFaceWrapper face (library, file, faceIndex);
269 if (face.face !=
nullptr)
272 numFaces = (
int) face.face->num_faces;
274 if ((face.face->face_flags & FT_FACE_FLAG_SCALABLE) != 0)
275 faces.add (
new KnownTypeface (file, faceIndex, face));
280 while (faceIndex < numFaces);
283 const KnownTypeface* matchTypeface (
const String& familyName,
const String& style)
const noexcept
285 for (
auto* face : faces)
286 if (face->family == familyName
287 && (face->style.equalsIgnoreCase (style) || style.isEmpty()))
293 static bool isFaceSansSerif (
const String& family)
295 static const char* sansNames[] = {
"Sans",
"Verdana",
"Arial",
"Ubuntu" };
297 for (
auto* name : sansNames)
298 if (family.containsIgnoreCase (name))
315 : faceWrapper (FTTypefaceList::getInstance()->createFace (font.
getTypefaceName(),
318 if (faceWrapper !=
nullptr)
324 : faceWrapper (FTTypefaceList::getInstance()->createFace (data, dataSize, 0))
326 if (faceWrapper !=
nullptr)
327 initialiseCharacteristics (faceWrapper->face->family_name,
328 faceWrapper->face->style_name);
331 void initialiseCharacteristics (
const String& fontName,
const String& fontStyle)
333 setCharacteristics (fontName, fontStyle,
334 faceWrapper->face->ascender / (
float) (faceWrapper->face->ascender - faceWrapper->face->descender),
340 if (faceWrapper !=
nullptr)
342 auto face = faceWrapper->face;
343 auto glyphIndex = FT_Get_Char_Index (face, (FT_ULong) character);
345 if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING) == 0
346 && face->glyph->format == ft_glyph_format_outline)
348 auto scale = 1.0f / (
float) (face->ascender - face->descender);
351 if (getGlyphShape (destShape, face->glyph->outline, scale))
353 addGlyph (character, destShape, (
float) face->glyph->metrics.horiAdvance * scale);
355 if ((face->face_flags & FT_FACE_FLAG_KERNING) != 0)
356 addKerning (face, (
uint32) character, glyphIndex);
369 bool getGlyphShape (
Path& destShape,
const FT_Outline& outline,
float scaleX)
371 auto scaleY = -scaleX;
372 auto* contours = outline.contours;
373 auto* tags = outline.tags;
374 auto* points = outline.points;
376 for (
int c = 0; c < outline.n_contours; ++c)
378 const int startPoint = (c == 0) ? 0 : contours [c - 1] + 1;
379 const int endPoint = contours[c];
381 for (
int p = startPoint; p <= endPoint; ++p)
383 auto x = scaleX * (
float) points[p].x;
384 auto y = scaleY * (
float) points[p].y;
388 if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
390 auto x2 = scaleX * (
float) points[endPoint].x;
391 auto y2 = scaleY * (
float) points[endPoint].y;
393 if (FT_CURVE_TAG (tags[endPoint]) != FT_Curve_Tag_On)
395 x2 = (x + x2) * 0.5f;
396 y2 = (y + y2) * 0.5f;
407 if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_On)
412 else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
414 const int nextIndex = (p == endPoint) ? startPoint : p + 1;
415 auto x2 = scaleX * (
float) points[nextIndex].x;
416 auto y2 = scaleY * (
float) points[nextIndex].y;
418 if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic)
420 x2 = (x + x2) * 0.5f;
421 y2 = (y + y2) * 0.5f;
430 else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Cubic)
432 const int next1 = p + 1;
433 const int next2 = (p == (endPoint - 1)) ? startPoint : (p + 2);
436 || FT_CURVE_TAG (tags[next1]) != FT_Curve_Tag_Cubic
437 || FT_CURVE_TAG (tags[next2]) != FT_Curve_Tag_On)
440 auto x2 = scaleX * (
float) points[next1].x;
441 auto y2 = scaleY * (
float) points[next1].y;
442 auto x3 = scaleX * (
float) points[next2].x;
443 auto y3 = scaleY * (
float) points[next2].y;
445 destShape.
cubicTo (x, y, x2, y2, x3, y3);
456 void addKerning (FT_Face face,
const uint32 character,
const uint32 glyphIndex)
458 auto height = (
float) (face->ascender - face->descender);
460 uint32 rightGlyphIndex;
461 auto rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
463 while (rightGlyphIndex != 0)
467 if (FT_Get_Kerning (face, glyphIndex, rightGlyphIndex, ft_kerning_unscaled, &kerning) == 0
469 addKerningPair ((juce_wchar) character, (juce_wchar) rightCharCode, (
float) kerning.x / height);
471 rightCharCode = FT_Get_Next_Char (face, rightCharCode, &rightGlyphIndex);
void cubicTo(float controlPoint1X, float controlPoint1Y, float controlPoint2X, float controlPoint2Y, float endPointX, float endPointY)
Adds a cubic bezier curve from the shape's last position to a new position.