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

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