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.

698 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 ReferenceCountedObject
  122. {
  123. public:
  124. SharedFontInternal() noexcept
  125. : typefaceName (Font::getDefaultSansSerifFontName()),
  126. typefaceStyle (Font::getDefaultStyle()),
  127. height (FontValues::defaultFontHeight),
  128. horizontalScale (1.0f),
  129. kerning (0),
  130. ascent (0),
  131. underline (false),
  132. typeface (TypefaceCache::getInstance()->getDefaultTypeface())
  133. {
  134. }
  135. SharedFontInternal (const String& typefaceStyle_, const float height_,
  136. const bool underline_) noexcept
  137. : typefaceName (Font::getDefaultSansSerifFontName()),
  138. typefaceStyle (typefaceStyle_),
  139. height (height_),
  140. horizontalScale (1.0f),
  141. kerning (0),
  142. ascent (0),
  143. underline (underline_),
  144. typeface (nullptr)
  145. {
  146. }
  147. SharedFontInternal (const String& typefaceName_, const String& typefaceStyle_,
  148. const float height_, const bool underline_) noexcept
  149. : typefaceName (typefaceName_),
  150. typefaceStyle (typefaceStyle_),
  151. height (height_),
  152. horizontalScale (1.0f),
  153. kerning (0),
  154. ascent (0),
  155. underline (underline_),
  156. typeface (nullptr)
  157. {
  158. if (typefaceName.isEmpty())
  159. typefaceName = Font::getDefaultSansSerifFontName();
  160. }
  161. SharedFontInternal (const Typeface::Ptr& typeface_) noexcept
  162. : typefaceName (typeface_->getName()),
  163. typefaceStyle (typeface_->getStyle()),
  164. height (FontValues::defaultFontHeight),
  165. horizontalScale (1.0f),
  166. kerning (0),
  167. ascent (0),
  168. underline (false),
  169. typeface (typeface_)
  170. {
  171. jassert (typefaceName.isNotEmpty());
  172. }
  173. SharedFontInternal (const SharedFontInternal& other) noexcept
  174. : typefaceName (other.typefaceName),
  175. typefaceStyle (other.typefaceStyle),
  176. height (other.height),
  177. horizontalScale (other.horizontalScale),
  178. kerning (other.kerning),
  179. ascent (other.ascent),
  180. underline (other.underline),
  181. typeface (other.typeface)
  182. {
  183. }
  184. bool operator== (const SharedFontInternal& other) const noexcept
  185. {
  186. return height == other.height
  187. && underline == other.underline
  188. && horizontalScale == other.horizontalScale
  189. && kerning == other.kerning
  190. && typefaceName == other.typefaceName
  191. && typefaceStyle == other.typefaceStyle;
  192. }
  193. String typefaceName, typefaceStyle;
  194. float height, horizontalScale, kerning, ascent;
  195. bool underline;
  196. Typeface::Ptr typeface;
  197. };
  198. //==============================================================================
  199. Font::Font()
  200. : font (new SharedFontInternal())
  201. {
  202. }
  203. Font::Font (const float fontHeight, const int styleFlags)
  204. : font (new SharedFontInternal (FontStyleHelpers::getStyleName (styleFlags),
  205. FontValues::limitFontHeight (fontHeight),
  206. (styleFlags & underlined) != 0))
  207. {
  208. }
  209. Font::Font (const String& typefaceName, const float fontHeight, const int styleFlags)
  210. : font (new SharedFontInternal (typefaceName,
  211. FontStyleHelpers::getStyleName (styleFlags),
  212. FontValues::limitFontHeight (fontHeight),
  213. (styleFlags & underlined) != 0))
  214. {
  215. }
  216. Font::Font (const String& typefaceStyle, float fontHeight)
  217. : font (new SharedFontInternal (typefaceStyle, FontValues::limitFontHeight (fontHeight), false))
  218. {
  219. }
  220. Font::Font (const String& typefaceName, const String& typefaceStyle, float fontHeight)
  221. : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight), false))
  222. {
  223. }
  224. Font::Font (const Typeface::Ptr& typeface)
  225. : font (new SharedFontInternal (typeface))
  226. {
  227. }
  228. Font::Font (const Font& other) noexcept
  229. : font (other.font)
  230. {
  231. }
  232. Font& Font::operator= (const Font& other) noexcept
  233. {
  234. font = other.font;
  235. return *this;
  236. }
  237. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  238. Font::Font (Font&& other) noexcept
  239. : font (static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font))
  240. {
  241. }
  242. Font& Font::operator= (Font&& other) noexcept
  243. {
  244. font = static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font);
  245. return *this;
  246. }
  247. #endif
  248. Font::~Font() noexcept
  249. {
  250. }
  251. bool Font::operator== (const Font& other) const noexcept
  252. {
  253. return font == other.font
  254. || *font == *other.font;
  255. }
  256. bool Font::operator!= (const Font& other) const noexcept
  257. {
  258. return ! operator== (other);
  259. }
  260. void Font::dupeInternalIfShared()
  261. {
  262. if (font->getReferenceCount() > 1)
  263. font = new SharedFontInternal (*font);
  264. }
  265. //==============================================================================
  266. const String& Font::getDefaultSansSerifFontName()
  267. {
  268. static const String name ("<Sans-Serif>");
  269. return name;
  270. }
  271. const String& Font::getDefaultSerifFontName()
  272. {
  273. static const String name ("<Serif>");
  274. return name;
  275. }
  276. const String& Font::getDefaultMonospacedFontName()
  277. {
  278. static const String name ("<Monospaced>");
  279. return name;
  280. }
  281. const String& Font::getDefaultStyle()
  282. {
  283. static const String style ("<Regular>");
  284. return style;
  285. }
  286. const String& Font::getTypefaceName() const noexcept
  287. {
  288. return font->typefaceName;
  289. }
  290. void Font::setTypefaceName (const String& faceName)
  291. {
  292. if (faceName != font->typefaceName)
  293. {
  294. jassert (faceName.isNotEmpty());
  295. dupeInternalIfShared();
  296. font->typefaceName = faceName;
  297. font->typeface = nullptr;
  298. font->ascent = 0;
  299. }
  300. }
  301. const String& Font::getTypefaceStyle() const noexcept
  302. {
  303. return font->typefaceStyle;
  304. }
  305. void Font::setTypefaceStyle (const String& typefaceStyle)
  306. {
  307. if (typefaceStyle != font->typefaceStyle)
  308. {
  309. dupeInternalIfShared();
  310. font->typefaceStyle = typefaceStyle;
  311. font->typeface = nullptr;
  312. font->ascent = 0;
  313. }
  314. }
  315. StringArray Font::getAvailableStyles() const
  316. {
  317. return findAllTypefaceStyles (getTypeface()->getName());
  318. }
  319. Typeface* Font::getTypeface() const
  320. {
  321. if (font->typeface == nullptr)
  322. font->typeface = TypefaceCache::getInstance()->findTypefaceFor (*this);
  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. float Font::getHeight() const noexcept
  350. {
  351. return font->height;
  352. }
  353. Font Font::withHeight (const float newHeight) const
  354. {
  355. Font f (*this);
  356. f.setHeight (newHeight);
  357. return f;
  358. }
  359. void Font::setHeight (float newHeight)
  360. {
  361. newHeight = FontValues::limitFontHeight (newHeight);
  362. if (font->height != newHeight)
  363. {
  364. dupeInternalIfShared();
  365. font->height = newHeight;
  366. }
  367. }
  368. void Font::setHeightWithoutChangingWidth (float newHeight)
  369. {
  370. newHeight = FontValues::limitFontHeight (newHeight);
  371. if (font->height != newHeight)
  372. {
  373. dupeInternalIfShared();
  374. font->horizontalScale *= (font->height / newHeight);
  375. font->height = newHeight;
  376. }
  377. }
  378. int Font::getStyleFlags() const noexcept
  379. {
  380. int styleFlags = font->underline ? underlined : plain;
  381. if (isBold()) styleFlags |= bold;
  382. if (isItalic()) styleFlags |= italic;
  383. return styleFlags;
  384. }
  385. Font Font::withStyle (const int newFlags) const
  386. {
  387. Font f (*this);
  388. f.setStyleFlags (newFlags);
  389. return f;
  390. }
  391. void Font::setStyleFlags (const int newFlags)
  392. {
  393. if (getStyleFlags() != newFlags)
  394. {
  395. dupeInternalIfShared();
  396. font->typefaceStyle = FontStyleHelpers::getStyleName (newFlags);
  397. font->underline = (newFlags & underlined) != 0;
  398. font->typeface = nullptr;
  399. font->ascent = 0;
  400. }
  401. }
  402. void Font::setSizeAndStyle (float newHeight,
  403. const int newStyleFlags,
  404. const float newHorizontalScale,
  405. const float newKerningAmount)
  406. {
  407. newHeight = FontValues::limitFontHeight (newHeight);
  408. if (font->height != newHeight
  409. || font->horizontalScale != newHorizontalScale
  410. || font->kerning != newKerningAmount)
  411. {
  412. dupeInternalIfShared();
  413. font->height = newHeight;
  414. font->horizontalScale = newHorizontalScale;
  415. font->kerning = newKerningAmount;
  416. }
  417. setStyleFlags (newStyleFlags);
  418. }
  419. void Font::setSizeAndStyle (float newHeight,
  420. const String& newStyle,
  421. const float newHorizontalScale,
  422. const float newKerningAmount)
  423. {
  424. newHeight = FontValues::limitFontHeight (newHeight);
  425. if (font->height != newHeight
  426. || font->horizontalScale != newHorizontalScale
  427. || font->kerning != newKerningAmount)
  428. {
  429. dupeInternalIfShared();
  430. font->height = newHeight;
  431. font->horizontalScale = newHorizontalScale;
  432. font->kerning = newKerningAmount;
  433. }
  434. setTypefaceStyle (newStyle);
  435. }
  436. float Font::getHorizontalScale() const noexcept
  437. {
  438. return font->horizontalScale;
  439. }
  440. Font Font::withHorizontalScale (const float newHorizontalScale) const
  441. {
  442. Font f (*this);
  443. f.setHorizontalScale (newHorizontalScale);
  444. return f;
  445. }
  446. void Font::setHorizontalScale (const float scaleFactor)
  447. {
  448. dupeInternalIfShared();
  449. font->horizontalScale = scaleFactor;
  450. }
  451. float Font::getExtraKerningFactor() const noexcept
  452. {
  453. return font->kerning;
  454. }
  455. Font Font::withExtraKerningFactor (const float extraKerning) const
  456. {
  457. Font f (*this);
  458. f.setExtraKerningFactor (extraKerning);
  459. return f;
  460. }
  461. void Font::setExtraKerningFactor (const float extraKerning)
  462. {
  463. dupeInternalIfShared();
  464. font->kerning = extraKerning;
  465. }
  466. Font Font::boldened() const { return withStyle (getStyleFlags() | bold); }
  467. Font Font::italicised() const { return withStyle (getStyleFlags() | italic); }
  468. bool Font::isBold() const noexcept { return FontStyleHelpers::isBold (font->typefaceStyle); }
  469. bool Font::isItalic() const noexcept { return FontStyleHelpers::isItalic (font->typefaceStyle); }
  470. void Font::setBold (const bool shouldBeBold)
  471. {
  472. const int flags = getStyleFlags();
  473. setStyleFlags (shouldBeBold ? (flags | bold)
  474. : (flags & ~bold));
  475. }
  476. void Font::setItalic (const bool shouldBeItalic)
  477. {
  478. const int flags = getStyleFlags();
  479. setStyleFlags (shouldBeItalic ? (flags | italic)
  480. : (flags & ~italic));
  481. }
  482. void Font::setUnderline (const bool shouldBeUnderlined)
  483. {
  484. font->underline = shouldBeUnderlined;
  485. }
  486. bool Font::isUnderlined() const noexcept
  487. {
  488. return font->underline;
  489. }
  490. float Font::getAscent() const
  491. {
  492. if (font->ascent == 0)
  493. font->ascent = getTypeface()->getAscent();
  494. return font->height * font->ascent;
  495. }
  496. float Font::getDescent() const
  497. {
  498. return font->height - getAscent();
  499. }
  500. int Font::getStringWidth (const String& text) const
  501. {
  502. return roundToInt (getStringWidthFloat (text));
  503. }
  504. float Font::getStringWidthFloat (const String& text) const
  505. {
  506. float w = getTypeface()->getStringWidth (text);
  507. if (font->kerning != 0)
  508. w += font->kerning * text.length();
  509. return w * font->height * font->horizontalScale;
  510. }
  511. void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const
  512. {
  513. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  514. const int num = xOffsets.size();
  515. if (num > 0)
  516. {
  517. const float scale = font->height * font->horizontalScale;
  518. float* const x = xOffsets.getRawDataPointer();
  519. if (font->kerning != 0)
  520. {
  521. for (int i = 0; i < num; ++i)
  522. x[i] = (x[i] + i * font->kerning) * scale;
  523. }
  524. else
  525. {
  526. for (int i = 0; i < num; ++i)
  527. x[i] *= scale;
  528. }
  529. }
  530. }
  531. void Font::findFonts (Array<Font>& destArray)
  532. {
  533. const StringArray names (findAllTypefaceNames());
  534. for (int i = 0; i < names.size(); ++i)
  535. {
  536. const StringArray styles (findAllTypefaceStyles (names[i]));
  537. String style ("Regular");
  538. if (! styles.contains (style, true))
  539. style = styles[0];
  540. destArray.add (Font (names[i], style, FontValues::defaultFontHeight));
  541. }
  542. }
  543. //==============================================================================
  544. String Font::toString() const
  545. {
  546. String s;
  547. if (getTypefaceName() != getDefaultSansSerifFontName())
  548. s << getTypefaceName() << "; ";
  549. s << String (getHeight(), 1);
  550. if (getTypefaceStyle() != getDefaultStyle())
  551. s << ' ' << getTypefaceStyle();
  552. return s;
  553. }
  554. Font Font::fromString (const String& fontDescription)
  555. {
  556. const int separator = fontDescription.indexOfChar (';');
  557. String name;
  558. if (separator > 0)
  559. name = fontDescription.substring (0, separator).trim();
  560. if (name.isEmpty())
  561. name = getDefaultSansSerifFontName();
  562. String sizeAndStyle (fontDescription.substring (separator + 1));
  563. float height = sizeAndStyle.getFloatValue();
  564. if (height <= 0)
  565. height = 10.0f;
  566. const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false));
  567. return Font (name, style, height);
  568. }