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.

708 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. void clear()
  50. {
  51. setSize (faces.size());
  52. }
  53. Typeface::Ptr findTypefaceFor (const Font& font)
  54. {
  55. const String faceName (font.getTypefaceName());
  56. const String faceStyle (font.getTypefaceStyle());
  57. jassert (faceName.isNotEmpty());
  58. for (int i = faces.size(); --i >= 0;)
  59. {
  60. CachedFace& face = faces.getReference(i);
  61. if (face.typefaceName == faceName
  62. && face.typefaceStyle == faceStyle
  63. && face.typeface != nullptr
  64. && face.typeface->isSuitableForFont (font))
  65. {
  66. face.lastUsageCount = ++counter;
  67. return face.typeface;
  68. }
  69. }
  70. int replaceIndex = 0;
  71. size_t bestLastUsageCount = std::numeric_limits<int>::max();
  72. for (int i = faces.size(); --i >= 0;)
  73. {
  74. const size_t lu = faces.getReference(i).lastUsageCount;
  75. if (bestLastUsageCount > lu)
  76. {
  77. bestLastUsageCount = lu;
  78. replaceIndex = i;
  79. }
  80. }
  81. CachedFace& face = faces.getReference (replaceIndex);
  82. face.typefaceName = faceName;
  83. face.typefaceStyle = faceStyle;
  84. face.lastUsageCount = ++counter;
  85. if (juce_getTypefaceForFont == nullptr)
  86. face.typeface = Font::getDefaultTypefaceForFont (font);
  87. else
  88. face.typeface = juce_getTypefaceForFont (font);
  89. jassert (face.typeface != nullptr); // the look and feel must return a typeface!
  90. if (defaultFace == nullptr && font == Font())
  91. defaultFace = face.typeface;
  92. return face.typeface;
  93. }
  94. Typeface::Ptr getDefaultTypeface() const noexcept
  95. {
  96. return defaultFace;
  97. }
  98. private:
  99. struct CachedFace
  100. {
  101. CachedFace() noexcept
  102. : lastUsageCount (0)
  103. {
  104. }
  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;
  110. String typefaceStyle;
  111. size_t lastUsageCount;
  112. Typeface::Ptr typeface;
  113. };
  114. Array <CachedFace> faces;
  115. Typeface::Ptr defaultFace;
  116. size_t counter;
  117. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache);
  118. };
  119. juce_ImplementSingleton_SingleThreaded (TypefaceCache)
  120. void Typeface::setTypefaceCacheSize (int numFontsToCache)
  121. {
  122. TypefaceCache::getInstance()->setSize (numFontsToCache);
  123. }
  124. void Typeface::clearTypefaceCache()
  125. {
  126. TypefaceCache::getInstance()->clear();
  127. }
  128. //==============================================================================
  129. class Font::SharedFontInternal : public ReferenceCountedObject
  130. {
  131. public:
  132. SharedFontInternal() noexcept
  133. : typefaceName (Font::getDefaultSansSerifFontName()),
  134. typefaceStyle (Font::getDefaultStyle()),
  135. height (FontValues::defaultFontHeight),
  136. horizontalScale (1.0f),
  137. kerning (0),
  138. ascent (0),
  139. underline (false),
  140. typeface (TypefaceCache::getInstance()->getDefaultTypeface())
  141. {
  142. }
  143. SharedFontInternal (const String& typefaceStyle_, const float height_,
  144. const bool underline_) noexcept
  145. : typefaceName (Font::getDefaultSansSerifFontName()),
  146. typefaceStyle (typefaceStyle_),
  147. height (height_),
  148. horizontalScale (1.0f),
  149. kerning (0),
  150. ascent (0),
  151. underline (underline_),
  152. typeface (nullptr)
  153. {
  154. }
  155. SharedFontInternal (const String& typefaceName_, const String& typefaceStyle_,
  156. const float height_, const bool underline_) noexcept
  157. : typefaceName (typefaceName_),
  158. typefaceStyle (typefaceStyle_),
  159. height (height_),
  160. horizontalScale (1.0f),
  161. kerning (0),
  162. ascent (0),
  163. underline (underline_),
  164. typeface (nullptr)
  165. {
  166. if (typefaceName.isEmpty())
  167. typefaceName = Font::getDefaultSansSerifFontName();
  168. }
  169. SharedFontInternal (const Typeface::Ptr& typeface_) noexcept
  170. : typefaceName (typeface_->getName()),
  171. typefaceStyle (typeface_->getStyle()),
  172. height (FontValues::defaultFontHeight),
  173. horizontalScale (1.0f),
  174. kerning (0),
  175. ascent (0),
  176. underline (false),
  177. typeface (typeface_)
  178. {
  179. jassert (typefaceName.isNotEmpty());
  180. }
  181. SharedFontInternal (const SharedFontInternal& other) noexcept
  182. : typefaceName (other.typefaceName),
  183. typefaceStyle (other.typefaceStyle),
  184. height (other.height),
  185. horizontalScale (other.horizontalScale),
  186. kerning (other.kerning),
  187. ascent (other.ascent),
  188. underline (other.underline),
  189. typeface (other.typeface)
  190. {
  191. }
  192. bool operator== (const SharedFontInternal& other) const noexcept
  193. {
  194. return height == other.height
  195. && underline == other.underline
  196. && horizontalScale == other.horizontalScale
  197. && kerning == other.kerning
  198. && typefaceName == other.typefaceName
  199. && typefaceStyle == other.typefaceStyle;
  200. }
  201. String typefaceName, typefaceStyle;
  202. float height, horizontalScale, kerning, ascent;
  203. bool underline;
  204. Typeface::Ptr typeface;
  205. };
  206. //==============================================================================
  207. Font::Font()
  208. : font (new SharedFontInternal())
  209. {
  210. }
  211. Font::Font (const float fontHeight, const int styleFlags)
  212. : font (new SharedFontInternal (FontStyleHelpers::getStyleName (styleFlags),
  213. FontValues::limitFontHeight (fontHeight),
  214. (styleFlags & underlined) != 0))
  215. {
  216. }
  217. Font::Font (const String& typefaceName, const float fontHeight, const int styleFlags)
  218. : font (new SharedFontInternal (typefaceName,
  219. FontStyleHelpers::getStyleName (styleFlags),
  220. FontValues::limitFontHeight (fontHeight),
  221. (styleFlags & underlined) != 0))
  222. {
  223. }
  224. Font::Font (const String& typefaceStyle, float fontHeight)
  225. : font (new SharedFontInternal (typefaceStyle, FontValues::limitFontHeight (fontHeight), false))
  226. {
  227. }
  228. Font::Font (const String& typefaceName, const String& typefaceStyle, float fontHeight)
  229. : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight), false))
  230. {
  231. }
  232. Font::Font (const Typeface::Ptr& typeface)
  233. : font (new SharedFontInternal (typeface))
  234. {
  235. }
  236. Font::Font (const Font& other) noexcept
  237. : font (other.font)
  238. {
  239. }
  240. Font& Font::operator= (const Font& other) noexcept
  241. {
  242. font = other.font;
  243. return *this;
  244. }
  245. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  246. Font::Font (Font&& other) noexcept
  247. : font (static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font))
  248. {
  249. }
  250. Font& Font::operator= (Font&& other) noexcept
  251. {
  252. font = static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font);
  253. return *this;
  254. }
  255. #endif
  256. Font::~Font() noexcept
  257. {
  258. }
  259. bool Font::operator== (const Font& other) const noexcept
  260. {
  261. return font == other.font
  262. || *font == *other.font;
  263. }
  264. bool Font::operator!= (const Font& other) const noexcept
  265. {
  266. return ! operator== (other);
  267. }
  268. void Font::dupeInternalIfShared()
  269. {
  270. if (font->getReferenceCount() > 1)
  271. font = new SharedFontInternal (*font);
  272. }
  273. //==============================================================================
  274. const String& Font::getDefaultSansSerifFontName()
  275. {
  276. static const String name ("<Sans-Serif>");
  277. return name;
  278. }
  279. const String& Font::getDefaultSerifFontName()
  280. {
  281. static const String name ("<Serif>");
  282. return name;
  283. }
  284. const String& Font::getDefaultMonospacedFontName()
  285. {
  286. static const String name ("<Monospaced>");
  287. return name;
  288. }
  289. const String& Font::getDefaultStyle()
  290. {
  291. static const String style ("<Regular>");
  292. return style;
  293. }
  294. const String& Font::getTypefaceName() const noexcept
  295. {
  296. return font->typefaceName;
  297. }
  298. void Font::setTypefaceName (const String& faceName)
  299. {
  300. if (faceName != font->typefaceName)
  301. {
  302. jassert (faceName.isNotEmpty());
  303. dupeInternalIfShared();
  304. font->typefaceName = faceName;
  305. font->typeface = nullptr;
  306. font->ascent = 0;
  307. }
  308. }
  309. const String& Font::getTypefaceStyle() const noexcept
  310. {
  311. return font->typefaceStyle;
  312. }
  313. void Font::setTypefaceStyle (const String& typefaceStyle)
  314. {
  315. if (typefaceStyle != font->typefaceStyle)
  316. {
  317. dupeInternalIfShared();
  318. font->typefaceStyle = typefaceStyle;
  319. font->typeface = nullptr;
  320. font->ascent = 0;
  321. }
  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. font->underline = shouldBeUnderlined;
  493. }
  494. bool Font::isUnderlined() const noexcept
  495. {
  496. return font->underline;
  497. }
  498. float Font::getAscent() const
  499. {
  500. if (font->ascent == 0)
  501. font->ascent = getTypeface()->getAscent();
  502. return font->height * font->ascent;
  503. }
  504. float Font::getDescent() const
  505. {
  506. return font->height - getAscent();
  507. }
  508. int Font::getStringWidth (const String& text) const
  509. {
  510. return roundToInt (getStringWidthFloat (text));
  511. }
  512. float Font::getStringWidthFloat (const String& text) const
  513. {
  514. float w = getTypeface()->getStringWidth (text);
  515. if (font->kerning != 0)
  516. w += font->kerning * text.length();
  517. return w * font->height * font->horizontalScale;
  518. }
  519. void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const
  520. {
  521. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  522. const int num = xOffsets.size();
  523. if (num > 0)
  524. {
  525. const float scale = font->height * font->horizontalScale;
  526. float* const x = xOffsets.getRawDataPointer();
  527. if (font->kerning != 0)
  528. {
  529. for (int i = 0; i < num; ++i)
  530. x[i] = (x[i] + i * font->kerning) * scale;
  531. }
  532. else
  533. {
  534. for (int i = 0; i < num; ++i)
  535. x[i] *= scale;
  536. }
  537. }
  538. }
  539. void Font::findFonts (Array<Font>& destArray)
  540. {
  541. const StringArray names (findAllTypefaceNames());
  542. for (int i = 0; i < names.size(); ++i)
  543. {
  544. const StringArray styles (findAllTypefaceStyles (names[i]));
  545. String style ("Regular");
  546. if (! styles.contains (style, true))
  547. style = styles[0];
  548. destArray.add (Font (names[i], style, FontValues::defaultFontHeight));
  549. }
  550. }
  551. //==============================================================================
  552. String Font::toString() const
  553. {
  554. String s;
  555. if (getTypefaceName() != getDefaultSansSerifFontName())
  556. s << getTypefaceName() << "; ";
  557. s << String (getHeight(), 1);
  558. if (getTypefaceStyle() != getDefaultStyle())
  559. s << ' ' << getTypefaceStyle();
  560. return s;
  561. }
  562. Font Font::fromString (const String& fontDescription)
  563. {
  564. const int separator = fontDescription.indexOfChar (';');
  565. String name;
  566. if (separator > 0)
  567. name = fontDescription.substring (0, separator).trim();
  568. if (name.isEmpty())
  569. name = getDefaultSansSerifFontName();
  570. String sizeAndStyle (fontDescription.substring (separator + 1));
  571. float height = sizeAndStyle.getFloatValue();
  572. if (height <= 0)
  573. height = 10.0f;
  574. const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false));
  575. return Font (name, style, height);
  576. }