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.

832 lines
24KB

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