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.

709 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<size_t>::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& typefaceName, const String& typefaceStyle, float fontHeight)
  223. : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight), false))
  224. {
  225. }
  226. Font::Font (const Typeface::Ptr& typeface)
  227. : font (new SharedFontInternal (typeface))
  228. {
  229. }
  230. Font::Font (const Font& other) noexcept
  231. : font (other.font)
  232. {
  233. }
  234. Font& Font::operator= (const Font& other) noexcept
  235. {
  236. font = other.font;
  237. return *this;
  238. }
  239. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  240. Font::Font (Font&& other) noexcept
  241. : font (static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font))
  242. {
  243. }
  244. Font& Font::operator= (Font&& other) noexcept
  245. {
  246. font = static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font);
  247. return *this;
  248. }
  249. #endif
  250. Font::~Font() noexcept
  251. {
  252. }
  253. bool Font::operator== (const Font& other) const noexcept
  254. {
  255. return font == other.font
  256. || *font == *other.font;
  257. }
  258. bool Font::operator!= (const Font& other) const noexcept
  259. {
  260. return ! operator== (other);
  261. }
  262. void Font::dupeInternalIfShared()
  263. {
  264. if (font->getReferenceCount() > 1)
  265. font = new SharedFontInternal (*font);
  266. }
  267. //==============================================================================
  268. const String& Font::getDefaultSansSerifFontName()
  269. {
  270. static const String name ("<Sans-Serif>");
  271. return name;
  272. }
  273. const String& Font::getDefaultSerifFontName()
  274. {
  275. static const String name ("<Serif>");
  276. return name;
  277. }
  278. const String& Font::getDefaultMonospacedFontName()
  279. {
  280. static const String name ("<Monospaced>");
  281. return name;
  282. }
  283. const String& Font::getDefaultStyle()
  284. {
  285. static const String style ("<Regular>");
  286. return style;
  287. }
  288. const String& Font::getTypefaceName() const noexcept
  289. {
  290. return font->typefaceName;
  291. }
  292. void Font::setTypefaceName (const String& faceName)
  293. {
  294. if (faceName != font->typefaceName)
  295. {
  296. jassert (faceName.isNotEmpty());
  297. dupeInternalIfShared();
  298. font->typefaceName = faceName;
  299. font->typeface = nullptr;
  300. font->ascent = 0;
  301. }
  302. }
  303. const String& Font::getTypefaceStyle() const noexcept
  304. {
  305. return font->typefaceStyle;
  306. }
  307. void Font::setTypefaceStyle (const String& typefaceStyle)
  308. {
  309. if (typefaceStyle != font->typefaceStyle)
  310. {
  311. dupeInternalIfShared();
  312. font->typefaceStyle = typefaceStyle;
  313. font->typeface = nullptr;
  314. font->ascent = 0;
  315. }
  316. }
  317. Font Font::withTypefaceStyle (const String& newStyle) const
  318. {
  319. Font f (*this);
  320. f.setTypefaceStyle (newStyle);
  321. return f;
  322. }
  323. StringArray Font::getAvailableStyles() const
  324. {
  325. return findAllTypefaceStyles (getTypeface()->getName());
  326. }
  327. Typeface* Font::getTypeface() const
  328. {
  329. if (font->typeface == nullptr)
  330. font->typeface = TypefaceCache::getInstance()->findTypefaceFor (*this);
  331. return font->typeface;
  332. }
  333. //==============================================================================
  334. const String& Font::getFallbackFontName()
  335. {
  336. return FontValues::fallbackFont;
  337. }
  338. void Font::setFallbackFontName (const String& name)
  339. {
  340. FontValues::fallbackFont = name;
  341. #if JUCE_MAC || JUCE_IOS
  342. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  343. #endif
  344. }
  345. const String& Font::getFallbackFontStyle()
  346. {
  347. return FontValues::fallbackFontStyle;
  348. }
  349. void Font::setFallbackFontStyle (const String& style)
  350. {
  351. FontValues::fallbackFontStyle = style;
  352. #if JUCE_MAC || JUCE_IOS
  353. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  354. #endif
  355. }
  356. //==============================================================================
  357. float Font::getHeight() const noexcept
  358. {
  359. return font->height;
  360. }
  361. Font Font::withHeight (const float newHeight) const
  362. {
  363. Font f (*this);
  364. f.setHeight (newHeight);
  365. return f;
  366. }
  367. void Font::setHeight (float newHeight)
  368. {
  369. newHeight = FontValues::limitFontHeight (newHeight);
  370. if (font->height != newHeight)
  371. {
  372. dupeInternalIfShared();
  373. font->height = newHeight;
  374. }
  375. }
  376. void Font::setHeightWithoutChangingWidth (float newHeight)
  377. {
  378. newHeight = FontValues::limitFontHeight (newHeight);
  379. if (font->height != newHeight)
  380. {
  381. dupeInternalIfShared();
  382. font->horizontalScale *= (font->height / newHeight);
  383. font->height = newHeight;
  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->typefaceStyle = FontStyleHelpers::getStyleName (newFlags);
  405. font->underline = (newFlags & underlined) != 0;
  406. font->typeface = nullptr;
  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. }
  425. setStyleFlags (newStyleFlags);
  426. }
  427. void Font::setSizeAndStyle (float newHeight,
  428. const String& newStyle,
  429. const float newHorizontalScale,
  430. const float newKerningAmount)
  431. {
  432. newHeight = FontValues::limitFontHeight (newHeight);
  433. if (font->height != newHeight
  434. || font->horizontalScale != newHorizontalScale
  435. || font->kerning != newKerningAmount)
  436. {
  437. dupeInternalIfShared();
  438. font->height = newHeight;
  439. font->horizontalScale = newHorizontalScale;
  440. font->kerning = newKerningAmount;
  441. }
  442. setTypefaceStyle (newStyle);
  443. }
  444. float Font::getHorizontalScale() const noexcept
  445. {
  446. return font->horizontalScale;
  447. }
  448. Font Font::withHorizontalScale (const float newHorizontalScale) const
  449. {
  450. Font f (*this);
  451. f.setHorizontalScale (newHorizontalScale);
  452. return f;
  453. }
  454. void Font::setHorizontalScale (const float scaleFactor)
  455. {
  456. dupeInternalIfShared();
  457. font->horizontalScale = scaleFactor;
  458. }
  459. float Font::getExtraKerningFactor() const noexcept
  460. {
  461. return font->kerning;
  462. }
  463. Font Font::withExtraKerningFactor (const float extraKerning) const
  464. {
  465. Font f (*this);
  466. f.setExtraKerningFactor (extraKerning);
  467. return f;
  468. }
  469. void Font::setExtraKerningFactor (const float extraKerning)
  470. {
  471. dupeInternalIfShared();
  472. font->kerning = extraKerning;
  473. }
  474. Font Font::boldened() const { return withStyle (getStyleFlags() | bold); }
  475. Font Font::italicised() const { return withStyle (getStyleFlags() | italic); }
  476. bool Font::isBold() const noexcept { return FontStyleHelpers::isBold (font->typefaceStyle); }
  477. bool Font::isItalic() const noexcept { return FontStyleHelpers::isItalic (font->typefaceStyle); }
  478. void Font::setBold (const bool shouldBeBold)
  479. {
  480. const int flags = getStyleFlags();
  481. setStyleFlags (shouldBeBold ? (flags | bold)
  482. : (flags & ~bold));
  483. }
  484. void Font::setItalic (const bool shouldBeItalic)
  485. {
  486. const int 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. }
  495. bool Font::isUnderlined() const noexcept
  496. {
  497. return font->underline;
  498. }
  499. float Font::getAscent() const
  500. {
  501. if (font->ascent == 0)
  502. font->ascent = getTypeface()->getAscent();
  503. return font->height * font->ascent;
  504. }
  505. float Font::getDescent() const
  506. {
  507. return font->height - getAscent();
  508. }
  509. int Font::getStringWidth (const String& text) const
  510. {
  511. return roundToInt (getStringWidthFloat (text));
  512. }
  513. float Font::getStringWidthFloat (const String& text) const
  514. {
  515. float w = getTypeface()->getStringWidth (text);
  516. if (font->kerning != 0)
  517. w += font->kerning * text.length();
  518. return w * font->height * font->horizontalScale;
  519. }
  520. void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const
  521. {
  522. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  523. const int num = xOffsets.size();
  524. if (num > 0)
  525. {
  526. const float scale = font->height * font->horizontalScale;
  527. float* const x = xOffsets.getRawDataPointer();
  528. if (font->kerning != 0)
  529. {
  530. for (int i = 0; i < num; ++i)
  531. x[i] = (x[i] + i * font->kerning) * scale;
  532. }
  533. else
  534. {
  535. for (int i = 0; i < num; ++i)
  536. x[i] *= scale;
  537. }
  538. }
  539. }
  540. void Font::findFonts (Array<Font>& destArray)
  541. {
  542. const StringArray names (findAllTypefaceNames());
  543. for (int i = 0; i < names.size(); ++i)
  544. {
  545. const StringArray styles (findAllTypefaceStyles (names[i]));
  546. String style ("Regular");
  547. if (! styles.contains (style, true))
  548. style = styles[0];
  549. destArray.add (Font (names[i], style, FontValues::defaultFontHeight));
  550. }
  551. }
  552. //==============================================================================
  553. String Font::toString() const
  554. {
  555. String s;
  556. if (getTypefaceName() != getDefaultSansSerifFontName())
  557. s << getTypefaceName() << "; ";
  558. s << String (getHeight(), 1);
  559. if (getTypefaceStyle() != getDefaultStyle())
  560. s << ' ' << getTypefaceStyle();
  561. return s;
  562. }
  563. Font Font::fromString (const String& fontDescription)
  564. {
  565. const int separator = fontDescription.indexOfChar (';');
  566. String name;
  567. if (separator > 0)
  568. name = fontDescription.substring (0, separator).trim();
  569. if (name.isEmpty())
  570. name = getDefaultSansSerifFontName();
  571. String sizeAndStyle (fontDescription.substring (separator + 1).trimStart());
  572. float height = sizeAndStyle.getFloatValue();
  573. if (height <= 0)
  574. height = 10.0f;
  575. const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false));
  576. return Font (name, style, height);
  577. }