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.

548 lines
15KB

  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. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. namespace FontValues
  21. {
  22. float limitFontHeight (const float height) noexcept
  23. {
  24. return jlimit (0.1f, 10000.0f, height);
  25. }
  26. const float defaultFontHeight = 14.0f;
  27. String fallbackFont;
  28. }
  29. typedef Typeface::Ptr (*GetTypefaceForFont) (const Font&);
  30. GetTypefaceForFont juce_getTypefaceForFont = nullptr;
  31. //==============================================================================
  32. class TypefaceCache : public DeletedAtShutdown
  33. {
  34. public:
  35. TypefaceCache()
  36. : counter (0)
  37. {
  38. setSize (10);
  39. }
  40. ~TypefaceCache()
  41. {
  42. clearSingletonInstance();
  43. }
  44. juce_DeclareSingleton_SingleThreaded_Minimal (TypefaceCache);
  45. void setSize (const int numToCache)
  46. {
  47. faces.clear();
  48. faces.insertMultiple (-1, CachedFace(), numToCache);
  49. }
  50. Typeface::Ptr findTypefaceFor (const Font& font)
  51. {
  52. const int flags = font.getStyleFlags() & (Font::bold | Font::italic);
  53. const String faceName (font.getTypefaceName());
  54. int i;
  55. for (i = faces.size(); --i >= 0;)
  56. {
  57. CachedFace& face = faces.getReference(i);
  58. if (face.flags == flags
  59. && face.typefaceName == faceName
  60. && face.typeface->isSuitableForFont (font))
  61. {
  62. face.lastUsageCount = ++counter;
  63. return face.typeface;
  64. }
  65. }
  66. int replaceIndex = 0;
  67. int bestLastUsageCount = std::numeric_limits<int>::max();
  68. for (i = faces.size(); --i >= 0;)
  69. {
  70. const int 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.flags = flags;
  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), flags (-1)
  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. int lastUsageCount, flags;
  107. Typeface::Ptr typeface;
  108. };
  109. Array <CachedFace> faces;
  110. Typeface::Ptr defaultFace;
  111. int counter;
  112. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache);
  113. };
  114. juce_ImplementSingleton_SingleThreaded (TypefaceCache)
  115. void Typeface::setTypefaceCacheSize (int numFontsToCache)
  116. {
  117. TypefaceCache::getInstance()->setSize (numFontsToCache);
  118. }
  119. //==============================================================================
  120. Font::SharedFontInternal::SharedFontInternal (const float height_, const int styleFlags_) noexcept
  121. : typefaceName (Font::getDefaultSansSerifFontName()),
  122. height (height_),
  123. horizontalScale (1.0f),
  124. kerning (0),
  125. ascent (0),
  126. styleFlags (styleFlags_),
  127. typeface ((styleFlags_ & (Font::bold | Font::italic)) == 0
  128. ? TypefaceCache::getInstance()->getDefaultTypeface() : nullptr)
  129. {
  130. }
  131. Font::SharedFontInternal::SharedFontInternal (const String& typefaceName_, const float height_, const int styleFlags_) noexcept
  132. : typefaceName (typefaceName_),
  133. height (height_),
  134. horizontalScale (1.0f),
  135. kerning (0),
  136. ascent (0),
  137. styleFlags (styleFlags_),
  138. typeface (nullptr)
  139. {
  140. }
  141. Font::SharedFontInternal::SharedFontInternal (const Typeface::Ptr& typeface_) noexcept
  142. : typefaceName (typeface_->getName()),
  143. height (FontValues::defaultFontHeight),
  144. horizontalScale (1.0f),
  145. kerning (0),
  146. ascent (0),
  147. styleFlags (Font::plain),
  148. typeface (typeface_)
  149. {
  150. }
  151. Font::SharedFontInternal::SharedFontInternal (const SharedFontInternal& other) noexcept
  152. : typefaceName (other.typefaceName),
  153. height (other.height),
  154. horizontalScale (other.horizontalScale),
  155. kerning (other.kerning),
  156. ascent (other.ascent),
  157. styleFlags (other.styleFlags),
  158. typeface (other.typeface)
  159. {
  160. }
  161. bool Font::SharedFontInternal::operator== (const SharedFontInternal& other) const noexcept
  162. {
  163. return height == other.height
  164. && styleFlags == other.styleFlags
  165. && horizontalScale == other.horizontalScale
  166. && kerning == other.kerning
  167. && typefaceName == other.typefaceName;
  168. }
  169. //==============================================================================
  170. Font::Font()
  171. : font (new SharedFontInternal (FontValues::defaultFontHeight, Font::plain))
  172. {
  173. }
  174. Font::Font (const float fontHeight, const int styleFlags_)
  175. : font (new SharedFontInternal (FontValues::limitFontHeight (fontHeight), styleFlags_))
  176. {
  177. }
  178. Font::Font (const String& typefaceName_, const float fontHeight, const int styleFlags_)
  179. : font (new SharedFontInternal (typefaceName_, FontValues::limitFontHeight (fontHeight), styleFlags_))
  180. {
  181. }
  182. Font::Font (const Typeface::Ptr& typeface)
  183. : font (new SharedFontInternal (typeface))
  184. {
  185. }
  186. Font::Font (const Font& other) noexcept
  187. : font (other.font)
  188. {
  189. }
  190. Font& Font::operator= (const Font& other) noexcept
  191. {
  192. font = other.font;
  193. return *this;
  194. }
  195. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  196. Font::Font (Font&& other) noexcept
  197. : font (static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font))
  198. {
  199. }
  200. Font& Font::operator= (Font&& other) noexcept
  201. {
  202. font = static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font);
  203. return *this;
  204. }
  205. #endif
  206. Font::~Font() noexcept
  207. {
  208. }
  209. bool Font::operator== (const Font& other) const noexcept
  210. {
  211. return font == other.font
  212. || *font == *other.font;
  213. }
  214. bool Font::operator!= (const Font& other) const noexcept
  215. {
  216. return ! operator== (other);
  217. }
  218. void Font::dupeInternalIfShared()
  219. {
  220. if (font->getReferenceCount() > 1)
  221. font = new SharedFontInternal (*font);
  222. }
  223. //==============================================================================
  224. const String& Font::getDefaultSansSerifFontName()
  225. {
  226. static const String name ("<Sans-Serif>");
  227. return name;
  228. }
  229. const String& Font::getDefaultSerifFontName()
  230. {
  231. static const String name ("<Serif>");
  232. return name;
  233. }
  234. const String& Font::getDefaultMonospacedFontName()
  235. {
  236. static const String name ("<Monospaced>");
  237. return name;
  238. }
  239. void Font::setTypefaceName (const String& faceName)
  240. {
  241. if (faceName != font->typefaceName)
  242. {
  243. dupeInternalIfShared();
  244. font->typefaceName = faceName;
  245. font->typeface = nullptr;
  246. font->ascent = 0;
  247. }
  248. }
  249. //==============================================================================
  250. const String& Font::getFallbackFontName()
  251. {
  252. return FontValues::fallbackFont;
  253. }
  254. void Font::setFallbackFontName (const String& name)
  255. {
  256. FontValues::fallbackFont = name;
  257. }
  258. //==============================================================================
  259. void Font::setHeight (float newHeight)
  260. {
  261. newHeight = FontValues::limitFontHeight (newHeight);
  262. if (font->height != newHeight)
  263. {
  264. dupeInternalIfShared();
  265. font->height = newHeight;
  266. }
  267. }
  268. void Font::setHeightWithoutChangingWidth (float newHeight)
  269. {
  270. newHeight = FontValues::limitFontHeight (newHeight);
  271. if (font->height != newHeight)
  272. {
  273. dupeInternalIfShared();
  274. font->horizontalScale *= (font->height / newHeight);
  275. font->height = newHeight;
  276. }
  277. }
  278. void Font::setStyleFlags (const int newFlags)
  279. {
  280. if (font->styleFlags != newFlags)
  281. {
  282. dupeInternalIfShared();
  283. font->styleFlags = newFlags;
  284. font->typeface = nullptr;
  285. font->ascent = 0;
  286. }
  287. }
  288. void Font::setSizeAndStyle (float newHeight,
  289. const int newStyleFlags,
  290. const float newHorizontalScale,
  291. const float newKerningAmount)
  292. {
  293. newHeight = FontValues::limitFontHeight (newHeight);
  294. if (font->height != newHeight
  295. || font->horizontalScale != newHorizontalScale
  296. || font->kerning != newKerningAmount)
  297. {
  298. dupeInternalIfShared();
  299. font->height = newHeight;
  300. font->horizontalScale = newHorizontalScale;
  301. font->kerning = newKerningAmount;
  302. }
  303. setStyleFlags (newStyleFlags);
  304. }
  305. void Font::setHorizontalScale (const float scaleFactor)
  306. {
  307. dupeInternalIfShared();
  308. font->horizontalScale = scaleFactor;
  309. }
  310. void Font::setExtraKerningFactor (const float extraKerning)
  311. {
  312. dupeInternalIfShared();
  313. font->kerning = extraKerning;
  314. }
  315. void Font::setBold (const bool shouldBeBold)
  316. {
  317. setStyleFlags (shouldBeBold ? (font->styleFlags | bold)
  318. : (font->styleFlags & ~bold));
  319. }
  320. Font Font::boldened() const
  321. {
  322. Font f (*this);
  323. f.setBold (true);
  324. return f;
  325. }
  326. bool Font::isBold() const noexcept
  327. {
  328. return (font->styleFlags & bold) != 0;
  329. }
  330. void Font::setItalic (const bool shouldBeItalic)
  331. {
  332. setStyleFlags (shouldBeItalic ? (font->styleFlags | italic)
  333. : (font->styleFlags & ~italic));
  334. }
  335. Font Font::italicised() const
  336. {
  337. Font f (*this);
  338. f.setItalic (true);
  339. return f;
  340. }
  341. bool Font::isItalic() const noexcept
  342. {
  343. return (font->styleFlags & italic) != 0;
  344. }
  345. void Font::setUnderline (const bool shouldBeUnderlined)
  346. {
  347. setStyleFlags (shouldBeUnderlined ? (font->styleFlags | underlined)
  348. : (font->styleFlags & ~underlined));
  349. }
  350. bool Font::isUnderlined() const noexcept
  351. {
  352. return (font->styleFlags & underlined) != 0;
  353. }
  354. float Font::getAscent() const
  355. {
  356. if (font->ascent == 0)
  357. font->ascent = getTypeface()->getAscent();
  358. return font->height * font->ascent;
  359. }
  360. float Font::getDescent() const
  361. {
  362. return font->height - getAscent();
  363. }
  364. int Font::getStringWidth (const String& text) const
  365. {
  366. return roundToInt (getStringWidthFloat (text));
  367. }
  368. float Font::getStringWidthFloat (const String& text) const
  369. {
  370. float w = getTypeface()->getStringWidth (text);
  371. if (font->kerning != 0)
  372. w += font->kerning * text.length();
  373. return w * font->height * font->horizontalScale;
  374. }
  375. void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const
  376. {
  377. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  378. const float scale = font->height * font->horizontalScale;
  379. const int num = xOffsets.size();
  380. if (num > 0)
  381. {
  382. float* const x = &(xOffsets.getReference(0));
  383. if (font->kerning != 0)
  384. {
  385. for (int i = 0; i < num; ++i)
  386. x[i] = (x[i] + i * font->kerning) * scale;
  387. }
  388. else
  389. {
  390. for (int i = 0; i < num; ++i)
  391. x[i] *= scale;
  392. }
  393. }
  394. }
  395. void Font::findFonts (Array<Font>& destArray)
  396. {
  397. const StringArray names (findAllTypefaceNames());
  398. for (int i = 0; i < names.size(); ++i)
  399. destArray.add (Font (names[i], FontValues::defaultFontHeight, Font::plain));
  400. }
  401. //==============================================================================
  402. String Font::toString() const
  403. {
  404. String s (getTypefaceName());
  405. if (s == getDefaultSansSerifFontName())
  406. s = String::empty;
  407. else
  408. s += "; ";
  409. s += String (getHeight(), 1);
  410. if (isBold())
  411. s += " bold";
  412. if (isItalic())
  413. s += " italic";
  414. return s;
  415. }
  416. Font Font::fromString (const String& fontDescription)
  417. {
  418. String name;
  419. const int separator = fontDescription.indexOfChar (';');
  420. if (separator > 0)
  421. name = fontDescription.substring (0, separator).trim();
  422. if (name.isEmpty())
  423. name = getDefaultSansSerifFontName();
  424. String sizeAndStyle (fontDescription.substring (separator + 1));
  425. float height = sizeAndStyle.getFloatValue();
  426. if (height <= 0)
  427. height = 10.0f;
  428. int flags = Font::plain;
  429. if (sizeAndStyle.containsIgnoreCase ("bold"))
  430. flags |= Font::bold;
  431. if (sizeAndStyle.containsIgnoreCase ("italic"))
  432. flags |= Font::italic;
  433. return Font (name, height, flags);
  434. }
  435. //==============================================================================
  436. Typeface* Font::getTypeface() const
  437. {
  438. if (font->typeface == 0)
  439. font->typeface = TypefaceCache::getInstance()->findTypefaceFor (*this);
  440. return font->typeface;
  441. }
  442. END_JUCE_NAMESPACE