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.

693 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 : public 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. Typeface::Ptr findTypefaceFor (const Font& font)
  50. {
  51. const String faceName (font.getTypefaceName());
  52. const String faceStyle (font.getTypefaceStyle());
  53. jassert (faceName.isNotEmpty());
  54. for (int i = faces.size(); --i >= 0;)
  55. {
  56. CachedFace& face = faces.getReference(i);
  57. if (face.typefaceName == faceName
  58. && face.typefaceStyle == faceStyle
  59. && face.typeface != nullptr
  60. && face.typeface->isSuitableForFont (font))
  61. {
  62. face.lastUsageCount = ++counter;
  63. return face.typeface;
  64. }
  65. }
  66. int replaceIndex = 0;
  67. size_t bestLastUsageCount = std::numeric_limits<int>::max();
  68. for (int i = faces.size(); --i >= 0;)
  69. {
  70. const size_t lu = faces.getReference(i).lastUsageCount;
  71. if (bestLastUsageCount > lu)
  72. {
  73. bestLastUsageCount = lu;
  74. replaceIndex = i;
  75. }
  76. }
  77. CachedFace& face = faces.getReference (replaceIndex);
  78. face.typefaceName = faceName;
  79. face.typefaceStyle = faceStyle;
  80. face.lastUsageCount = ++counter;
  81. if (juce_getTypefaceForFont == nullptr)
  82. face.typeface = Font::getDefaultTypefaceForFont (font);
  83. else
  84. face.typeface = juce_getTypefaceForFont (font);
  85. jassert (face.typeface != nullptr); // the look and feel must return a typeface!
  86. if (defaultFace == nullptr && font == Font())
  87. defaultFace = face.typeface;
  88. return face.typeface;
  89. }
  90. Typeface::Ptr getDefaultTypeface() const noexcept
  91. {
  92. return defaultFace;
  93. }
  94. private:
  95. struct CachedFace
  96. {
  97. CachedFace() noexcept
  98. : lastUsageCount (0)
  99. {
  100. }
  101. // Although it seems a bit wacky to store the name here, it's because it may be a
  102. // placeholder rather than a real one, e.g. "<Sans-Serif>" vs the actual typeface name.
  103. // Since the typeface itself doesn't know that it may have this alias, the name under
  104. // which it was fetched needs to be stored separately.
  105. String typefaceName;
  106. String typefaceStyle;
  107. size_t lastUsageCount;
  108. Typeface::Ptr typeface;
  109. };
  110. Array <CachedFace> faces;
  111. Typeface::Ptr defaultFace;
  112. size_t counter;
  113. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache);
  114. };
  115. juce_ImplementSingleton_SingleThreaded (TypefaceCache)
  116. void Typeface::setTypefaceCacheSize (int numFontsToCache)
  117. {
  118. TypefaceCache::getInstance()->setSize (numFontsToCache);
  119. }
  120. //==============================================================================
  121. class Font::SharedFontInternal : public SingleThreadedReferenceCountedObject
  122. {
  123. public:
  124. SharedFontInternal (const String& typefaceStyle_, const float height_) noexcept
  125. : typefaceName (Font::getDefaultSansSerifFontName()),
  126. typefaceStyle (typefaceStyle_),
  127. height (height_),
  128. horizontalScale (1.0f),
  129. kerning (0),
  130. ascent (0),
  131. underline (false),
  132. typeface (typefaceStyle_ == Font::getDefaultStyle()
  133. ? TypefaceCache::getInstance()->getDefaultTypeface() : nullptr)
  134. {
  135. }
  136. SharedFontInternal (const String& typefaceName_, const String& typefaceStyle_, const float height_) noexcept
  137. : typefaceName (typefaceName_),
  138. typefaceStyle (typefaceStyle_),
  139. height (height_),
  140. horizontalScale (1.0f),
  141. kerning (0),
  142. ascent (0),
  143. underline (false),
  144. typeface (nullptr)
  145. {
  146. if (typefaceName.isEmpty())
  147. typefaceName = Font::getDefaultSansSerifFontName();
  148. }
  149. SharedFontInternal (const Typeface::Ptr& typeface_) noexcept
  150. : typefaceName (typeface_->getName()),
  151. typefaceStyle (typeface_->getStyle()),
  152. height (FontValues::defaultFontHeight),
  153. horizontalScale (1.0f),
  154. kerning (0),
  155. ascent (0),
  156. underline (false),
  157. typeface (typeface_)
  158. {
  159. jassert (typefaceName.isNotEmpty());
  160. }
  161. SharedFontInternal (const SharedFontInternal& other) noexcept
  162. : typefaceName (other.typefaceName),
  163. typefaceStyle (other.typefaceStyle),
  164. height (other.height),
  165. horizontalScale (other.horizontalScale),
  166. kerning (other.kerning),
  167. ascent (other.ascent),
  168. underline (other.underline),
  169. typeface (other.typeface)
  170. {
  171. }
  172. bool operator== (const SharedFontInternal& other) const noexcept
  173. {
  174. return height == other.height
  175. && underline == other.underline
  176. && horizontalScale == other.horizontalScale
  177. && kerning == other.kerning
  178. && typefaceName == other.typefaceName
  179. && typefaceStyle == other.typefaceStyle;
  180. }
  181. String typefaceName, typefaceStyle;
  182. float height, horizontalScale, kerning, ascent;
  183. bool underline;
  184. Typeface::Ptr typeface;
  185. };
  186. //==============================================================================
  187. Font::Font()
  188. : font (new SharedFontInternal (Font::getDefaultStyle(), FontValues::defaultFontHeight))
  189. {
  190. }
  191. Font::Font (const float fontHeight, const int styleFlags)
  192. : font (new SharedFontInternal (Font::getDefaultStyle(), FontValues::limitFontHeight (fontHeight)))
  193. {
  194. setStyleFlags (styleFlags);
  195. }
  196. Font::Font (const String& typefaceName, const float fontHeight, const int styleFlags)
  197. : font (new SharedFontInternal (typefaceName,
  198. FontStyleHelpers::getStyleName ((styleFlags & bold) != 0,
  199. (styleFlags & italic) != 0),
  200. FontValues::limitFontHeight (fontHeight)))
  201. {
  202. setStyleFlags (styleFlags);
  203. }
  204. Font::Font (const String& typefaceStyle, float fontHeight)
  205. : font (new SharedFontInternal (typefaceStyle, FontValues::limitFontHeight (fontHeight)))
  206. {
  207. }
  208. Font::Font (const String& typefaceName, const String& typefaceStyle, float fontHeight)
  209. : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight)))
  210. {
  211. }
  212. Font::Font (const Typeface::Ptr& typeface)
  213. : font (new SharedFontInternal (typeface))
  214. {
  215. }
  216. Font::Font (const Font& other) noexcept
  217. : font (other.font)
  218. {
  219. }
  220. Font& Font::operator= (const Font& other) noexcept
  221. {
  222. font = other.font;
  223. return *this;
  224. }
  225. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  226. Font::Font (Font&& other) noexcept
  227. : font (static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font))
  228. {
  229. }
  230. Font& Font::operator= (Font&& other) noexcept
  231. {
  232. font = static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font);
  233. return *this;
  234. }
  235. #endif
  236. Font::~Font() noexcept
  237. {
  238. }
  239. bool Font::operator== (const Font& other) const noexcept
  240. {
  241. return font == other.font
  242. || *font == *other.font;
  243. }
  244. bool Font::operator!= (const Font& other) const noexcept
  245. {
  246. return ! operator== (other);
  247. }
  248. void Font::dupeInternalIfShared()
  249. {
  250. if (font->getReferenceCount() > 1)
  251. font = new SharedFontInternal (*font);
  252. }
  253. //==============================================================================
  254. const String& Font::getDefaultSansSerifFontName()
  255. {
  256. static const String name ("<Sans-Serif>");
  257. return name;
  258. }
  259. const String& Font::getDefaultSerifFontName()
  260. {
  261. static const String name ("<Serif>");
  262. return name;
  263. }
  264. const String& Font::getDefaultMonospacedFontName()
  265. {
  266. static const String name ("<Monospaced>");
  267. return name;
  268. }
  269. const String& Font::getDefaultStyle()
  270. {
  271. static const String style ("<Regular>");
  272. return style;
  273. }
  274. const String& Font::getTypefaceName() const noexcept
  275. {
  276. return font->typefaceName;
  277. }
  278. void Font::setTypefaceName (const String& faceName)
  279. {
  280. if (faceName != font->typefaceName)
  281. {
  282. jassert (faceName.isNotEmpty());
  283. dupeInternalIfShared();
  284. font->typefaceName = faceName;
  285. font->typeface = nullptr;
  286. font->ascent = 0;
  287. }
  288. }
  289. const String& Font::getTypefaceStyle() const noexcept
  290. {
  291. return font->typefaceStyle;
  292. }
  293. void Font::setTypefaceStyle (const String& typefaceStyle)
  294. {
  295. if (typefaceStyle != font->typefaceStyle)
  296. {
  297. dupeInternalIfShared();
  298. font->typefaceStyle = typefaceStyle;
  299. font->typeface = nullptr;
  300. font->ascent = 0;
  301. }
  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. font->typeface = TypefaceCache::getInstance()->findTypefaceFor (*this);
  311. return font->typeface;
  312. }
  313. //==============================================================================
  314. const String& Font::getFallbackFontName()
  315. {
  316. return FontValues::fallbackFont;
  317. }
  318. void Font::setFallbackFontName (const String& name)
  319. {
  320. FontValues::fallbackFont = name;
  321. #if JUCE_MAC || JUCE_IOS
  322. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  323. #endif
  324. }
  325. const String& Font::getFallbackFontStyle()
  326. {
  327. return FontValues::fallbackFontStyle;
  328. }
  329. void Font::setFallbackFontStyle (const String& style)
  330. {
  331. FontValues::fallbackFontStyle = style;
  332. #if JUCE_MAC || JUCE_IOS
  333. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  334. #endif
  335. }
  336. //==============================================================================
  337. float Font::getHeight() const noexcept
  338. {
  339. return font->height;
  340. }
  341. Font Font::withHeight (const float newHeight) const
  342. {
  343. Font f (*this);
  344. f.setHeight (newHeight);
  345. return f;
  346. }
  347. void Font::setHeight (float newHeight)
  348. {
  349. newHeight = FontValues::limitFontHeight (newHeight);
  350. if (font->height != newHeight)
  351. {
  352. dupeInternalIfShared();
  353. font->height = newHeight;
  354. }
  355. }
  356. void Font::setHeightWithoutChangingWidth (float newHeight)
  357. {
  358. newHeight = FontValues::limitFontHeight (newHeight);
  359. if (font->height != newHeight)
  360. {
  361. dupeInternalIfShared();
  362. font->horizontalScale *= (font->height / newHeight);
  363. font->height = newHeight;
  364. }
  365. }
  366. int Font::getStyleFlags() const noexcept
  367. {
  368. int styleFlags = font->underline ? underlined : plain;
  369. if (isBold()) styleFlags |= bold;
  370. if (isItalic()) styleFlags |= italic;
  371. return styleFlags;
  372. }
  373. Font Font::withStyle (const int newFlags) const
  374. {
  375. Font f (*this);
  376. f.setStyleFlags (newFlags);
  377. return f;
  378. }
  379. void Font::setStyleFlags (const int newFlags)
  380. {
  381. if (getStyleFlags() != newFlags)
  382. {
  383. dupeInternalIfShared();
  384. font->typefaceStyle = FontStyleHelpers::getStyleName ((newFlags & bold) != 0,
  385. (newFlags & italic) != 0);
  386. font->underline = (newFlags & underlined) != 0;
  387. font->typeface = nullptr;
  388. font->ascent = 0;
  389. }
  390. }
  391. void Font::setSizeAndStyle (float newHeight,
  392. const int newStyleFlags,
  393. const float newHorizontalScale,
  394. const float newKerningAmount)
  395. {
  396. newHeight = FontValues::limitFontHeight (newHeight);
  397. if (font->height != newHeight
  398. || font->horizontalScale != newHorizontalScale
  399. || font->kerning != newKerningAmount)
  400. {
  401. dupeInternalIfShared();
  402. font->height = newHeight;
  403. font->horizontalScale = newHorizontalScale;
  404. font->kerning = newKerningAmount;
  405. }
  406. setStyleFlags (newStyleFlags);
  407. }
  408. void Font::setSizeAndStyle (float newHeight,
  409. const String& newStyle,
  410. const float newHorizontalScale,
  411. const float newKerningAmount)
  412. {
  413. newHeight = FontValues::limitFontHeight (newHeight);
  414. if (font->height != newHeight
  415. || font->horizontalScale != newHorizontalScale
  416. || font->kerning != newKerningAmount)
  417. {
  418. dupeInternalIfShared();
  419. font->height = newHeight;
  420. font->horizontalScale = newHorizontalScale;
  421. font->kerning = newKerningAmount;
  422. }
  423. setTypefaceStyle (newStyle);
  424. }
  425. float Font::getHorizontalScale() const noexcept
  426. {
  427. return font->horizontalScale;
  428. }
  429. Font Font::withHorizontalScale (const float newHorizontalScale) const
  430. {
  431. Font f (*this);
  432. f.setHorizontalScale (newHorizontalScale);
  433. return f;
  434. }
  435. void Font::setHorizontalScale (const float scaleFactor)
  436. {
  437. dupeInternalIfShared();
  438. font->horizontalScale = scaleFactor;
  439. }
  440. float Font::getExtraKerningFactor() const noexcept
  441. {
  442. return font->kerning;
  443. }
  444. Font Font::withExtraKerningFactor (const float extraKerning) const
  445. {
  446. Font f (*this);
  447. f.setExtraKerningFactor (extraKerning);
  448. return f;
  449. }
  450. void Font::setExtraKerningFactor (const float extraKerning)
  451. {
  452. dupeInternalIfShared();
  453. font->kerning = extraKerning;
  454. }
  455. Font Font::boldened() const { return withStyle (getStyleFlags() | bold); }
  456. Font Font::italicised() const { return withStyle (getStyleFlags() | italic); }
  457. bool Font::isBold() const noexcept
  458. {
  459. return FontStyleHelpers::isBold (font->typefaceStyle);
  460. }
  461. bool Font::isItalic() const noexcept
  462. {
  463. return FontStyleHelpers::isItalic (font->typefaceStyle);
  464. }
  465. void Font::setBold (const bool shouldBeBold)
  466. {
  467. const int flags = getStyleFlags();
  468. setStyleFlags (shouldBeBold ? (flags | bold)
  469. : (flags & ~bold));
  470. }
  471. void Font::setItalic (const bool shouldBeItalic)
  472. {
  473. const int flags = getStyleFlags();
  474. setStyleFlags (shouldBeItalic ? (flags | italic)
  475. : (flags & ~italic));
  476. }
  477. void Font::setUnderline (const bool shouldBeUnderlined)
  478. {
  479. font->underline = shouldBeUnderlined;
  480. }
  481. bool Font::isUnderlined() const noexcept
  482. {
  483. return font->underline;
  484. }
  485. float Font::getAscent() const
  486. {
  487. if (font->ascent == 0)
  488. font->ascent = getTypeface()->getAscent();
  489. return font->height * font->ascent;
  490. }
  491. float Font::getDescent() const
  492. {
  493. return font->height - getAscent();
  494. }
  495. int Font::getStringWidth (const String& text) const
  496. {
  497. return roundToInt (getStringWidthFloat (text));
  498. }
  499. float Font::getStringWidthFloat (const String& text) const
  500. {
  501. float w = getTypeface()->getStringWidth (text);
  502. if (font->kerning != 0)
  503. w += font->kerning * text.length();
  504. return w * font->height * font->horizontalScale;
  505. }
  506. void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const
  507. {
  508. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  509. const int num = xOffsets.size();
  510. if (num > 0)
  511. {
  512. const float scale = font->height * font->horizontalScale;
  513. float* const x = xOffsets.getRawDataPointer();
  514. if (font->kerning != 0)
  515. {
  516. for (int i = 0; i < num; ++i)
  517. x[i] = (x[i] + i * font->kerning) * scale;
  518. }
  519. else
  520. {
  521. for (int i = 0; i < num; ++i)
  522. x[i] *= scale;
  523. }
  524. }
  525. }
  526. void Font::findFonts (Array<Font>& destArray)
  527. {
  528. const StringArray names (findAllTypefaceNames());
  529. for (int i = 0; i < names.size(); ++i)
  530. {
  531. const StringArray styles (findAllTypefaceStyles (names[i]));
  532. String style ("Regular");
  533. if (! styles.contains (style, true))
  534. style = styles[0];
  535. destArray.add (Font (names[i], style, FontValues::defaultFontHeight));
  536. }
  537. }
  538. //==============================================================================
  539. String Font::toString() const
  540. {
  541. String s;
  542. if (getTypefaceName() != getDefaultSansSerifFontName())
  543. s << getTypefaceName() << "; ";
  544. s << String (getHeight(), 1);
  545. if (getTypefaceStyle() != getDefaultStyle())
  546. s << ' ' << getTypefaceStyle();
  547. return s;
  548. }
  549. Font Font::fromString (const String& fontDescription)
  550. {
  551. const int separator = fontDescription.indexOfChar (';');
  552. String name;
  553. if (separator > 0)
  554. name = fontDescription.substring (0, separator).trim();
  555. if (name.isEmpty())
  556. name = getDefaultSansSerifFontName();
  557. String sizeAndStyle (fontDescription.substring (separator + 1));
  558. float height = sizeAndStyle.getFloatValue();
  559. if (height <= 0)
  560. height = 10.0f;
  561. const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false));
  562. return Font (name, style, height);
  563. }