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.

552 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. #if JUCE_MAC || JUCE_IOS
  258. jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
  259. #endif
  260. }
  261. //==============================================================================
  262. void Font::setHeight (float newHeight)
  263. {
  264. newHeight = FontValues::limitFontHeight (newHeight);
  265. if (font->height != newHeight)
  266. {
  267. dupeInternalIfShared();
  268. font->height = newHeight;
  269. }
  270. }
  271. void Font::setHeightWithoutChangingWidth (float newHeight)
  272. {
  273. newHeight = FontValues::limitFontHeight (newHeight);
  274. if (font->height != newHeight)
  275. {
  276. dupeInternalIfShared();
  277. font->horizontalScale *= (font->height / newHeight);
  278. font->height = newHeight;
  279. }
  280. }
  281. void Font::setStyleFlags (const int newFlags)
  282. {
  283. if (font->styleFlags != newFlags)
  284. {
  285. dupeInternalIfShared();
  286. font->styleFlags = newFlags;
  287. font->typeface = nullptr;
  288. font->ascent = 0;
  289. }
  290. }
  291. void Font::setSizeAndStyle (float newHeight,
  292. const int newStyleFlags,
  293. const float newHorizontalScale,
  294. const float newKerningAmount)
  295. {
  296. newHeight = FontValues::limitFontHeight (newHeight);
  297. if (font->height != newHeight
  298. || font->horizontalScale != newHorizontalScale
  299. || font->kerning != newKerningAmount)
  300. {
  301. dupeInternalIfShared();
  302. font->height = newHeight;
  303. font->horizontalScale = newHorizontalScale;
  304. font->kerning = newKerningAmount;
  305. }
  306. setStyleFlags (newStyleFlags);
  307. }
  308. void Font::setHorizontalScale (const float scaleFactor)
  309. {
  310. dupeInternalIfShared();
  311. font->horizontalScale = scaleFactor;
  312. }
  313. void Font::setExtraKerningFactor (const float extraKerning)
  314. {
  315. dupeInternalIfShared();
  316. font->kerning = extraKerning;
  317. }
  318. void Font::setBold (const bool shouldBeBold)
  319. {
  320. setStyleFlags (shouldBeBold ? (font->styleFlags | bold)
  321. : (font->styleFlags & ~bold));
  322. }
  323. Font Font::boldened() const
  324. {
  325. Font f (*this);
  326. f.setBold (true);
  327. return f;
  328. }
  329. bool Font::isBold() const noexcept
  330. {
  331. return (font->styleFlags & bold) != 0;
  332. }
  333. void Font::setItalic (const bool shouldBeItalic)
  334. {
  335. setStyleFlags (shouldBeItalic ? (font->styleFlags | italic)
  336. : (font->styleFlags & ~italic));
  337. }
  338. Font Font::italicised() const
  339. {
  340. Font f (*this);
  341. f.setItalic (true);
  342. return f;
  343. }
  344. bool Font::isItalic() const noexcept
  345. {
  346. return (font->styleFlags & italic) != 0;
  347. }
  348. void Font::setUnderline (const bool shouldBeUnderlined)
  349. {
  350. setStyleFlags (shouldBeUnderlined ? (font->styleFlags | underlined)
  351. : (font->styleFlags & ~underlined));
  352. }
  353. bool Font::isUnderlined() const noexcept
  354. {
  355. return (font->styleFlags & underlined) != 0;
  356. }
  357. float Font::getAscent() const
  358. {
  359. if (font->ascent == 0)
  360. font->ascent = getTypeface()->getAscent();
  361. return font->height * font->ascent;
  362. }
  363. float Font::getDescent() const
  364. {
  365. return font->height - getAscent();
  366. }
  367. int Font::getStringWidth (const String& text) const
  368. {
  369. return roundToInt (getStringWidthFloat (text));
  370. }
  371. float Font::getStringWidthFloat (const String& text) const
  372. {
  373. float w = getTypeface()->getStringWidth (text);
  374. if (font->kerning != 0)
  375. w += font->kerning * text.length();
  376. return w * font->height * font->horizontalScale;
  377. }
  378. void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const
  379. {
  380. getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
  381. const float scale = font->height * font->horizontalScale;
  382. const int num = xOffsets.size();
  383. if (num > 0)
  384. {
  385. float* const x = &(xOffsets.getReference(0));
  386. if (font->kerning != 0)
  387. {
  388. for (int i = 0; i < num; ++i)
  389. x[i] = (x[i] + i * font->kerning) * scale;
  390. }
  391. else
  392. {
  393. for (int i = 0; i < num; ++i)
  394. x[i] *= scale;
  395. }
  396. }
  397. }
  398. void Font::findFonts (Array<Font>& destArray)
  399. {
  400. const StringArray names (findAllTypefaceNames());
  401. for (int i = 0; i < names.size(); ++i)
  402. destArray.add (Font (names[i], FontValues::defaultFontHeight, Font::plain));
  403. }
  404. //==============================================================================
  405. String Font::toString() const
  406. {
  407. String s (getTypefaceName());
  408. if (s == getDefaultSansSerifFontName())
  409. s = String::empty;
  410. else
  411. s += "; ";
  412. s += String (getHeight(), 1);
  413. if (isBold())
  414. s += " bold";
  415. if (isItalic())
  416. s += " italic";
  417. return s;
  418. }
  419. Font Font::fromString (const String& fontDescription)
  420. {
  421. String name;
  422. const int separator = fontDescription.indexOfChar (';');
  423. if (separator > 0)
  424. name = fontDescription.substring (0, separator).trim();
  425. if (name.isEmpty())
  426. name = getDefaultSansSerifFontName();
  427. String sizeAndStyle (fontDescription.substring (separator + 1));
  428. float height = sizeAndStyle.getFloatValue();
  429. if (height <= 0)
  430. height = 10.0f;
  431. int flags = Font::plain;
  432. if (sizeAndStyle.containsIgnoreCase ("bold"))
  433. flags |= Font::bold;
  434. if (sizeAndStyle.containsIgnoreCase ("italic"))
  435. flags |= Font::italic;
  436. return Font (name, height, flags);
  437. }
  438. //==============================================================================
  439. Typeface* Font::getTypeface() const
  440. {
  441. if (font->typeface == 0)
  442. font->typeface = TypefaceCache::getInstance()->findTypefaceFor (*this);
  443. return font->typeface;
  444. }
  445. END_JUCE_NAMESPACE