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.

823 lines
24KB

  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 getDefaultFace() const noexcept
  106. {
  107. const ScopedReadLock slr (lock);
  108. return defaultFace;
  109. }
  110. private:
  111. struct CachedFace
  112. {
  113. CachedFace() noexcept {}
  114. // Although it seems a bit wacky to store the name here, it's because it may be a
  115. // placeholder rather than a real one, e.g. "<Sans-Serif>" vs the actual typeface name.
  116. // Since the typeface itself doesn't know that it may have this alias, the name under
  117. // which it was fetched needs to be stored separately.
  118. String typefaceName, typefaceStyle;
  119. size_t lastUsageCount = 0;
  120. Typeface::Ptr typeface;
  121. };
  122. Typeface::Ptr defaultFace;
  123. ReadWriteLock lock;
  124. Array<CachedFace> faces;
  125. size_t counter = 0;
  126. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache)
  127. };
  128. JUCE_IMPLEMENT_SINGLETON (TypefaceCache)
  129. void Typeface::setTypefaceCacheSize (int numFontsToCache)
  130. {
  131. TypefaceCache::getInstance()->setSize (numFontsToCache);
  132. }
  133. void (*clearOpenGLGlyphCache)() = nullptr;
  134. void Typeface::clearTypefaceCache()
  135. {
  136. TypefaceCache::getInstance()->clear();
  137. RenderingHelpers::SoftwareRendererSavedState::clearGlyphCache();
  138. if (clearOpenGLGlyphCache != nullptr)
  139. clearOpenGLGlyphCache();
  140. }
  141. //==============================================================================
  142. class Font::SharedFontInternal : public ReferenceCountedObject
  143. {
  144. public:
  145. SharedFontInternal() noexcept
  146. : typeface (TypefaceCache::getInstance()->getDefaultFace()),
  147. typefaceName (Font::getDefaultSansSerifFontName()),
  148. typefaceStyle (Font::getDefaultStyle()),
  149. height (FontValues::defaultFontHeight)
  150. {
  151. }
  152. SharedFontInternal (int styleFlags, float fontHeight) noexcept
  153. : typefaceName (Font::getDefaultSansSerifFontName()),
  154. typefaceStyle (FontStyleHelpers::getStyleName (styleFlags)),
  155. height (fontHeight),
  156. underline ((styleFlags & underlined) != 0)
  157. {
  158. if (styleFlags == plain)
  159. typeface = TypefaceCache::getInstance()->getDefaultFace();
  160. }
  161. SharedFontInternal (const String& name, int styleFlags, float fontHeight) noexcept
  162. : typefaceName (name),
  163. typefaceStyle (FontStyleHelpers::getStyleName (styleFlags)),
  164. height (fontHeight),
  165. underline ((styleFlags & underlined) != 0)
  166. {
  167. if (styleFlags == plain && typefaceName.isEmpty())
  168. typeface = TypefaceCache::getInstance()->getDefaultFace();
  169. }
  170. SharedFontInternal (const String& name, const String& style, float fontHeight) noexcept
  171. : typefaceName (name), typefaceStyle (style), height (fontHeight)
  172. {
  173. if (typefaceName.isEmpty())
  174. typefaceName = Font::getDefaultSansSerifFontName();
  175. }
  176. explicit SharedFontInternal (const Typeface::Ptr& face) noexcept
  177. : typeface (face),
  178. typefaceName (face->getName()),
  179. typefaceStyle (face->getStyle()),
  180. height (FontValues::defaultFontHeight)
  181. {
  182. jassert (typefaceName.isNotEmpty());
  183. }
  184. SharedFontInternal (const SharedFontInternal& other) noexcept
  185. : ReferenceCountedObject(),
  186. typeface (other.typeface),
  187. typefaceName (other.typefaceName),
  188. typefaceStyle (other.typefaceStyle),
  189. height (other.height),
  190. horizontalScale (other.horizontalScale),
  191. kerning (other.kerning),
  192. ascent (other.ascent),
  193. underline (other.underline)
  194. {
  195. }
  196. bool operator== (const SharedFontInternal& other) const noexcept
  197. {
  198. return height == other.height
  199. && underline == other.underline
  200. && horizontalScale == other.horizontalScale
  201. && kerning == other.kerning
  202. && typefaceName == other.typefaceName
  203. && typefaceStyle == other.typefaceStyle;
  204. }
  205. /* The typeface and ascent data members may be read/set from multiple threads
  206. simultaneously, e.g. in the case that two Font instances reference the same
  207. SharedFontInternal and call getTypefacePtr() simultaneously.
  208. We lock in functions that modify the typeface or ascent in order to
  209. ensure thread safety.
  210. */
  211. Typeface::Ptr getTypefacePtr (const Font& f)
  212. {
  213. const ScopedLock lock (mutex);
  214. if (typeface == nullptr)
  215. {
  216. typeface = TypefaceCache::getInstance()->findTypefaceFor (f);
  217. jassert (typeface != nullptr);
  218. }
  219. return typeface;
  220. }
  221. void checkTypefaceSuitability (const Font& f)
  222. {
  223. const ScopedLock lock (mutex);
  224. if (typeface != nullptr && ! typeface->isSuitableForFont (f))
  225. typeface = nullptr;
  226. }
  227. float getAscent (const Font& f)
  228. {
  229. const ScopedLock lock (mutex);
  230. if (ascent == 0.0f)
  231. ascent = getTypefacePtr (f)->getAscent();
  232. return height * ascent;
  233. }
  234. /* We do not need to lock in these functions, as it's guaranteed
  235. that these data members can only change if there is a single Font
  236. instance referencing the shared state.
  237. */
  238. String getTypefaceName() const { return typefaceName; }
  239. String getTypefaceStyle() const { return typefaceStyle; }
  240. float getHeight() const { return height; }
  241. float getHorizontalScale() const { return horizontalScale; }
  242. float getKerning() const { return kerning; }
  243. bool getUnderline() const { return underline; }
  244. /* This shared state may be shared between two or more Font instances that are being
  245. read/modified from multiple threads.
  246. Before modifying a shared instance you *must* call dupeInternalIfShared to
  247. ensure that only one Font instance is pointing to the SharedFontInternal instance
  248. during the modification.
  249. */
  250. void setTypeface (Typeface::Ptr x)
  251. {
  252. jassert (getReferenceCount() == 1);
  253. typeface = std::move (x);
  254. }
  255. void setTypefaceName (String x)
  256. {
  257. jassert (getReferenceCount() == 1);
  258. typefaceName = std::move (x);
  259. }
  260. void setTypefaceStyle (String x)
  261. {
  262. jassert (getReferenceCount() == 1);
  263. typefaceStyle = std::move (x);
  264. }
  265. void setHeight (float x)
  266. {
  267. jassert (getReferenceCount() == 1);
  268. height = x;
  269. }
  270. void setHorizontalScale (float x)
  271. {
  272. jassert (getReferenceCount() == 1);
  273. horizontalScale = x;
  274. }
  275. void setKerning (float x)
  276. {
  277. jassert (getReferenceCount() == 1);
  278. kerning = x;
  279. }
  280. void setAscent (float x)
  281. {
  282. jassert (getReferenceCount() == 1);
  283. ascent = x;
  284. }
  285. void setUnderline (bool x)
  286. {
  287. jassert (getReferenceCount() == 1);
  288. underline = x;
  289. }
  290. private:
  291. Typeface::Ptr typeface;
  292. String typefaceName, typefaceStyle;
  293. float height = 0.0f, horizontalScale = 1.0f, kerning = 0.0f, ascent = 0.0f;
  294. bool underline = false;
  295. CriticalSection mutex;
  296. };
  297. //==============================================================================
  298. Font::Font() : font (new SharedFontInternal()) {}
  299. Font::Font (const Typeface::Ptr& typeface) : font (new SharedFontInternal (typeface)) {}
  300. Font::Font (const Font& other) noexcept : font (other.font) {}
  301. Font::Font (float fontHeight, int styleFlags)
  302. : font (new SharedFontInternal (styleFlags, FontValues::limitFontHeight (fontHeight)))
  303. {
  304. }
  305. Font::Font (const String& typefaceName, float fontHeight, int styleFlags)
  306. : font (new SharedFontInternal (typefaceName, styleFlags, FontValues::limitFontHeight (fontHeight)))
  307. {
  308. }
  309. Font::Font (const String& typefaceName, const String& typefaceStyle, float fontHeight)
  310. : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight)))
  311. {
  312. }
  313. Font& Font::operator= (const Font& other) noexcept
  314. {
  315. font = other.font;
  316. return *this;
  317. }
  318. Font::Font (Font&& other) noexcept
  319. : font (std::move (other.font))
  320. {
  321. }
  322. Font& Font::operator= (Font&& other) noexcept
  323. {
  324. font = std::move (other.font);
  325. return *this;
  326. }
  327. Font::~Font() noexcept = default;
  328. bool Font::operator== (const Font& other) const noexcept
  329. {
  330. return font == other.font
  331. || *font == *other.font;
  332. }
  333. bool Font::operator!= (const Font& other) const noexcept
  334. {
  335. return ! operator== (other);
  336. }
  337. void Font::dupeInternalIfShared()
  338. {
  339. if (font->getReferenceCount() > 1)
  340. font = *new SharedFontInternal (*font);
  341. }
  342. void Font::checkTypefaceSuitability()
  343. {
  344. font->checkTypefaceSuitability (*this);
  345. }
  346. //==============================================================================
  347. struct FontPlaceholderNames
  348. {
  349. String sans { "<Sans-Serif>" },
  350. serif { "<Serif>" },
  351. mono { "<Monospaced>" },
  352. regular { "<Regular>" };
  353. };
  354. static const FontPlaceholderNames& getFontPlaceholderNames()
  355. {
  356. static FontPlaceholderNames names;
  357. return names;
  358. }
  359. #if JUCE_MSVC
  360. // This is a workaround for the lack of thread-safety in MSVC's handling of function-local
  361. // statics - if multiple threads all try to create the first Font object at the same time,
  362. // it can cause a race-condition in creating these placeholder strings.
  363. struct FontNamePreloader { FontNamePreloader() { getFontPlaceholderNames(); } };
  364. static FontNamePreloader fnp;
  365. #endif
  366. const String& Font::getDefaultSansSerifFontName() { return getFontPlaceholderNames().sans; }
  367. const String& Font::getDefaultSerifFontName() { return getFontPlaceholderNames().serif; }
  368. const String& Font::getDefaultMonospacedFontName() { return getFontPlaceholderNames().mono; }
  369. const String& Font::getDefaultStyle() { return getFontPlaceholderNames().regular; }
  370. String Font::getTypefaceName() const noexcept { return font->getTypefaceName(); }
  371. String Font::getTypefaceStyle() const noexcept { return font->getTypefaceStyle(); }
  372. void Font::setTypefaceName (const String& faceName)
  373. {
  374. if (faceName != font->getTypefaceName())
  375. {
  376. jassert (faceName.isNotEmpty());
  377. dupeInternalIfShared();
  378. font->setTypefaceName (faceName);
  379. font->setTypeface (nullptr);
  380. font->setAscent (0);
  381. }
  382. }
  383. void Font::setTypefaceStyle (const String& typefaceStyle)
  384. {
  385. if (typefaceStyle != font->getTypefaceStyle())
  386. {
  387. dupeInternalIfShared();
  388. font->setTypefaceStyle (typefaceStyle);
  389. font->setTypeface (nullptr);
  390. font->setAscent (0);
  391. }
  392. }
  393. Font Font::withTypefaceStyle (const String& newStyle) const
  394. {
  395. Font f (*this);
  396. f.setTypefaceStyle (newStyle);
  397. return f;
  398. }
  399. StringArray Font::getAvailableStyles() const
  400. {
  401. return findAllTypefaceStyles (getTypefacePtr()->getName());
  402. }
  403. Typeface::Ptr Font::getTypefacePtr() const
  404. {
  405. return font->getTypefacePtr (*this);
  406. }
  407. Typeface* Font::getTypeface() const
  408. {
  409. return getTypefacePtr().get();
  410. }
  411. //==============================================================================
  412. const String& Font::getFallbackFontName()
  413. {
  414. return FontValues::fallbackFont;
  415. }
  416. void Font::setFallbackFontName (const String& name)
  417. {
  418. FontValues::fallbackFont = name;
  419. #if JUCE_MAC || JUCE_IOS
  420. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  421. #endif
  422. }
  423. const String& Font::getFallbackFontStyle()
  424. {
  425. return FontValues::fallbackFontStyle;
  426. }
  427. void Font::setFallbackFontStyle (const String& style)
  428. {
  429. FontValues::fallbackFontStyle = style;
  430. #if JUCE_MAC || JUCE_IOS
  431. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  432. #endif
  433. }
  434. //==============================================================================
  435. Font Font::withHeight (const float newHeight) const
  436. {
  437. Font f (*this);
  438. f.setHeight (newHeight);
  439. return f;
  440. }
  441. float Font::getHeightToPointsFactor() const
  442. {
  443. return getTypefacePtr()->getHeightToPointsFactor();
  444. }
  445. Font Font::withPointHeight (float heightInPoints) const
  446. {
  447. Font f (*this);
  448. f.setHeight (heightInPoints / getHeightToPointsFactor());
  449. return f;
  450. }
  451. void Font::setHeight (float newHeight)
  452. {
  453. newHeight = FontValues::limitFontHeight (newHeight);
  454. if (font->getHeight() != newHeight)
  455. {
  456. dupeInternalIfShared();
  457. font->setHeight (newHeight);
  458. checkTypefaceSuitability();
  459. }
  460. }
  461. void Font::setHeightWithoutChangingWidth (float newHeight)
  462. {
  463. newHeight = FontValues::limitFontHeight (newHeight);
  464. if (font->getHeight() != newHeight)
  465. {
  466. dupeInternalIfShared();
  467. font->setHorizontalScale (font->getHorizontalScale() * (font->getHeight() / newHeight));
  468. font->setHeight (newHeight);
  469. checkTypefaceSuitability();
  470. }
  471. }
  472. int Font::getStyleFlags() const noexcept
  473. {
  474. int styleFlags = font->getUnderline() ? underlined : plain;
  475. if (isBold()) styleFlags |= bold;
  476. if (isItalic()) styleFlags |= italic;
  477. return styleFlags;
  478. }
  479. Font Font::withStyle (const int newFlags) const
  480. {
  481. Font f (*this);
  482. f.setStyleFlags (newFlags);
  483. return f;
  484. }
  485. void Font::setStyleFlags (const int newFlags)
  486. {
  487. if (getStyleFlags() != newFlags)
  488. {
  489. dupeInternalIfShared();
  490. font->setTypeface (nullptr);
  491. font->setTypefaceStyle (FontStyleHelpers::getStyleName (newFlags));
  492. font->setUnderline ((newFlags & underlined) != 0);
  493. font->setAscent (0);
  494. }
  495. }
  496. void Font::setSizeAndStyle (float newHeight,
  497. const int newStyleFlags,
  498. const float newHorizontalScale,
  499. const float newKerningAmount)
  500. {
  501. newHeight = FontValues::limitFontHeight (newHeight);
  502. if (font->getHeight() != newHeight
  503. || font->getHorizontalScale() != newHorizontalScale
  504. || font->getKerning() != newKerningAmount)
  505. {
  506. dupeInternalIfShared();
  507. font->setHeight (newHeight);
  508. font->setHorizontalScale (newHorizontalScale);
  509. font->setKerning (newKerningAmount);
  510. checkTypefaceSuitability();
  511. }
  512. setStyleFlags (newStyleFlags);
  513. }
  514. void Font::setSizeAndStyle (float newHeight,
  515. const String& newStyle,
  516. const float newHorizontalScale,
  517. const float newKerningAmount)
  518. {
  519. newHeight = FontValues::limitFontHeight (newHeight);
  520. if (font->getHeight() != newHeight
  521. || font->getHorizontalScale() != newHorizontalScale
  522. || font->getKerning() != newKerningAmount)
  523. {
  524. dupeInternalIfShared();
  525. font->setHeight (newHeight);
  526. font->setHorizontalScale (newHorizontalScale);
  527. font->setKerning (newKerningAmount);
  528. checkTypefaceSuitability();
  529. }
  530. setTypefaceStyle (newStyle);
  531. }
  532. Font Font::withHorizontalScale (const float newHorizontalScale) const
  533. {
  534. Font f (*this);
  535. f.setHorizontalScale (newHorizontalScale);
  536. return f;
  537. }
  538. void Font::setHorizontalScale (const float scaleFactor)
  539. {
  540. dupeInternalIfShared();
  541. font->setHorizontalScale (scaleFactor);
  542. checkTypefaceSuitability();
  543. }
  544. float Font::getHorizontalScale() const noexcept
  545. {
  546. return font->getHorizontalScale();
  547. }
  548. float Font::getExtraKerningFactor() const noexcept
  549. {
  550. return font->getKerning();
  551. }
  552. Font Font::withExtraKerningFactor (const float extraKerning) const
  553. {
  554. Font f (*this);
  555. f.setExtraKerningFactor (extraKerning);
  556. return f;
  557. }
  558. void Font::setExtraKerningFactor (const float extraKerning)
  559. {
  560. dupeInternalIfShared();
  561. font->setKerning (extraKerning);
  562. checkTypefaceSuitability();
  563. }
  564. Font Font::boldened() const { return withStyle (getStyleFlags() | bold); }
  565. Font Font::italicised() const { return withStyle (getStyleFlags() | italic); }
  566. bool Font::isBold() const noexcept { return FontStyleHelpers::isBold (font->getTypefaceStyle()); }
  567. bool Font::isItalic() const noexcept { return FontStyleHelpers::isItalic (font->getTypefaceStyle()); }
  568. bool Font::isUnderlined() const noexcept { return font->getUnderline(); }
  569. void Font::setBold (const bool shouldBeBold)
  570. {
  571. auto flags = getStyleFlags();
  572. setStyleFlags (shouldBeBold ? (flags | bold)
  573. : (flags & ~bold));
  574. }
  575. void Font::setItalic (const bool shouldBeItalic)
  576. {
  577. auto flags = getStyleFlags();
  578. setStyleFlags (shouldBeItalic ? (flags | italic)
  579. : (flags & ~italic));
  580. }
  581. void Font::setUnderline (const bool shouldBeUnderlined)
  582. {
  583. dupeInternalIfShared();
  584. font->setUnderline (shouldBeUnderlined);
  585. checkTypefaceSuitability();
  586. }
  587. float Font::getAscent() const
  588. {
  589. return font->getAscent (*this);
  590. }
  591. float Font::getHeight() const noexcept { return font->getHeight(); }
  592. float Font::getDescent() const { return font->getHeight() - getAscent(); }
  593. float Font::getHeightInPoints() const { return getHeight() * getHeightToPointsFactor(); }
  594. float Font::getAscentInPoints() const { return getAscent() * getHeightToPointsFactor(); }
  595. float Font::getDescentInPoints() const { return getDescent() * getHeightToPointsFactor(); }
  596. int Font::getStringWidth (const String& text) const
  597. {
  598. return (int) std::ceil (getStringWidthFloat (text));
  599. }
  600. float Font::getStringWidthFloat (const String& text) const
  601. {
  602. auto w = getTypefacePtr()->getStringWidth (text);
  603. if (font->getKerning() != 0.0f)
  604. w += font->getKerning() * (float) text.length();
  605. return w * font->getHeight() * font->getHorizontalScale();
  606. }
  607. void Font::getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const
  608. {
  609. getTypefacePtr()->getGlyphPositions (text, glyphs, xOffsets);
  610. if (auto num = xOffsets.size())
  611. {
  612. auto scale = font->getHeight() * font->getHorizontalScale();
  613. auto* x = xOffsets.getRawDataPointer();
  614. if (font->getKerning() != 0.0f)
  615. {
  616. for (int i = 0; i < num; ++i)
  617. x[i] = (x[i] + (float) i * font->getKerning()) * scale;
  618. }
  619. else
  620. {
  621. for (int i = 0; i < num; ++i)
  622. x[i] *= scale;
  623. }
  624. }
  625. }
  626. void Font::findFonts (Array<Font>& destArray)
  627. {
  628. for (auto& name : findAllTypefaceNames())
  629. {
  630. auto styles = findAllTypefaceStyles (name);
  631. String style ("Regular");
  632. if (! styles.contains (style, true))
  633. style = styles[0];
  634. destArray.add (Font (name, style, FontValues::defaultFontHeight));
  635. }
  636. }
  637. //==============================================================================
  638. String Font::toString() const
  639. {
  640. String s;
  641. if (getTypefaceName() != getDefaultSansSerifFontName())
  642. s << getTypefaceName() << "; ";
  643. s << String (getHeight(), 1);
  644. if (getTypefaceStyle() != getDefaultStyle())
  645. s << ' ' << getTypefaceStyle();
  646. return s;
  647. }
  648. Font Font::fromString (const String& fontDescription)
  649. {
  650. const int separator = fontDescription.indexOfChar (';');
  651. String name;
  652. if (separator > 0)
  653. name = fontDescription.substring (0, separator).trim();
  654. if (name.isEmpty())
  655. name = getDefaultSansSerifFontName();
  656. String sizeAndStyle (fontDescription.substring (separator + 1).trimStart());
  657. float height = sizeAndStyle.getFloatValue();
  658. if (height <= 0)
  659. height = 10.0f;
  660. const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false));
  661. return Font (name, style, height);
  662. }
  663. } // namespace juce