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.

715 lines
21KB

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