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

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