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.

714 lines
19KB

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