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.

718 lines
21KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace FontValues
  20. {
  21. static float limitFontHeight (const float height) noexcept
  22. {
  23. return jlimit (0.1f, 10000.0f, height);
  24. }
  25. const float defaultFontHeight = 14.0f;
  26. float minimumHorizontalScale = 0.7f;
  27. String fallbackFont;
  28. String fallbackFontStyle;
  29. }
  30. typedef Typeface::Ptr (*GetTypefaceForFont) (const Font&);
  31. GetTypefaceForFont juce_getTypefaceForFont = nullptr;
  32. float Font::getDefaultMinimumHorizontalScaleFactor() noexcept { return FontValues::minimumHorizontalScale; }
  33. void Font::setDefaultMinimumHorizontalScaleFactor (float newValue) noexcept { FontValues::minimumHorizontalScale = newValue; }
  34. //==============================================================================
  35. class TypefaceCache : private DeletedAtShutdown
  36. {
  37. public:
  38. TypefaceCache()
  39. {
  40. setSize (10);
  41. }
  42. ~TypefaceCache()
  43. {
  44. clearSingletonInstance();
  45. }
  46. juce_DeclareSingleton (TypefaceCache, false)
  47. void setSize (const int numToCache)
  48. {
  49. const ScopedWriteLock sl (lock);
  50. faces.clear();
  51. faces.insertMultiple (-1, CachedFace(), numToCache);
  52. }
  53. void clear()
  54. {
  55. const ScopedWriteLock sl (lock);
  56. setSize (faces.size());
  57. defaultFace = nullptr;
  58. }
  59. Typeface::Ptr findTypefaceFor (const Font& font)
  60. {
  61. const ScopedReadLock slr (lock);
  62. auto faceName = font.getTypefaceName();
  63. auto faceStyle = font.getTypefaceStyle();
  64. jassert (faceName.isNotEmpty());
  65. for (int i = faces.size(); --i >= 0;)
  66. {
  67. CachedFace& face = faces.getReference(i);
  68. if (face.typefaceName == faceName
  69. && face.typefaceStyle == faceStyle
  70. && face.typeface != nullptr
  71. && face.typeface->isSuitableForFont (font))
  72. {
  73. face.lastUsageCount = ++counter;
  74. return face.typeface;
  75. }
  76. }
  77. const ScopedWriteLock slw (lock);
  78. int replaceIndex = 0;
  79. auto bestLastUsageCount = std::numeric_limits<size_t>::max();
  80. for (int i = faces.size(); --i >= 0;)
  81. {
  82. auto lu = faces.getReference(i).lastUsageCount;
  83. if (bestLastUsageCount > lu)
  84. {
  85. bestLastUsageCount = lu;
  86. replaceIndex = i;
  87. }
  88. }
  89. auto& face = faces.getReference (replaceIndex);
  90. face.typefaceName = faceName;
  91. face.typefaceStyle = faceStyle;
  92. face.lastUsageCount = ++counter;
  93. if (juce_getTypefaceForFont == nullptr)
  94. face.typeface = Font::getDefaultTypefaceForFont (font);
  95. else
  96. face.typeface = juce_getTypefaceForFont (font);
  97. jassert (face.typeface != nullptr); // the look and feel must return a typeface!
  98. if (defaultFace == nullptr && font == Font())
  99. defaultFace = face.typeface;
  100. return face.typeface;
  101. }
  102. Typeface::Ptr defaultFace;
  103. private:
  104. struct CachedFace
  105. {
  106. CachedFace() noexcept : lastUsageCount (0) {}
  107. // Although it seems a bit wacky to store the name here, it's because it may be a
  108. // placeholder rather than a real one, e.g. "<Sans-Serif>" vs the actual typeface name.
  109. // Since the typeface itself doesn't know that it may have this alias, the name under
  110. // which it was fetched needs to be stored separately.
  111. String typefaceName, typefaceStyle;
  112. size_t lastUsageCount;
  113. Typeface::Ptr typeface;
  114. };
  115. ReadWriteLock lock;
  116. Array<CachedFace> faces;
  117. size_t counter = 0;
  118. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache)
  119. };
  120. juce_ImplementSingleton (TypefaceCache)
  121. void Typeface::setTypefaceCacheSize (int numFontsToCache)
  122. {
  123. TypefaceCache::getInstance()->setSize (numFontsToCache);
  124. }
  125. void (*clearOpenGLGlyphCache)() = nullptr;
  126. void Typeface::clearTypefaceCache()
  127. {
  128. TypefaceCache::getInstance()->clear();
  129. RenderingHelpers::SoftwareRendererSavedState::clearGlyphCache();
  130. if (clearOpenGLGlyphCache != nullptr)
  131. clearOpenGLGlyphCache();
  132. }
  133. //==============================================================================
  134. class Font::SharedFontInternal : public ReferenceCountedObject
  135. {
  136. public:
  137. SharedFontInternal() noexcept
  138. : typeface (TypefaceCache::getInstance()->defaultFace),
  139. typefaceName (Font::getDefaultSansSerifFontName()),
  140. typefaceStyle (Font::getDefaultStyle()),
  141. height (FontValues::defaultFontHeight)
  142. {
  143. }
  144. SharedFontInternal (int styleFlags, float fontHeight) noexcept
  145. : typefaceName (Font::getDefaultSansSerifFontName()),
  146. typefaceStyle (FontStyleHelpers::getStyleName (styleFlags)),
  147. height (fontHeight),
  148. underline ((styleFlags & underlined) != 0)
  149. {
  150. if (styleFlags == plain)
  151. typeface = TypefaceCache::getInstance()->defaultFace;
  152. }
  153. SharedFontInternal (const String& name, int styleFlags, float fontHeight) noexcept
  154. : typefaceName (name),
  155. typefaceStyle (FontStyleHelpers::getStyleName (styleFlags)),
  156. height (fontHeight),
  157. underline ((styleFlags & underlined) != 0)
  158. {
  159. if (styleFlags == plain && typefaceName.isEmpty())
  160. typeface = TypefaceCache::getInstance()->defaultFace;
  161. }
  162. SharedFontInternal (const String& name, const String& style, float fontHeight) noexcept
  163. : typefaceName (name), typefaceStyle (style), height (fontHeight)
  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. {
  174. jassert (typefaceName.isNotEmpty());
  175. }
  176. SharedFontInternal (const SharedFontInternal& other) noexcept
  177. : ReferenceCountedObject(),
  178. typeface (other.typeface),
  179. typefaceName (other.typefaceName),
  180. typefaceStyle (other.typefaceStyle),
  181. height (other.height),
  182. horizontalScale (other.horizontalScale),
  183. kerning (other.kerning),
  184. ascent (other.ascent),
  185. underline (other.underline)
  186. {
  187. }
  188. bool operator== (const SharedFontInternal& other) const noexcept
  189. {
  190. return height == other.height
  191. && underline == other.underline
  192. && horizontalScale == other.horizontalScale
  193. && kerning == other.kerning
  194. && typefaceName == other.typefaceName
  195. && typefaceStyle == other.typefaceStyle;
  196. }
  197. Typeface::Ptr typeface;
  198. String typefaceName, typefaceStyle;
  199. float height, horizontalScale = 1.0f, kerning = 0, ascent = 0;
  200. bool underline = false;
  201. };
  202. //==============================================================================
  203. Font::Font() : font (new SharedFontInternal()) {}
  204. Font::Font (const Typeface::Ptr& typeface) : font (new SharedFontInternal (typeface)) {}
  205. Font::Font (const Font& other) noexcept : font (other.font) {}
  206. Font::Font (float fontHeight, int styleFlags)
  207. : font (new SharedFontInternal (styleFlags, FontValues::limitFontHeight (fontHeight)))
  208. {
  209. }
  210. Font::Font (const String& typefaceName, float fontHeight, int styleFlags)
  211. : font (new SharedFontInternal (typefaceName, styleFlags, FontValues::limitFontHeight (fontHeight)))
  212. {
  213. }
  214. Font::Font (const String& typefaceName, const String& typefaceStyle, float fontHeight)
  215. : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight)))
  216. {
  217. }
  218. Font& Font::operator= (const Font& other) noexcept
  219. {
  220. font = other.font;
  221. return *this;
  222. }
  223. Font::Font (Font&& other) noexcept
  224. : font (static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font))
  225. {
  226. }
  227. Font& Font::operator= (Font&& other) noexcept
  228. {
  229. font = static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font);
  230. return *this;
  231. }
  232. Font::~Font() noexcept
  233. {
  234. }
  235. bool Font::operator== (const Font& other) const noexcept
  236. {
  237. return font == other.font
  238. || *font == *other.font;
  239. }
  240. bool Font::operator!= (const Font& other) const noexcept
  241. {
  242. return ! operator== (other);
  243. }
  244. void Font::dupeInternalIfShared()
  245. {
  246. if (font->getReferenceCount() > 1)
  247. font = new SharedFontInternal (*font);
  248. }
  249. void Font::checkTypefaceSuitability()
  250. {
  251. if (font->typeface != nullptr && ! font->typeface->isSuitableForFont (*this))
  252. font->typeface = nullptr;
  253. }
  254. //==============================================================================
  255. struct FontPlaceholderNames
  256. {
  257. String sans { "<Sans-Serif>" },
  258. serif { "<Serif>" },
  259. mono { "<Monospaced>" },
  260. regular { "<Regular>" };
  261. };
  262. const FontPlaceholderNames& getFontPlaceholderNames()
  263. {
  264. static FontPlaceholderNames names;
  265. return names;
  266. }
  267. #if JUCE_MSVC
  268. // This is a workaround for the lack of thread-safety in MSVC's handling of function-local
  269. // statics - if multiple threads all try to create the first Font object at the same time,
  270. // it can cause a race-condition in creating these placeholder strings.
  271. struct FontNamePreloader { FontNamePreloader() { getFontPlaceholderNames(); } };
  272. static FontNamePreloader fnp;
  273. #endif
  274. const String& Font::getDefaultSansSerifFontName() { return getFontPlaceholderNames().sans; }
  275. const String& Font::getDefaultSerifFontName() { return getFontPlaceholderNames().serif; }
  276. const String& Font::getDefaultMonospacedFontName() { return getFontPlaceholderNames().mono; }
  277. const String& Font::getDefaultStyle() { return getFontPlaceholderNames().regular; }
  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. auto flags = getStyleFlags();
  481. setStyleFlags (shouldBeBold ? (flags | bold)
  482. : (flags & ~bold));
  483. }
  484. void Font::setItalic (const bool shouldBeItalic)
  485. {
  486. auto 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.0f)
  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 (int) std::ceil (getStringWidthFloat (text));
  510. }
  511. float Font::getStringWidthFloat (const String& text) const
  512. {
  513. // This call isn't thread-safe when there's a message thread running
  514. jassert (MessageManager::getInstanceWithoutCreating() == nullptr
  515. || MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager());
  516. auto w = getTypeface()->getStringWidth (text);
  517. if (font->kerning != 0.0f)
  518. w += font->kerning * text.length();
  519. return w * font->height * font->horizontalScale;
  520. }
  521. void Font::getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const
  522. {
  523. // This call isn't thread-safe when there's a message thread running
  524. jassert (MessageManager::getInstanceWithoutCreating() == nullptr
  525. || MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager());
  526. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  527. if (auto num = xOffsets.size())
  528. {
  529. auto scale = font->height * font->horizontalScale;
  530. auto* x = xOffsets.getRawDataPointer();
  531. if (font->kerning != 0.0f)
  532. {
  533. for (int i = 0; i < num; ++i)
  534. x[i] = (x[i] + i * font->kerning) * scale;
  535. }
  536. else
  537. {
  538. for (int i = 0; i < num; ++i)
  539. x[i] *= scale;
  540. }
  541. }
  542. }
  543. void Font::findFonts (Array<Font>& destArray)
  544. {
  545. for (auto& name : findAllTypefaceNames())
  546. {
  547. auto styles = findAllTypefaceStyles (name);
  548. String style ("Regular");
  549. if (! styles.contains (style, true))
  550. style = styles[0];
  551. destArray.add (Font (name, style, FontValues::defaultFontHeight));
  552. }
  553. }
  554. //==============================================================================
  555. String Font::toString() const
  556. {
  557. String s;
  558. if (getTypefaceName() != getDefaultSansSerifFontName())
  559. s << getTypefaceName() << "; ";
  560. s << String (getHeight(), 1);
  561. if (getTypefaceStyle() != getDefaultStyle())
  562. s << ' ' << getTypefaceStyle();
  563. return s;
  564. }
  565. Font Font::fromString (const String& fontDescription)
  566. {
  567. const int separator = fontDescription.indexOfChar (';');
  568. String name;
  569. if (separator > 0)
  570. name = fontDescription.substring (0, separator).trim();
  571. if (name.isEmpty())
  572. name = getDefaultSansSerifFontName();
  573. String sizeAndStyle (fontDescription.substring (separator + 1).trimStart());
  574. float height = sizeAndStyle.getFloatValue();
  575. if (height <= 0)
  576. height = 10.0f;
  577. const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false));
  578. return Font (name, style, height);
  579. }