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 24KB

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