Audio plugin host https://kx.studio/carla
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.

juce_Font.cpp 20KB

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