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.

720 lines
21KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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. float minimumHorizontalScale = 0.7f;
  25. String fallbackFont;
  26. String fallbackFontStyle;
  27. }
  28. typedef Typeface::Ptr (*GetTypefaceForFont) (const Font&);
  29. GetTypefaceForFont juce_getTypefaceForFont = nullptr;
  30. float Font::getDefaultMinimumHorizontalScaleFactor() noexcept { return FontValues::minimumHorizontalScale; }
  31. void Font::setDefaultMinimumHorizontalScaleFactor (float newValue) noexcept { FontValues::minimumHorizontalScale = newValue; }
  32. //==============================================================================
  33. class TypefaceCache : private DeletedAtShutdown
  34. {
  35. public:
  36. TypefaceCache() : counter (0)
  37. {
  38. setSize (10);
  39. }
  40. ~TypefaceCache()
  41. {
  42. clearSingletonInstance();
  43. }
  44. juce_DeclareSingleton (TypefaceCache, false)
  45. void setSize (const int numToCache)
  46. {
  47. const ScopedWriteLock sl (lock);
  48. faces.clear();
  49. faces.insertMultiple (-1, CachedFace(), numToCache);
  50. }
  51. void clear()
  52. {
  53. const ScopedWriteLock sl (lock);
  54. setSize (faces.size());
  55. defaultFace = nullptr;
  56. }
  57. Typeface::Ptr findTypefaceFor (const Font& font)
  58. {
  59. const ScopedReadLock slr (lock);
  60. const String faceName (font.getTypefaceName());
  61. const String faceStyle (font.getTypefaceStyle());
  62. jassert (faceName.isNotEmpty());
  63. for (int i = faces.size(); --i >= 0;)
  64. {
  65. CachedFace& face = faces.getReference(i);
  66. if (face.typefaceName == faceName
  67. && face.typefaceStyle == faceStyle
  68. && face.typeface != nullptr
  69. && face.typeface->isSuitableForFont (font))
  70. {
  71. face.lastUsageCount = ++counter;
  72. return face.typeface;
  73. }
  74. }
  75. const ScopedWriteLock slw (lock);
  76. int replaceIndex = 0;
  77. size_t bestLastUsageCount = std::numeric_limits<size_t>::max();
  78. for (int i = faces.size(); --i >= 0;)
  79. {
  80. const size_t lu = faces.getReference(i).lastUsageCount;
  81. if (bestLastUsageCount > lu)
  82. {
  83. bestLastUsageCount = lu;
  84. replaceIndex = i;
  85. }
  86. }
  87. CachedFace& face = faces.getReference (replaceIndex);
  88. face.typefaceName = faceName;
  89. face.typefaceStyle = faceStyle;
  90. face.lastUsageCount = ++counter;
  91. if (juce_getTypefaceForFont == nullptr)
  92. face.typeface = Font::getDefaultTypefaceForFont (font);
  93. else
  94. face.typeface = juce_getTypefaceForFont (font);
  95. jassert (face.typeface != nullptr); // the look and feel must return a typeface!
  96. if (defaultFace == nullptr && font == Font())
  97. defaultFace = face.typeface;
  98. return face.typeface;
  99. }
  100. Typeface::Ptr defaultFace;
  101. private:
  102. struct CachedFace
  103. {
  104. CachedFace() noexcept : lastUsageCount (0) {}
  105. // Although it seems a bit wacky to store the name here, it's because it may be a
  106. // placeholder rather than a real one, e.g. "<Sans-Serif>" vs the actual typeface name.
  107. // Since the typeface itself doesn't know that it may have this alias, the name under
  108. // which it was fetched needs to be stored separately.
  109. String typefaceName, typefaceStyle;
  110. size_t lastUsageCount;
  111. Typeface::Ptr typeface;
  112. };
  113. ReadWriteLock lock;
  114. Array<CachedFace> faces;
  115. size_t counter;
  116. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache)
  117. };
  118. juce_ImplementSingleton (TypefaceCache)
  119. void Typeface::setTypefaceCacheSize (int numFontsToCache)
  120. {
  121. TypefaceCache::getInstance()->setSize (numFontsToCache);
  122. }
  123. void (*clearOpenGLGlyphCache)() = nullptr;
  124. void Typeface::clearTypefaceCache()
  125. {
  126. TypefaceCache::getInstance()->clear();
  127. RenderingHelpers::SoftwareRendererSavedState::clearGlyphCache();
  128. if (clearOpenGLGlyphCache != nullptr)
  129. clearOpenGLGlyphCache();
  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. Font::Font (Font&& other) noexcept
  225. : font (static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font))
  226. {
  227. }
  228. Font& Font::operator= (Font&& other) noexcept
  229. {
  230. font = static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font);
  231. return *this;
  232. }
  233. Font::~Font() noexcept
  234. {
  235. }
  236. bool Font::operator== (const Font& other) const noexcept
  237. {
  238. return font == other.font
  239. || *font == *other.font;
  240. }
  241. bool Font::operator!= (const Font& other) const noexcept
  242. {
  243. return ! operator== (other);
  244. }
  245. void Font::dupeInternalIfShared()
  246. {
  247. if (font->getReferenceCount() > 1)
  248. font = new SharedFontInternal (*font);
  249. }
  250. void Font::checkTypefaceSuitability()
  251. {
  252. if (font->typeface != nullptr && ! font->typeface->isSuitableForFont (*this))
  253. font->typeface = nullptr;
  254. }
  255. //==============================================================================
  256. struct FontPlaceholderNames
  257. {
  258. FontPlaceholderNames()
  259. : sans ("<Sans-Serif>"),
  260. serif ("<Serif>"),
  261. mono ("<Monospaced>"),
  262. regular ("<Regular>")
  263. {
  264. }
  265. String sans, serif, mono, regular;
  266. };
  267. const FontPlaceholderNames& getFontPlaceholderNames()
  268. {
  269. static FontPlaceholderNames names;
  270. return names;
  271. }
  272. #if JUCE_MSVC
  273. // This is a workaround for the lack of thread-safety in MSVC's handling of function-local
  274. // statics - if multiple threads all try to create the first Font object at the same time,
  275. // it can cause a race-condition in creating these placeholder strings.
  276. struct FontNamePreloader { FontNamePreloader() { getFontPlaceholderNames(); } };
  277. static FontNamePreloader fnp;
  278. #endif
  279. const String& Font::getDefaultSansSerifFontName() { return getFontPlaceholderNames().sans; }
  280. const String& Font::getDefaultSerifFontName() { return getFontPlaceholderNames().serif; }
  281. const String& Font::getDefaultMonospacedFontName() { return getFontPlaceholderNames().mono; }
  282. const String& Font::getDefaultStyle() { return getFontPlaceholderNames().regular; }
  283. const String& Font::getTypefaceName() const noexcept { return font->typefaceName; }
  284. const String& Font::getTypefaceStyle() const noexcept { return font->typefaceStyle; }
  285. void Font::setTypefaceName (const String& faceName)
  286. {
  287. if (faceName != font->typefaceName)
  288. {
  289. jassert (faceName.isNotEmpty());
  290. dupeInternalIfShared();
  291. font->typefaceName = faceName;
  292. font->typeface = nullptr;
  293. font->ascent = 0;
  294. }
  295. }
  296. void Font::setTypefaceStyle (const String& typefaceStyle)
  297. {
  298. if (typefaceStyle != font->typefaceStyle)
  299. {
  300. dupeInternalIfShared();
  301. font->typefaceStyle = typefaceStyle;
  302. font->typeface = nullptr;
  303. font->ascent = 0;
  304. }
  305. }
  306. Font Font::withTypefaceStyle (const String& newStyle) const
  307. {
  308. Font f (*this);
  309. f.setTypefaceStyle (newStyle);
  310. return f;
  311. }
  312. StringArray Font::getAvailableStyles() const
  313. {
  314. return findAllTypefaceStyles (getTypeface()->getName());
  315. }
  316. Typeface* Font::getTypeface() const
  317. {
  318. if (font->typeface == nullptr)
  319. {
  320. font->typeface = TypefaceCache::getInstance()->findTypefaceFor (*this);
  321. jassert (font->typeface != nullptr);
  322. }
  323. return font->typeface;
  324. }
  325. //==============================================================================
  326. const String& Font::getFallbackFontName()
  327. {
  328. return FontValues::fallbackFont;
  329. }
  330. void Font::setFallbackFontName (const String& name)
  331. {
  332. FontValues::fallbackFont = name;
  333. #if JUCE_MAC || JUCE_IOS
  334. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  335. #endif
  336. }
  337. const String& Font::getFallbackFontStyle()
  338. {
  339. return FontValues::fallbackFontStyle;
  340. }
  341. void Font::setFallbackFontStyle (const String& style)
  342. {
  343. FontValues::fallbackFontStyle = style;
  344. #if JUCE_MAC || JUCE_IOS
  345. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  346. #endif
  347. }
  348. //==============================================================================
  349. Font Font::withHeight (const float newHeight) const
  350. {
  351. Font f (*this);
  352. f.setHeight (newHeight);
  353. return f;
  354. }
  355. float Font::getHeightToPointsFactor() const
  356. {
  357. return getTypeface()->getHeightToPointsFactor();
  358. }
  359. Font Font::withPointHeight (float heightInPoints) const
  360. {
  361. Font f (*this);
  362. f.setHeight (heightInPoints / getHeightToPointsFactor());
  363. return f;
  364. }
  365. void Font::setHeight (float newHeight)
  366. {
  367. newHeight = FontValues::limitFontHeight (newHeight);
  368. if (font->height != newHeight)
  369. {
  370. dupeInternalIfShared();
  371. font->height = newHeight;
  372. checkTypefaceSuitability();
  373. }
  374. }
  375. void Font::setHeightWithoutChangingWidth (float newHeight)
  376. {
  377. newHeight = FontValues::limitFontHeight (newHeight);
  378. if (font->height != newHeight)
  379. {
  380. dupeInternalIfShared();
  381. font->horizontalScale *= (font->height / newHeight);
  382. font->height = newHeight;
  383. checkTypefaceSuitability();
  384. }
  385. }
  386. int Font::getStyleFlags() const noexcept
  387. {
  388. int styleFlags = font->underline ? underlined : plain;
  389. if (isBold()) styleFlags |= bold;
  390. if (isItalic()) styleFlags |= italic;
  391. return styleFlags;
  392. }
  393. Font Font::withStyle (const int newFlags) const
  394. {
  395. Font f (*this);
  396. f.setStyleFlags (newFlags);
  397. return f;
  398. }
  399. void Font::setStyleFlags (const int newFlags)
  400. {
  401. if (getStyleFlags() != newFlags)
  402. {
  403. dupeInternalIfShared();
  404. font->typeface = nullptr;
  405. font->typefaceStyle = FontStyleHelpers::getStyleName (newFlags);
  406. font->underline = (newFlags & underlined) != 0;
  407. font->ascent = 0;
  408. }
  409. }
  410. void Font::setSizeAndStyle (float newHeight,
  411. const int newStyleFlags,
  412. const float newHorizontalScale,
  413. const float newKerningAmount)
  414. {
  415. newHeight = FontValues::limitFontHeight (newHeight);
  416. if (font->height != newHeight
  417. || font->horizontalScale != newHorizontalScale
  418. || font->kerning != newKerningAmount)
  419. {
  420. dupeInternalIfShared();
  421. font->height = newHeight;
  422. font->horizontalScale = newHorizontalScale;
  423. font->kerning = newKerningAmount;
  424. checkTypefaceSuitability();
  425. }
  426. setStyleFlags (newStyleFlags);
  427. }
  428. void Font::setSizeAndStyle (float newHeight,
  429. const String& newStyle,
  430. const float newHorizontalScale,
  431. const float newKerningAmount)
  432. {
  433. newHeight = FontValues::limitFontHeight (newHeight);
  434. if (font->height != newHeight
  435. || font->horizontalScale != newHorizontalScale
  436. || font->kerning != newKerningAmount)
  437. {
  438. dupeInternalIfShared();
  439. font->height = newHeight;
  440. font->horizontalScale = newHorizontalScale;
  441. font->kerning = newKerningAmount;
  442. checkTypefaceSuitability();
  443. }
  444. setTypefaceStyle (newStyle);
  445. }
  446. Font Font::withHorizontalScale (const float newHorizontalScale) const
  447. {
  448. Font f (*this);
  449. f.setHorizontalScale (newHorizontalScale);
  450. return f;
  451. }
  452. void Font::setHorizontalScale (const float scaleFactor)
  453. {
  454. dupeInternalIfShared();
  455. font->horizontalScale = scaleFactor;
  456. checkTypefaceSuitability();
  457. }
  458. float Font::getHorizontalScale() const noexcept
  459. {
  460. return font->horizontalScale;
  461. }
  462. float Font::getExtraKerningFactor() const noexcept
  463. {
  464. return font->kerning;
  465. }
  466. Font Font::withExtraKerningFactor (const float extraKerning) const
  467. {
  468. Font f (*this);
  469. f.setExtraKerningFactor (extraKerning);
  470. return f;
  471. }
  472. void Font::setExtraKerningFactor (const float extraKerning)
  473. {
  474. dupeInternalIfShared();
  475. font->kerning = extraKerning;
  476. checkTypefaceSuitability();
  477. }
  478. Font Font::boldened() const { return withStyle (getStyleFlags() | bold); }
  479. Font Font::italicised() const { return withStyle (getStyleFlags() | italic); }
  480. bool Font::isBold() const noexcept { return FontStyleHelpers::isBold (font->typefaceStyle); }
  481. bool Font::isItalic() const noexcept { return FontStyleHelpers::isItalic (font->typefaceStyle); }
  482. bool Font::isUnderlined() const noexcept { return font->underline; }
  483. void Font::setBold (const bool shouldBeBold)
  484. {
  485. const int flags = getStyleFlags();
  486. setStyleFlags (shouldBeBold ? (flags | bold)
  487. : (flags & ~bold));
  488. }
  489. void Font::setItalic (const bool shouldBeItalic)
  490. {
  491. const int flags = getStyleFlags();
  492. setStyleFlags (shouldBeItalic ? (flags | italic)
  493. : (flags & ~italic));
  494. }
  495. void Font::setUnderline (const bool shouldBeUnderlined)
  496. {
  497. dupeInternalIfShared();
  498. font->underline = shouldBeUnderlined;
  499. checkTypefaceSuitability();
  500. }
  501. float Font::getAscent() const
  502. {
  503. if (font->ascent == 0)
  504. font->ascent = getTypeface()->getAscent();
  505. return font->height * font->ascent;
  506. }
  507. float Font::getHeight() const noexcept { return font->height; }
  508. float Font::getDescent() const { return font->height - getAscent(); }
  509. float Font::getHeightInPoints() const { return getHeight() * getHeightToPointsFactor(); }
  510. float Font::getAscentInPoints() const { return getAscent() * getHeightToPointsFactor(); }
  511. float Font::getDescentInPoints() const { return getDescent() * getHeightToPointsFactor(); }
  512. int Font::getStringWidth (const String& text) const
  513. {
  514. return (int) std::ceil (getStringWidthFloat (text));
  515. }
  516. float Font::getStringWidthFloat (const String& text) const
  517. {
  518. float w = getTypeface()->getStringWidth (text);
  519. if (font->kerning != 0)
  520. w += font->kerning * text.length();
  521. return w * font->height * font->horizontalScale;
  522. }
  523. void Font::getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const
  524. {
  525. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  526. const int num = xOffsets.size();
  527. if (num > 0)
  528. {
  529. const float scale = font->height * font->horizontalScale;
  530. float* const x = xOffsets.getRawDataPointer();
  531. if (font->kerning != 0)
  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. const StringArray names (findAllTypefaceNames());
  546. for (int i = 0; i < names.size(); ++i)
  547. {
  548. const StringArray styles (findAllTypefaceStyles (names[i]));
  549. String style ("Regular");
  550. if (! styles.contains (style, true))
  551. style = styles[0];
  552. destArray.add (Font (names[i], style, FontValues::defaultFontHeight));
  553. }
  554. }
  555. //==============================================================================
  556. String Font::toString() const
  557. {
  558. String s;
  559. if (getTypefaceName() != getDefaultSansSerifFontName())
  560. s << getTypefaceName() << "; ";
  561. s << String (getHeight(), 1);
  562. if (getTypefaceStyle() != getDefaultStyle())
  563. s << ' ' << getTypefaceStyle();
  564. return s;
  565. }
  566. Font Font::fromString (const String& fontDescription)
  567. {
  568. const int separator = fontDescription.indexOfChar (';');
  569. String name;
  570. if (separator > 0)
  571. name = fontDescription.substring (0, separator).trim();
  572. if (name.isEmpty())
  573. name = getDefaultSansSerifFontName();
  574. String sizeAndStyle (fontDescription.substring (separator + 1).trimStart());
  575. float height = sizeAndStyle.getFloatValue();
  576. if (height <= 0)
  577. height = 10.0f;
  578. const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false));
  579. return Font (name, style, height);
  580. }