Audio plugin host https://kx.studio/carla
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.

juce_Font.cpp 21KB

9 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. namespace FontValues
  18. {
  19. static float limitFontHeight (const float height) noexcept
  20. {
  21. return jlimit (0.1f, 10000.0f, height);
  22. }
  23. const float defaultFontHeight = 14.0f;
  24. float minimumHorizontalScale = 0.7f;
  25. String fallbackFont;
  26. String fallbackFontStyle;
  27. }
  28. typedef Typeface::Ptr (*GetTypefaceForFont) (const Font&);
  29. GetTypefaceForFont juce_getTypefaceForFont = nullptr;
  30. float Font::getDefaultMinimumHorizontalScaleFactor() noexcept { return FontValues::minimumHorizontalScale; }
  31. void Font::setDefaultMinimumHorizontalScaleFactor (float newValue) noexcept { FontValues::minimumHorizontalScale = newValue; }
  32. //==============================================================================
  33. class TypefaceCache : private DeletedAtShutdown
  34. {
  35. public:
  36. TypefaceCache() : counter (0)
  37. {
  38. setSize (10);
  39. }
  40. ~TypefaceCache()
  41. {
  42. clearSingletonInstance();
  43. }
  44. juce_DeclareSingleton (TypefaceCache, false)
  45. void setSize (const int numToCache)
  46. {
  47. const ScopedWriteLock sl (lock);
  48. faces.clear();
  49. faces.insertMultiple (-1, CachedFace(), numToCache);
  50. }
  51. void clear()
  52. {
  53. const ScopedWriteLock sl (lock);
  54. setSize (faces.size());
  55. defaultFace = nullptr;
  56. }
  57. Typeface::Ptr findTypefaceFor (const Font& font)
  58. {
  59. const ScopedReadLock slr (lock);
  60. const String faceName (font.getTypefaceName());
  61. const String faceStyle (font.getTypefaceStyle());
  62. jassert (faceName.isNotEmpty());
  63. for (int i = faces.size(); --i >= 0;)
  64. {
  65. CachedFace& face = faces.getReference(i);
  66. if (face.typefaceName == faceName
  67. && face.typefaceStyle == faceStyle
  68. && face.typeface != nullptr
  69. && face.typeface->isSuitableForFont (font))
  70. {
  71. face.lastUsageCount = ++counter;
  72. return face.typeface;
  73. }
  74. }
  75. const ScopedWriteLock slw (lock);
  76. int replaceIndex = 0;
  77. size_t bestLastUsageCount = std::numeric_limits<size_t>::max();
  78. for (int i = faces.size(); --i >= 0;)
  79. {
  80. const size_t lu = faces.getReference(i).lastUsageCount;
  81. if (bestLastUsageCount > lu)
  82. {
  83. bestLastUsageCount = lu;
  84. replaceIndex = i;
  85. }
  86. }
  87. CachedFace& face = faces.getReference (replaceIndex);
  88. face.typefaceName = faceName;
  89. face.typefaceStyle = faceStyle;
  90. face.lastUsageCount = ++counter;
  91. if (juce_getTypefaceForFont == nullptr)
  92. face.typeface = Font::getDefaultTypefaceForFont (font);
  93. else
  94. face.typeface = juce_getTypefaceForFont (font);
  95. jassert (face.typeface != nullptr); // the look and feel must return a typeface!
  96. if (defaultFace == nullptr && font == Font())
  97. defaultFace = face.typeface;
  98. return face.typeface;
  99. }
  100. Typeface::Ptr defaultFace;
  101. private:
  102. struct CachedFace
  103. {
  104. CachedFace() noexcept : lastUsageCount (0) {}
  105. // Although it seems a bit wacky to store the name here, it's because it may be a
  106. // placeholder rather than a real one, e.g. "<Sans-Serif>" vs the actual typeface name.
  107. // Since the typeface itself doesn't know that it may have this alias, the name under
  108. // which it was fetched needs to be stored separately.
  109. String typefaceName, typefaceStyle;
  110. size_t lastUsageCount;
  111. Typeface::Ptr typeface;
  112. };
  113. ReadWriteLock lock;
  114. Array<CachedFace> faces;
  115. size_t counter;
  116. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache)
  117. };
  118. juce_ImplementSingleton (TypefaceCache)
  119. void Typeface::setTypefaceCacheSize (int numFontsToCache)
  120. {
  121. TypefaceCache::getInstance()->setSize (numFontsToCache);
  122. }
  123. #if JUCE_MODULE_AVAILABLE_juce_opengl
  124. extern void clearOpenGLGlyphCache();
  125. #endif
  126. void Typeface::clearTypefaceCache()
  127. {
  128. TypefaceCache::getInstance()->clear();
  129. RenderingHelpers::SoftwareRendererSavedState::clearGlyphCache();
  130. #if JUCE_MODULE_AVAILABLE_juce_opengl
  131. clearOpenGLGlyphCache();
  132. #endif
  133. }
  134. //==============================================================================
  135. class Font::SharedFontInternal : public ReferenceCountedObject
  136. {
  137. public:
  138. SharedFontInternal() noexcept
  139. : typeface (TypefaceCache::getInstance()->defaultFace),
  140. typefaceName (Font::getDefaultSansSerifFontName()),
  141. typefaceStyle (Font::getDefaultStyle()),
  142. height (FontValues::defaultFontHeight),
  143. horizontalScale (1.0f), kerning (0), ascent (0), underline (false)
  144. {
  145. }
  146. SharedFontInternal (int styleFlags, float fontHeight) noexcept
  147. : typefaceName (Font::getDefaultSansSerifFontName()),
  148. typefaceStyle (FontStyleHelpers::getStyleName (styleFlags)),
  149. height (fontHeight),
  150. horizontalScale (1.0f), kerning (0), ascent (0), underline ((styleFlags & underlined) != 0)
  151. {
  152. if (styleFlags == plain)
  153. typeface = TypefaceCache::getInstance()->defaultFace;
  154. }
  155. SharedFontInternal (const String& name, int styleFlags, float fontHeight) noexcept
  156. : typefaceName (name),
  157. typefaceStyle (FontStyleHelpers::getStyleName (styleFlags)),
  158. height (fontHeight),
  159. horizontalScale (1.0f), kerning (0), ascent (0), underline ((styleFlags & underlined) != 0)
  160. {
  161. if (styleFlags == plain && typefaceName.isEmpty())
  162. typeface = TypefaceCache::getInstance()->defaultFace;
  163. }
  164. SharedFontInternal (const String& name, const String& style, float fontHeight) noexcept
  165. : typefaceName (name), typefaceStyle (style), height (fontHeight),
  166. horizontalScale (1.0f), kerning (0), ascent (0), underline (false)
  167. {
  168. if (typefaceName.isEmpty())
  169. typefaceName = Font::getDefaultSansSerifFontName();
  170. }
  171. explicit SharedFontInternal (const Typeface::Ptr& face) noexcept
  172. : typeface (face),
  173. typefaceName (face->getName()),
  174. typefaceStyle (face->getStyle()),
  175. height (FontValues::defaultFontHeight),
  176. horizontalScale (1.0f), kerning (0), ascent (0), underline (false)
  177. {
  178. jassert (typefaceName.isNotEmpty());
  179. }
  180. SharedFontInternal (const SharedFontInternal& other) noexcept
  181. : ReferenceCountedObject(),
  182. typeface (other.typeface),
  183. typefaceName (other.typefaceName),
  184. typefaceStyle (other.typefaceStyle),
  185. height (other.height),
  186. horizontalScale (other.horizontalScale),
  187. kerning (other.kerning),
  188. ascent (other.ascent),
  189. underline (other.underline)
  190. {
  191. }
  192. bool operator== (const SharedFontInternal& other) const noexcept
  193. {
  194. return height == other.height
  195. && underline == other.underline
  196. && horizontalScale == other.horizontalScale
  197. && kerning == other.kerning
  198. && typefaceName == other.typefaceName
  199. && typefaceStyle == other.typefaceStyle;
  200. }
  201. Typeface::Ptr typeface;
  202. String typefaceName, typefaceStyle;
  203. float height, horizontalScale, kerning, ascent;
  204. bool underline;
  205. };
  206. //==============================================================================
  207. Font::Font() : font (new SharedFontInternal()) {}
  208. Font::Font (const Typeface::Ptr& typeface) : font (new SharedFontInternal (typeface)) {}
  209. Font::Font (const Font& other) noexcept : font (other.font) {}
  210. Font::Font (float fontHeight, int styleFlags)
  211. : font (new SharedFontInternal (styleFlags, FontValues::limitFontHeight (fontHeight)))
  212. {
  213. }
  214. Font::Font (const String& typefaceName, float fontHeight, int styleFlags)
  215. : font (new SharedFontInternal (typefaceName, styleFlags, FontValues::limitFontHeight (fontHeight)))
  216. {
  217. }
  218. Font::Font (const String& typefaceName, const String& typefaceStyle, float fontHeight)
  219. : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight)))
  220. {
  221. }
  222. Font& Font::operator= (const Font& other) noexcept
  223. {
  224. font = other.font;
  225. return *this;
  226. }
  227. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  228. Font::Font (Font&& other) noexcept
  229. : font (static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font))
  230. {
  231. }
  232. Font& Font::operator= (Font&& other) noexcept
  233. {
  234. font = static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font);
  235. return *this;
  236. }
  237. #endif
  238. Font::~Font() noexcept
  239. {
  240. }
  241. bool Font::operator== (const Font& other) const noexcept
  242. {
  243. return font == other.font
  244. || *font == *other.font;
  245. }
  246. bool Font::operator!= (const Font& other) const noexcept
  247. {
  248. return ! operator== (other);
  249. }
  250. void Font::dupeInternalIfShared()
  251. {
  252. if (font->getReferenceCount() > 1)
  253. font = new SharedFontInternal (*font);
  254. }
  255. void Font::checkTypefaceSuitability()
  256. {
  257. if (font->typeface != nullptr && ! font->typeface->isSuitableForFont (*this))
  258. font->typeface = nullptr;
  259. }
  260. //==============================================================================
  261. struct FontPlaceholderNames
  262. {
  263. FontPlaceholderNames()
  264. : sans ("<Sans-Serif>"),
  265. serif ("<Serif>"),
  266. mono ("<Monospaced>"),
  267. regular ("<Regular>")
  268. {
  269. }
  270. String sans, serif, mono, regular;
  271. };
  272. const FontPlaceholderNames& getFontPlaceholderNames()
  273. {
  274. static FontPlaceholderNames names;
  275. return names;
  276. }
  277. #if JUCE_MSVC
  278. // This is a workaround for the lack of thread-safety in MSVC's handling of function-local
  279. // statics - if multiple threads all try to create the first Font object at the same time,
  280. // it can cause a race-condition in creating these placeholder strings.
  281. struct FontNamePreloader { FontNamePreloader() { getFontPlaceholderNames(); } };
  282. static FontNamePreloader fnp;
  283. #endif
  284. const String& Font::getDefaultSansSerifFontName() { return getFontPlaceholderNames().sans; }
  285. const String& Font::getDefaultSerifFontName() { return getFontPlaceholderNames().serif; }
  286. const String& Font::getDefaultMonospacedFontName() { return getFontPlaceholderNames().mono; }
  287. const String& Font::getDefaultStyle() { return getFontPlaceholderNames().regular; }
  288. const String& Font::getTypefaceName() const noexcept { return font->typefaceName; }
  289. const String& Font::getTypefaceStyle() const noexcept { return font->typefaceStyle; }
  290. void Font::setTypefaceName (const String& faceName)
  291. {
  292. if (faceName != font->typefaceName)
  293. {
  294. jassert (faceName.isNotEmpty());
  295. dupeInternalIfShared();
  296. font->typefaceName = faceName;
  297. font->typeface = nullptr;
  298. font->ascent = 0;
  299. }
  300. }
  301. void Font::setTypefaceStyle (const String& typefaceStyle)
  302. {
  303. if (typefaceStyle != font->typefaceStyle)
  304. {
  305. dupeInternalIfShared();
  306. font->typefaceStyle = typefaceStyle;
  307. font->typeface = nullptr;
  308. font->ascent = 0;
  309. }
  310. }
  311. Font Font::withTypefaceStyle (const String& newStyle) const
  312. {
  313. Font f (*this);
  314. f.setTypefaceStyle (newStyle);
  315. return f;
  316. }
  317. StringArray Font::getAvailableStyles() const
  318. {
  319. return findAllTypefaceStyles (getTypeface()->getName());
  320. }
  321. Typeface* Font::getTypeface() const
  322. {
  323. if (font->typeface == nullptr)
  324. {
  325. font->typeface = TypefaceCache::getInstance()->findTypefaceFor (*this);
  326. jassert (font->typeface != nullptr);
  327. }
  328. return font->typeface;
  329. }
  330. //==============================================================================
  331. const String& Font::getFallbackFontName()
  332. {
  333. return FontValues::fallbackFont;
  334. }
  335. void Font::setFallbackFontName (const String& name)
  336. {
  337. FontValues::fallbackFont = name;
  338. #if JUCE_MAC || JUCE_IOS
  339. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  340. #endif
  341. }
  342. const String& Font::getFallbackFontStyle()
  343. {
  344. return FontValues::fallbackFontStyle;
  345. }
  346. void Font::setFallbackFontStyle (const String& style)
  347. {
  348. FontValues::fallbackFontStyle = style;
  349. #if JUCE_MAC || JUCE_IOS
  350. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  351. #endif
  352. }
  353. //==============================================================================
  354. Font Font::withHeight (const float newHeight) const
  355. {
  356. Font f (*this);
  357. f.setHeight (newHeight);
  358. return f;
  359. }
  360. float Font::getHeightToPointsFactor() const
  361. {
  362. return getTypeface()->getHeightToPointsFactor();
  363. }
  364. Font Font::withPointHeight (float heightInPoints) const
  365. {
  366. Font f (*this);
  367. f.setHeight (heightInPoints / getHeightToPointsFactor());
  368. return f;
  369. }
  370. void Font::setHeight (float newHeight)
  371. {
  372. newHeight = FontValues::limitFontHeight (newHeight);
  373. if (font->height != newHeight)
  374. {
  375. dupeInternalIfShared();
  376. font->height = newHeight;
  377. checkTypefaceSuitability();
  378. }
  379. }
  380. void Font::setHeightWithoutChangingWidth (float newHeight)
  381. {
  382. newHeight = FontValues::limitFontHeight (newHeight);
  383. if (font->height != newHeight)
  384. {
  385. dupeInternalIfShared();
  386. font->horizontalScale *= (font->height / newHeight);
  387. font->height = newHeight;
  388. checkTypefaceSuitability();
  389. }
  390. }
  391. int Font::getStyleFlags() const noexcept
  392. {
  393. int styleFlags = font->underline ? underlined : plain;
  394. if (isBold()) styleFlags |= bold;
  395. if (isItalic()) styleFlags |= italic;
  396. return styleFlags;
  397. }
  398. Font Font::withStyle (const int newFlags) const
  399. {
  400. Font f (*this);
  401. f.setStyleFlags (newFlags);
  402. return f;
  403. }
  404. void Font::setStyleFlags (const int newFlags)
  405. {
  406. if (getStyleFlags() != newFlags)
  407. {
  408. dupeInternalIfShared();
  409. font->typeface = nullptr;
  410. font->typefaceStyle = FontStyleHelpers::getStyleName (newFlags);
  411. font->underline = (newFlags & underlined) != 0;
  412. font->ascent = 0;
  413. }
  414. }
  415. void Font::setSizeAndStyle (float newHeight,
  416. const int newStyleFlags,
  417. const float newHorizontalScale,
  418. const float newKerningAmount)
  419. {
  420. newHeight = FontValues::limitFontHeight (newHeight);
  421. if (font->height != newHeight
  422. || font->horizontalScale != newHorizontalScale
  423. || font->kerning != newKerningAmount)
  424. {
  425. dupeInternalIfShared();
  426. font->height = newHeight;
  427. font->horizontalScale = newHorizontalScale;
  428. font->kerning = newKerningAmount;
  429. checkTypefaceSuitability();
  430. }
  431. setStyleFlags (newStyleFlags);
  432. }
  433. void Font::setSizeAndStyle (float newHeight,
  434. const String& newStyle,
  435. const float newHorizontalScale,
  436. const float newKerningAmount)
  437. {
  438. newHeight = FontValues::limitFontHeight (newHeight);
  439. if (font->height != newHeight
  440. || font->horizontalScale != newHorizontalScale
  441. || font->kerning != newKerningAmount)
  442. {
  443. dupeInternalIfShared();
  444. font->height = newHeight;
  445. font->horizontalScale = newHorizontalScale;
  446. font->kerning = newKerningAmount;
  447. checkTypefaceSuitability();
  448. }
  449. setTypefaceStyle (newStyle);
  450. }
  451. Font Font::withHorizontalScale (const float newHorizontalScale) const
  452. {
  453. Font f (*this);
  454. f.setHorizontalScale (newHorizontalScale);
  455. return f;
  456. }
  457. void Font::setHorizontalScale (const float scaleFactor)
  458. {
  459. dupeInternalIfShared();
  460. font->horizontalScale = scaleFactor;
  461. checkTypefaceSuitability();
  462. }
  463. float Font::getHorizontalScale() const noexcept
  464. {
  465. return font->horizontalScale;
  466. }
  467. float Font::getExtraKerningFactor() const noexcept
  468. {
  469. return font->kerning;
  470. }
  471. Font Font::withExtraKerningFactor (const float extraKerning) const
  472. {
  473. Font f (*this);
  474. f.setExtraKerningFactor (extraKerning);
  475. return f;
  476. }
  477. void Font::setExtraKerningFactor (const float extraKerning)
  478. {
  479. dupeInternalIfShared();
  480. font->kerning = extraKerning;
  481. checkTypefaceSuitability();
  482. }
  483. Font Font::boldened() const { return withStyle (getStyleFlags() | bold); }
  484. Font Font::italicised() const { return withStyle (getStyleFlags() | italic); }
  485. bool Font::isBold() const noexcept { return FontStyleHelpers::isBold (font->typefaceStyle); }
  486. bool Font::isItalic() const noexcept { return FontStyleHelpers::isItalic (font->typefaceStyle); }
  487. bool Font::isUnderlined() const noexcept { return font->underline; }
  488. void Font::setBold (const bool shouldBeBold)
  489. {
  490. const int flags = getStyleFlags();
  491. setStyleFlags (shouldBeBold ? (flags | bold)
  492. : (flags & ~bold));
  493. }
  494. void Font::setItalic (const bool shouldBeItalic)
  495. {
  496. const int flags = getStyleFlags();
  497. setStyleFlags (shouldBeItalic ? (flags | italic)
  498. : (flags & ~italic));
  499. }
  500. void Font::setUnderline (const bool shouldBeUnderlined)
  501. {
  502. dupeInternalIfShared();
  503. font->underline = shouldBeUnderlined;
  504. checkTypefaceSuitability();
  505. }
  506. float Font::getAscent() const
  507. {
  508. if (font->ascent == 0)
  509. font->ascent = getTypeface()->getAscent();
  510. return font->height * font->ascent;
  511. }
  512. float Font::getHeight() const noexcept { return font->height; }
  513. float Font::getDescent() const { return font->height - getAscent(); }
  514. float Font::getHeightInPoints() const { return getHeight() * getHeightToPointsFactor(); }
  515. float Font::getAscentInPoints() const { return getAscent() * getHeightToPointsFactor(); }
  516. float Font::getDescentInPoints() const { return getDescent() * getHeightToPointsFactor(); }
  517. int Font::getStringWidth (const String& text) const
  518. {
  519. return roundToInt (getStringWidthFloat (text));
  520. }
  521. float Font::getStringWidthFloat (const String& text) const
  522. {
  523. float w = getTypeface()->getStringWidth (text);
  524. if (font->kerning != 0)
  525. w += font->kerning * text.length();
  526. return w * font->height * font->horizontalScale;
  527. }
  528. void Font::getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const
  529. {
  530. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  531. const int num = xOffsets.size();
  532. if (num > 0)
  533. {
  534. const float scale = font->height * font->horizontalScale;
  535. float* const x = xOffsets.getRawDataPointer();
  536. if (font->kerning != 0)
  537. {
  538. for (int i = 0; i < num; ++i)
  539. x[i] = (x[i] + i * font->kerning) * scale;
  540. }
  541. else
  542. {
  543. for (int i = 0; i < num; ++i)
  544. x[i] *= scale;
  545. }
  546. }
  547. }
  548. void Font::findFonts (Array<Font>& destArray)
  549. {
  550. const StringArray names (findAllTypefaceNames());
  551. for (int i = 0; i < names.size(); ++i)
  552. {
  553. const StringArray styles (findAllTypefaceStyles (names[i]));
  554. String style ("Regular");
  555. if (! styles.contains (style, true))
  556. style = styles[0];
  557. destArray.add (Font (names[i], style, FontValues::defaultFontHeight));
  558. }
  559. }
  560. //==============================================================================
  561. String Font::toString() const
  562. {
  563. String s;
  564. if (getTypefaceName() != getDefaultSansSerifFontName())
  565. s << getTypefaceName() << "; ";
  566. s << String (getHeight(), 1);
  567. if (getTypefaceStyle() != getDefaultStyle())
  568. s << ' ' << getTypefaceStyle();
  569. return s;
  570. }
  571. Font Font::fromString (const String& fontDescription)
  572. {
  573. const int separator = fontDescription.indexOfChar (';');
  574. String name;
  575. if (separator > 0)
  576. name = fontDescription.substring (0, separator).trim();
  577. if (name.isEmpty())
  578. name = getDefaultSansSerifFontName();
  579. String sizeAndStyle (fontDescription.substring (separator + 1).trimStart());
  580. float height = sizeAndStyle.getFloatValue();
  581. if (height <= 0)
  582. height = 10.0f;
  583. const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false));
  584. return Font (name, style, height);
  585. }