| @@ -38,7 +38,7 @@ SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* document_, | |||
| #if JUCE_MAC | |||
| Font font (10.6f); | |||
| font.setTypefaceName ("Menlo Regular"); | |||
| font.setTypefaceName ("Menlo"); | |||
| #else | |||
| Font font (10.0f); | |||
| font.setTypefaceName (Font::getDefaultMonospacedFontName()); | |||
| @@ -102,13 +102,13 @@ namespace CustomTypefaceHelpers | |||
| //============================================================================== | |||
| CustomTypeface::CustomTypeface() | |||
| : Typeface (String::empty) | |||
| : Typeface (String::empty, String::empty) | |||
| { | |||
| clear(); | |||
| } | |||
| CustomTypeface::CustomTypeface (InputStream& serialisedTypefaceStream) | |||
| : Typeface (String::empty) | |||
| : Typeface (String::empty, String::empty) | |||
| { | |||
| clear(); | |||
| @@ -116,8 +116,11 @@ CustomTypeface::CustomTypeface (InputStream& serialisedTypefaceStream) | |||
| BufferedInputStream in (gzin, 32768); | |||
| name = in.readString(); | |||
| isBold = in.readBool(); | |||
| isItalic = in.readBool(); | |||
| const bool isBold = in.readBool(); | |||
| const bool isItalic = in.readBool(); | |||
| style = FontStyleHelpers::getStyleName (isBold, isItalic); | |||
| ascent = in.readFloat(); | |||
| defaultCharacter = CustomTypefaceHelpers::readChar (in); | |||
| @@ -153,19 +156,27 @@ void CustomTypeface::clear() | |||
| { | |||
| defaultCharacter = 0; | |||
| ascent = 1.0f; | |||
| isBold = isItalic = false; | |||
| style = "Regular"; | |||
| zeromem (lookupTable, sizeof (lookupTable)); | |||
| glyphs.clear(); | |||
| } | |||
| void CustomTypeface::setCharacteristics (const String& name_, const float ascent_, const bool isBold_, | |||
| const bool isItalic_, const juce_wchar defaultCharacter_) noexcept | |||
| void CustomTypeface::setCharacteristics (const String& name_, const float ascent_, const bool isBold, | |||
| const bool isItalic, const juce_wchar defaultCharacter_) noexcept | |||
| { | |||
| name = name_; | |||
| defaultCharacter = defaultCharacter_; | |||
| ascent = ascent_; | |||
| style = FontStyleHelpers::getStyleName (isBold, isItalic); | |||
| } | |||
| void CustomTypeface::setCharacteristics (const String& name_, const String& style_, const float ascent_, | |||
| const juce_wchar defaultCharacter_) noexcept | |||
| { | |||
| name = name_; | |||
| style = style_; | |||
| defaultCharacter = defaultCharacter_; | |||
| ascent = ascent_; | |||
| isBold = isBold_; | |||
| isItalic = isItalic_; | |||
| } | |||
| void CustomTypeface::addGlyph (const juce_wchar character, const Path& path, const float width) noexcept | |||
| @@ -216,7 +227,7 @@ bool CustomTypeface::loadGlyphIfPossible (const juce_wchar /*characterNeeded*/) | |||
| void CustomTypeface::addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept | |||
| { | |||
| setCharacteristics (name, typefaceToCopy.getAscent(), isBold, isItalic, defaultCharacter); | |||
| setCharacteristics (name, style, typefaceToCopy.getAscent(), defaultCharacter); | |||
| for (int i = 0; i < numCharacters; ++i) | |||
| { | |||
| @@ -256,8 +267,8 @@ bool CustomTypeface::writeToStream (OutputStream& outputStream) | |||
| GZIPCompressorOutputStream out (&outputStream); | |||
| out.writeString (name); | |||
| out.writeBool (isBold); | |||
| out.writeBool (isItalic); | |||
| out.writeBool (FontStyleHelpers::isBold (style)); | |||
| out.writeBool (FontStyleHelpers::isItalic (style)); | |||
| out.writeFloat (ascent); | |||
| CustomTypefaceHelpers::writeChar (out, defaultCharacter); | |||
| out.writeInt (glyphs.size()); | |||
| @@ -64,19 +64,31 @@ public: | |||
| void clear(); | |||
| /** Sets the vital statistics for the typeface. | |||
| @param name the typeface's name | |||
| @param ascent the ascent - this is normalised to a height of 1.0 and this is | |||
| the value that will be returned by Typeface::getAscent(). The | |||
| descent is assumed to be (1.0 - ascent) | |||
| @param isBold should be true if the typeface is bold | |||
| @param isItalic should be true if the typeface is italic | |||
| @param defaultCharacter the character to be used as a replacement if there's | |||
| no glyph available for the character that's being drawn | |||
| @param fontFamily the typeface's font family | |||
| @param ascent the ascent - this is normalised to a height of 1.0 and this is | |||
| the value that will be returned by Typeface::getAscent(). The | |||
| descent is assumed to be (1.0 - ascent) | |||
| @param isBold should be true if the typeface is bold | |||
| @param isItalic should be true if the typeface is italic | |||
| @param defaultCharacter the character to be used as a replacement if there's | |||
| no glyph available for the character that's being drawn | |||
| */ | |||
| void setCharacteristics (const String& name, float ascent, | |||
| void setCharacteristics (const String& fontFamily, float ascent, | |||
| bool isBold, bool isItalic, | |||
| juce_wchar defaultCharacter) noexcept; | |||
| /** Sets the vital statistics for the typeface. | |||
| @param fontFamily the typeface's font family | |||
| @param fontStyle the typeface's font style | |||
| @param ascent the ascent - this is normalised to a height of 1.0 and this is | |||
| the value that will be returned by Typeface::getAscent(). The | |||
| descent is assumed to be (1.0 - ascent) | |||
| @param defaultCharacter the character to be used as a replacement if there's | |||
| no glyph available for the character that's being drawn | |||
| */ | |||
| void setCharacteristics (const String& fontFamily, const String& fontStyle, | |||
| float ascent, juce_wchar defaultCharacter) noexcept; | |||
| /** Adds a glyph to the typeface. | |||
| The path that is passed in is normalised so that the font height is 1.0, and its | |||
| @@ -117,7 +129,6 @@ protected: | |||
| //============================================================================== | |||
| juce_wchar defaultCharacter; | |||
| float ascent; | |||
| bool isBold, isItalic; | |||
| //============================================================================== | |||
| /** If a subclass overrides this, it can load glyphs into the font on-demand. | |||
| @@ -32,6 +32,7 @@ namespace FontValues | |||
| const float defaultFontHeight = 14.0f; | |||
| String fallbackFont; | |||
| String fallbackFontStyle; | |||
| } | |||
| typedef Typeface::Ptr (*GetTypefaceForFont) (const Font&); | |||
| @@ -62,16 +63,18 @@ public: | |||
| Typeface::Ptr findTypefaceFor (const Font& font) | |||
| { | |||
| const int flags = font.getStyleFlags() & (Font::bold | Font::italic); | |||
| const String faceName (font.getTypefaceName()); | |||
| const String faceStyle (font.getTypefaceStyle()); | |||
| int i; | |||
| for (i = faces.size(); --i >= 0;) | |||
| jassert (faceName.isNotEmpty()); | |||
| for (int i = faces.size(); --i >= 0;) | |||
| { | |||
| CachedFace& face = faces.getReference(i); | |||
| if (face.flags == flags | |||
| && face.typefaceName == faceName | |||
| if (face.typefaceName == faceName | |||
| && face.typefaceStyle == faceStyle | |||
| && face.typeface != nullptr | |||
| && face.typeface->isSuitableForFont (font)) | |||
| { | |||
| face.lastUsageCount = ++counter; | |||
| @@ -82,7 +85,7 @@ public: | |||
| int replaceIndex = 0; | |||
| size_t bestLastUsageCount = std::numeric_limits<int>::max(); | |||
| for (i = faces.size(); --i >= 0;) | |||
| for (int i = faces.size(); --i >= 0;) | |||
| { | |||
| const size_t lu = faces.getReference(i).lastUsageCount; | |||
| @@ -95,7 +98,7 @@ public: | |||
| CachedFace& face = faces.getReference (replaceIndex); | |||
| face.typefaceName = faceName; | |||
| face.flags = flags; | |||
| face.typefaceStyle = faceStyle; | |||
| face.lastUsageCount = ++counter; | |||
| if (juce_getTypefaceForFont == nullptr) | |||
| @@ -120,7 +123,7 @@ private: | |||
| struct CachedFace | |||
| { | |||
| CachedFace() noexcept | |||
| : lastUsageCount (0), flags (-1) | |||
| : lastUsageCount (0) | |||
| { | |||
| } | |||
| @@ -129,8 +132,8 @@ private: | |||
| // Since the typeface itself doesn't know that it may have this alias, the name under | |||
| // which it was fetched needs to be stored separately. | |||
| String typefaceName; | |||
| String typefaceStyle; | |||
| size_t lastUsageCount; | |||
| int flags; | |||
| Typeface::Ptr typeface; | |||
| }; | |||
| @@ -152,47 +155,54 @@ void Typeface::setTypefaceCacheSize (int numFontsToCache) | |||
| class Font::SharedFontInternal : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| SharedFontInternal (const float height_, const int styleFlags_) noexcept | |||
| SharedFontInternal (const String& typefaceStyle_, const float height_) noexcept | |||
| : typefaceName (Font::getDefaultSansSerifFontName()), | |||
| typefaceStyle (typefaceStyle_), | |||
| height (height_), | |||
| horizontalScale (1.0f), | |||
| kerning (0), | |||
| ascent (0), | |||
| styleFlags (styleFlags_), | |||
| typeface ((styleFlags_ & (Font::bold | Font::italic)) == 0 | |||
| underline (false), | |||
| typeface (typefaceStyle_ == Font::getDefaultStyle() | |||
| ? TypefaceCache::getInstance()->getDefaultTypeface() : nullptr) | |||
| { | |||
| } | |||
| SharedFontInternal (const String& typefaceName_, const float height_, const int styleFlags_) noexcept | |||
| SharedFontInternal (const String& typefaceName_, const String& typefaceStyle_, const float height_) noexcept | |||
| : typefaceName (typefaceName_), | |||
| typefaceStyle (typefaceStyle_), | |||
| height (height_), | |||
| horizontalScale (1.0f), | |||
| kerning (0), | |||
| ascent (0), | |||
| styleFlags (styleFlags_), | |||
| underline (false), | |||
| typeface (nullptr) | |||
| { | |||
| if (typefaceName.isEmpty()) | |||
| typefaceName = Font::getDefaultSansSerifFontName(); | |||
| } | |||
| SharedFontInternal (const Typeface::Ptr& typeface_) noexcept | |||
| : typefaceName (typeface_->getName()), | |||
| typefaceStyle (typeface_->getStyle()), | |||
| height (FontValues::defaultFontHeight), | |||
| horizontalScale (1.0f), | |||
| kerning (0), | |||
| ascent (0), | |||
| styleFlags (Font::plain), | |||
| underline (false), | |||
| typeface (typeface_) | |||
| { | |||
| jassert (typefaceName.isNotEmpty()); | |||
| } | |||
| SharedFontInternal (const SharedFontInternal& other) noexcept | |||
| : typefaceName (other.typefaceName), | |||
| typefaceStyle (other.typefaceStyle), | |||
| height (other.height), | |||
| horizontalScale (other.horizontalScale), | |||
| kerning (other.kerning), | |||
| ascent (other.ascent), | |||
| styleFlags (other.styleFlags), | |||
| underline (other.underline), | |||
| typeface (other.typeface) | |||
| { | |||
| } | |||
| @@ -200,31 +210,44 @@ public: | |||
| bool operator== (const SharedFontInternal& other) const noexcept | |||
| { | |||
| return height == other.height | |||
| && styleFlags == other.styleFlags | |||
| && underline == other.underline | |||
| && horizontalScale == other.horizontalScale | |||
| && kerning == other.kerning | |||
| && typefaceName == other.typefaceName; | |||
| && typefaceName == other.typefaceName | |||
| && typefaceStyle == other.typefaceStyle; | |||
| } | |||
| String typefaceName; | |||
| String typefaceName, typefaceStyle; | |||
| float height, horizontalScale, kerning, ascent; | |||
| int styleFlags; | |||
| bool underline; | |||
| Typeface::Ptr typeface; | |||
| }; | |||
| //============================================================================== | |||
| Font::Font() | |||
| : font (new SharedFontInternal (FontValues::defaultFontHeight, Font::plain)) | |||
| : font (new SharedFontInternal (Font::getDefaultStyle(), FontValues::defaultFontHeight)) | |||
| { | |||
| } | |||
| Font::Font (const float fontHeight, const int styleFlags) | |||
| : font (new SharedFontInternal (FontValues::limitFontHeight (fontHeight), styleFlags)) | |||
| : font (new SharedFontInternal (Font::getDefaultStyle(), FontValues::limitFontHeight (fontHeight))) | |||
| { | |||
| setStyleFlags(styleFlags); | |||
| } | |||
| Font::Font (const String& typefaceName, const float fontHeight, const int styleFlags) | |||
| : font (new SharedFontInternal (typefaceName, FontValues::limitFontHeight (fontHeight), styleFlags)) | |||
| : font (new SharedFontInternal (typefaceName, Font::getDefaultStyle(), FontValues::limitFontHeight (fontHeight))) | |||
| { | |||
| setStyleFlags (styleFlags); | |||
| } | |||
| Font::Font (const String& typefaceStyle, float fontHeight) | |||
| : font (new SharedFontInternal (typefaceStyle, FontValues::limitFontHeight (fontHeight))) | |||
| { | |||
| } | |||
| Font::Font (const String& typefaceName, const String& typefaceStyle, float fontHeight) | |||
| : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight))) | |||
| { | |||
| } | |||
| @@ -297,6 +320,12 @@ const String& Font::getDefaultMonospacedFontName() | |||
| return name; | |||
| } | |||
| const String& Font::getDefaultStyle() | |||
| { | |||
| static const String style ("<Regular>"); | |||
| return style; | |||
| } | |||
| const String& Font::getTypefaceName() const noexcept | |||
| { | |||
| return font->typefaceName; | |||
| @@ -306,6 +335,8 @@ void Font::setTypefaceName (const String& faceName) | |||
| { | |||
| if (faceName != font->typefaceName) | |||
| { | |||
| jassert (faceName.isNotEmpty()); | |||
| dupeInternalIfShared(); | |||
| font->typefaceName = faceName; | |||
| font->typeface = nullptr; | |||
| @@ -313,6 +344,22 @@ void Font::setTypefaceName (const String& faceName) | |||
| } | |||
| } | |||
| const String& Font::getTypefaceStyle() const noexcept | |||
| { | |||
| return font->typefaceStyle; | |||
| } | |||
| void Font::setTypefaceStyle (const String& typefaceStyle) | |||
| { | |||
| if (typefaceStyle != font->typefaceStyle) | |||
| { | |||
| dupeInternalIfShared(); | |||
| font->typefaceStyle = typefaceStyle; | |||
| font->typeface = nullptr; | |||
| font->ascent = 0; | |||
| } | |||
| } | |||
| Typeface* Font::getTypeface() const | |||
| { | |||
| if (font->typeface == nullptr) | |||
| @@ -336,6 +383,20 @@ void Font::setFallbackFontName (const String& name) | |||
| #endif | |||
| } | |||
| const String& Font::getFallbackFontStyle() | |||
| { | |||
| return FontValues::fallbackFontStyle; | |||
| } | |||
| void Font::setFallbackFontStyle (const String& style) | |||
| { | |||
| FontValues::fallbackFontStyle = style; | |||
| #if JUCE_MAC || JUCE_IOS | |||
| jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX.. | |||
| #endif | |||
| } | |||
| //============================================================================== | |||
| float Font::getHeight() const noexcept | |||
| { | |||
| @@ -374,7 +435,12 @@ void Font::setHeightWithoutChangingWidth (float newHeight) | |||
| int Font::getStyleFlags() const noexcept | |||
| { | |||
| return font->styleFlags; | |||
| int styleFlags = font->underline ? underlined : plain; | |||
| if (isBold()) styleFlags |= bold; | |||
| if (isItalic()) styleFlags |= italic; | |||
| return styleFlags; | |||
| } | |||
| Font Font::withStyle (const int newFlags) const | |||
| @@ -386,10 +452,12 @@ Font Font::withStyle (const int newFlags) const | |||
| void Font::setStyleFlags (const int newFlags) | |||
| { | |||
| if (font->styleFlags != newFlags) | |||
| if (getStyleFlags() != newFlags) | |||
| { | |||
| dupeInternalIfShared(); | |||
| font->styleFlags = newFlags; | |||
| font->typefaceStyle = FontStyleHelpers::getStyleName ((newFlags & bold) != 0, | |||
| (newFlags & italic) != 0); | |||
| font->underline = (newFlags & underlined) != 0; | |||
| font->typeface = nullptr; | |||
| font->ascent = 0; | |||
| } | |||
| @@ -415,6 +483,26 @@ void Font::setSizeAndStyle (float newHeight, | |||
| setStyleFlags (newStyleFlags); | |||
| } | |||
| void Font::setSizeAndStyle (float newHeight, | |||
| const String& newStyle, | |||
| const float newHorizontalScale, | |||
| const float newKerningAmount) | |||
| { | |||
| newHeight = FontValues::limitFontHeight (newHeight); | |||
| if (font->height != newHeight | |||
| || font->horizontalScale != newHorizontalScale | |||
| || font->kerning != newKerningAmount) | |||
| { | |||
| dupeInternalIfShared(); | |||
| font->height = newHeight; | |||
| font->horizontalScale = newHorizontalScale; | |||
| font->kerning = newKerningAmount; | |||
| } | |||
| setTypefaceStyle (newStyle); | |||
| } | |||
| float Font::getHorizontalScale() const noexcept | |||
| { | |||
| return font->horizontalScale; | |||
| @@ -451,33 +539,41 @@ void Font::setExtraKerningFactor (const float extraKerning) | |||
| font->kerning = extraKerning; | |||
| } | |||
| Font Font::boldened() const { return withStyle (font->styleFlags | bold); } | |||
| Font Font::italicised() const { return withStyle (font->styleFlags | italic); } | |||
| Font Font::boldened() const { return withStyle (getStyleFlags() | bold); } | |||
| Font Font::italicised() const { return withStyle (getStyleFlags() | italic); } | |||
| bool Font::isBold() const noexcept { return (font->styleFlags & bold) != 0; } | |||
| bool Font::isItalic() const noexcept { return (font->styleFlags & italic) != 0; } | |||
| bool Font::isBold() const noexcept | |||
| { | |||
| return FontStyleHelpers::isBold (font->typefaceStyle); | |||
| } | |||
| bool Font::isItalic() const noexcept | |||
| { | |||
| return FontStyleHelpers::isItalic (font->typefaceStyle); | |||
| } | |||
| void Font::setBold (const bool shouldBeBold) | |||
| { | |||
| setStyleFlags (shouldBeBold ? (font->styleFlags | bold) | |||
| : (font->styleFlags & ~bold)); | |||
| const int flags = getStyleFlags(); | |||
| setStyleFlags (shouldBeBold ? (flags | bold) | |||
| : (flags & ~bold)); | |||
| } | |||
| void Font::setItalic (const bool shouldBeItalic) | |||
| { | |||
| setStyleFlags (shouldBeItalic ? (font->styleFlags | italic) | |||
| : (font->styleFlags & ~italic)); | |||
| const int flags = getStyleFlags(); | |||
| setStyleFlags (shouldBeItalic ? (flags | italic) | |||
| : (flags & ~italic)); | |||
| } | |||
| void Font::setUnderline (const bool shouldBeUnderlined) | |||
| { | |||
| setStyleFlags (shouldBeUnderlined ? (font->styleFlags | underlined) | |||
| : (font->styleFlags & ~underlined)); | |||
| font->underline = shouldBeUnderlined; | |||
| } | |||
| bool Font::isUnderlined() const noexcept | |||
| { | |||
| return (font->styleFlags & underlined) != 0; | |||
| return font->underline; | |||
| } | |||
| float Font::getAscent() const | |||
| @@ -537,23 +633,30 @@ void Font::findFonts (Array<Font>& destArray) | |||
| const StringArray names (findAllTypefaceNames()); | |||
| for (int i = 0; i < names.size(); ++i) | |||
| destArray.add (Font (names[i], FontValues::defaultFontHeight, Font::plain)); | |||
| { | |||
| const StringArray styles (findAllTypefaceStyles (names[i])); | |||
| String style ("Regular"); | |||
| if (! styles.contains (style, true)) | |||
| style = styles[0]; | |||
| destArray.add (Font (names[i], style, FontValues::defaultFontHeight)); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| String Font::toString() const | |||
| { | |||
| String s (getTypefaceName()); | |||
| String s; | |||
| if (s == getDefaultSansSerifFontName()) | |||
| s = String::empty; | |||
| else | |||
| s += "; "; | |||
| if (getTypefaceName() != getDefaultSansSerifFontName()) | |||
| s << getTypefaceName() << "; "; | |||
| s += String (getHeight(), 1); | |||
| s << String (getHeight(), 1); | |||
| if (isBold()) s += " bold"; | |||
| if (isItalic()) s += " italic"; | |||
| if (getTypefaceStyle() != getDefaultStyle()) | |||
| s << ' ' << getTypefaceStyle(); | |||
| return s; | |||
| } | |||
| @@ -575,9 +678,7 @@ Font Font::fromString (const String& fontDescription) | |||
| if (height <= 0) | |||
| height = 10.0f; | |||
| int flags = Font::plain; | |||
| if (sizeAndStyle.containsIgnoreCase ("bold")) flags |= Font::bold; | |||
| if (sizeAndStyle.containsIgnoreCase ("italic")) flags |= Font::italic; | |||
| const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false)); | |||
| return Font (name, height, flags); | |||
| return Font (name, style, height); | |||
| } | |||
| @@ -68,7 +68,7 @@ public: | |||
| /** Creates a font with a given typeface and parameters. | |||
| @param typefaceName the name of the typeface to use | |||
| @param typefaceName the font family of the typeface to use | |||
| @param fontHeight the height in pixels (can be fractional) | |||
| @param styleFlags the style to use - this can be a combination of the | |||
| Font::bold, Font::italic and Font::underlined, or | |||
| @@ -77,6 +77,21 @@ public: | |||
| */ | |||
| Font (const String& typefaceName, float fontHeight, int styleFlags); | |||
| /** Creates a sans-serif font in a given style and size. | |||
| @param typefaceStyle the font style of the typeface to use | |||
| @param fontHeight the height in pixels (can be fractional) | |||
| */ | |||
| Font (const String& typefaceStyle, float fontHeight); | |||
| /** Creates a font with a given typeface and parameters. | |||
| @param typefaceName the font family of the typeface to use | |||
| @param typefaceStyle the font style of the typeface to use | |||
| @param fontHeight the height in pixels (can be fractional) | |||
| */ | |||
| Font (const String& typefaceName, const String& typefaceStyle, float fontHeight); | |||
| /** Creates a copy of another Font object. */ | |||
| Font (const Font& other) noexcept; | |||
| @@ -106,64 +121,88 @@ public: | |||
| ~Font() noexcept; | |||
| //============================================================================== | |||
| /** Changes the name of the typeface family. | |||
| /** Changes the font family of the typeface. | |||
| e.g. "Arial", "Courier", etc. | |||
| This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), | |||
| or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font names, | |||
| but are generic names that are used to represent the various default fonts. | |||
| If you need to know the exact typeface name being used, you can call | |||
| Font::getTypeface()->getTypefaceName(), which will give you the platform-specific name. | |||
| or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names, | |||
| but are generic font family names that are used to represent the various default fonts. | |||
| If you need to know the exact typeface font family being used, you can call | |||
| Font::getTypeface()->getFamily(), which will give you the platform-specific font family. | |||
| If a suitable font isn't found on the machine, it'll just use a default instead. | |||
| */ | |||
| void setTypefaceName (const String& faceName); | |||
| /** Returns the name of the typeface family that this font uses. | |||
| /** Returns the font family of the typeface that this font uses. | |||
| e.g. "Arial", "Courier", etc. | |||
| This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), | |||
| or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font names, | |||
| but are generic names that are used to represent the various default fonts. | |||
| or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names, | |||
| but are generic font familiy names that are used to represent the various default fonts. | |||
| If you need to know the exact typeface name being used, you can call | |||
| Font::getTypeface()->getTypefaceName(), which will give you the platform-specific name. | |||
| If you need to know the exact typeface font family being used, you can call | |||
| Font::getTypeface()->getFamily(), which will give you the platform-specific font family. | |||
| */ | |||
| const String& getTypefaceName() const noexcept; | |||
| //============================================================================== | |||
| /** Returns a typeface name that represents the default sans-serif font. | |||
| /** Changes the font style of the typeface | |||
| e.g. "Regular", "Italic", etc. | |||
| */ | |||
| void setTypefaceStyle (const String& typefaceStyle); | |||
| /** Returns the font style of the typeface that this font uses. | |||
| e.g. "Regular", "Italic", etc. | |||
| */ | |||
| const String& getTypefaceStyle() const noexcept; | |||
| //============================================================================== | |||
| /** Returns a typeface font family that represents the default sans-serif font. | |||
| This is also the typeface that will be used when a font is created without | |||
| specifying any typeface details. | |||
| Note that this method just returns a generic placeholder string that means "the default | |||
| sans-serif font" - it's not the actual name of this font. | |||
| sans-serif font" - it's not the actual font family of this font. | |||
| @see setTypefaceName, getDefaultSerifFontName, getDefaultMonospacedFontName | |||
| */ | |||
| static const String& getDefaultSansSerifFontName(); | |||
| /** Returns a typeface name that represents the default sans-serif font. | |||
| /** Returns a typeface font family that represents the default sans-serif font. | |||
| Note that this method just returns a generic placeholder string that means "the default | |||
| serif font" - it's not the actual name of this font. | |||
| serif font" - it's not the actual font family of this font. | |||
| @see setTypefaceName, getDefaultSansSerifFontName, getDefaultMonospacedFontName | |||
| */ | |||
| static const String& getDefaultSerifFontName(); | |||
| /** Returns a typeface name that represents the default sans-serif font. | |||
| /** Returns a typeface font family that represents the default sans-serif font. | |||
| Note that this method just returns a generic placeholder string that means "the default | |||
| monospaced font" - it's not the actual name of this font. | |||
| monospaced font" - it's not the actual font family of this font. | |||
| @see setTypefaceName, getDefaultSansSerifFontName, getDefaultSerifFontName | |||
| */ | |||
| static const String& getDefaultMonospacedFontName(); | |||
| /** Returns a typeface font style that represents the default sans-serif font. | |||
| Note that this method just returns a generic placeholder string that means "the default | |||
| font style" - it's not the actual font style of this font. | |||
| @see setTypefaceStyle | |||
| */ | |||
| static const String& getDefaultStyle(); | |||
| /** Returns the default system typeface for the given font. */ | |||
| static Typeface::Ptr getDefaultTypefaceForFont (const Font& font); | |||
| @@ -299,6 +338,12 @@ public: | |||
| float newHorizontalScale, | |||
| float newKerningAmount); | |||
| /** Changes all the font's characteristics with one call. */ | |||
| void setSizeAndStyle (float newHeight, | |||
| const String& newStyle, | |||
| float newHorizontalScale, | |||
| float newKerningAmount); | |||
| //============================================================================== | |||
| /** Returns the total width of a string as it would be drawn using this font. | |||
| @@ -329,33 +374,52 @@ public: | |||
| /** Creates an array of Font objects to represent all the fonts on the system. | |||
| If you just need the names of the typefaces, you can also use | |||
| If you just need the font family names of the typefaces, you can also use | |||
| findAllTypefaceNames() instead. | |||
| @param results the array to which new Font objects will be added. | |||
| */ | |||
| static void findFonts (Array<Font>& results); | |||
| /** Returns a list of all the available typeface names. | |||
| /** Returns a list of all the available typeface font families. | |||
| The names returned can be passed into setTypefaceName(). | |||
| You can use this instead of findFonts() if you only need their names, and not | |||
| font objects. | |||
| You can use this instead of findFonts() if you only need their font family names, | |||
| and not font objects. | |||
| */ | |||
| static StringArray findAllTypefaceNames(); | |||
| /** Returns a list of all the available typeface font styles. | |||
| The names returned can be passed into setTypefaceStyle(). | |||
| You can use this instead of findFonts() if you only need their styles, and not | |||
| font objects. | |||
| */ | |||
| static StringArray findAllTypefaceStyles (const String& family); | |||
| //============================================================================== | |||
| /** Returns the name of the typeface to be used for rendering glyphs that aren't found | |||
| in the requested typeface. | |||
| /** Returns the font family of the typeface to be used for rendering glyphs that aren't | |||
| found in the requested typeface. | |||
| */ | |||
| static const String& getFallbackFontName(); | |||
| /** Sets the (platform-specific) name of the typeface to use to find glyphs that aren't | |||
| available in whatever font you're trying to use. | |||
| /** Sets the (platform-specific) font family of the typeface to use to find glyphs that | |||
| aren't available in whatever font you're trying to use. | |||
| */ | |||
| static void setFallbackFontName (const String& name); | |||
| /** Returns the font style of the typeface to be used for rendering glyphs that aren't | |||
| found in the requested typeface. | |||
| */ | |||
| static const String& getFallbackFontStyle(); | |||
| /** Sets the (platform-specific) font style of the typeface to use to find glyphs that | |||
| aren't available in whatever font you're trying to use. | |||
| */ | |||
| static void setFallbackFontStyle (const String& style); | |||
| //============================================================================== | |||
| /** Creates a string to describe this font. | |||
| The string will contain information to describe the font's typeface, size, and | |||
| @@ -23,8 +23,45 @@ | |||
| ============================================================================== | |||
| */ | |||
| Typeface::Typeface (const String& name_) noexcept | |||
| : name (name_) | |||
| namespace FontStyleHelpers | |||
| { | |||
| static const char* getStyleName (const bool bold, | |||
| const bool italic) noexcept | |||
| { | |||
| if (bold && ! italic) return "Bold"; | |||
| if (italic && ! bold) return "Italic"; | |||
| if (bold && italic) return "Bold Italic"; | |||
| return "Regular"; | |||
| } | |||
| static bool isBold (const String& style) noexcept | |||
| { | |||
| return style.containsWholeWordIgnoreCase ("Bold"); | |||
| } | |||
| static bool isItalic (const String& style) noexcept | |||
| { | |||
| return style.containsWholeWordIgnoreCase ("Italic") | |||
| || style.containsWholeWordIgnoreCase ("Oblique"); | |||
| } | |||
| static bool isPlaceholderFamilyName (const String& family) | |||
| { | |||
| return family == Font::getDefaultSansSerifFontName() | |||
| || family == Font::getDefaultSerifFontName() | |||
| || family == Font::getDefaultMonospacedFontName(); | |||
| } | |||
| static String getConcreteFamilyNameFromPlaceholder (const String& family) | |||
| { | |||
| const Font f (family, Font::getDefaultStyle(), 15.0f); | |||
| return Font::getDefaultTypefaceForFont (f)->getName(); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| Typeface::Typeface (const String& name_, const String& style_) noexcept | |||
| : name (name_), style (style_) | |||
| { | |||
| } | |||
| @@ -34,7 +71,7 @@ Typeface::~Typeface() | |||
| Typeface::Ptr Typeface::getFallbackTypeface() | |||
| { | |||
| const Font fallbackFont (Font::getFallbackFontName(), 10, 0); | |||
| const Font fallbackFont (Font::getFallbackFontName(), Font::getFallbackFontStyle(), 10.0f); | |||
| return fallbackFont.getTypeface(); | |||
| } | |||
| @@ -55,11 +55,17 @@ public: | |||
| typedef ReferenceCountedObjectPtr <Typeface> Ptr; | |||
| //============================================================================== | |||
| /** Returns the name of the typeface. | |||
| /** Returns the font family of the typeface. | |||
| @see Font::getTypefaceName | |||
| */ | |||
| const String& getName() const noexcept { return name; } | |||
| //============================================================================== | |||
| /** Returns the font style of the typeface. | |||
| @see Font::getTypefaceStyle | |||
| */ | |||
| const String& getStyle() const noexcept { return style; } | |||
| //============================================================================== | |||
| /** Creates a new system typeface. */ | |||
| static Ptr createSystemTypefaceFor (const Font& font); | |||
| @@ -122,9 +128,9 @@ public: | |||
| protected: | |||
| //============================================================================== | |||
| String name; | |||
| String name, style; | |||
| explicit Typeface (const String& name) noexcept; | |||
| Typeface (const String& name, const String& style) noexcept; | |||
| static Ptr getFallbackTypeface(); | |||
| @@ -67,8 +67,6 @@ | |||
| namespace juce | |||
| { | |||
| // START_AUTOINCLUDE colour/*.cpp, geometry/*.cpp, placement/*.cpp, contexts/*.cpp, images/*.cpp, | |||
| // image_formats/*.cpp, fonts/*.cpp, effects/*.cpp | |||
| #include "colour/juce_Colour.cpp" | |||
| #include "colour/juce_ColourGradient.cpp" | |||
| #include "colour/juce_Colours.cpp" | |||
| @@ -92,14 +90,13 @@ namespace juce | |||
| #include "image_formats/juce_JPEGLoader.cpp" | |||
| #include "image_formats/juce_PNGLoader.cpp" | |||
| #include "fonts/juce_AttributedString.cpp" | |||
| #include "fonts/juce_Typeface.cpp" | |||
| #include "fonts/juce_CustomTypeface.cpp" | |||
| #include "fonts/juce_Font.cpp" | |||
| #include "fonts/juce_GlyphArrangement.cpp" | |||
| #include "fonts/juce_TextLayout.cpp" | |||
| #include "fonts/juce_Typeface.cpp" | |||
| #include "effects/juce_DropShadowEffect.cpp" | |||
| #include "effects/juce_GlowEffect.cpp" | |||
| // END_AUTOINCLUDE | |||
| //============================================================================== | |||
| #if JUCE_MAC || JUCE_IOS | |||
| @@ -41,7 +41,22 @@ StringArray Font::findAllTypefaceNames() | |||
| File ("/system/fonts").findChildFiles (fonts, File::findFiles, false, "*.ttf"); | |||
| for (int i = 0; i < fonts.size(); ++i) | |||
| results.add (fonts.getReference(i).getFileNameWithoutExtension()); | |||
| results.addIfNotAlreadyThere (fonts.getReference(i).getFileNameWithoutExtension() | |||
| .upToLastOccurrenceOf ("-", false, false)); | |||
| return results; | |||
| } | |||
| StringArray Font::findAllTypefaceStyles (const String& family) | |||
| { | |||
| StringArray results ("Regular"); | |||
| Array<File> fonts; | |||
| File ("/system/fonts").findChildFiles (fonts, File::findFiles, false, family + "-*.ttf"); | |||
| for (int i = 0; i < fonts.size(); ++i) | |||
| results.addIfNotAlreadyThere (fonts.getReference(i).getFileNameWithoutExtension() | |||
| .fromLastOccurrenceOf ("-", false, false)); | |||
| return results; | |||
| } | |||
| @@ -79,24 +94,27 @@ class AndroidTypeface : public Typeface | |||
| { | |||
| public: | |||
| AndroidTypeface (const Font& font) | |||
| : Typeface (font.getTypefaceName()), | |||
| : Typeface (font.getTypefaceName(), font.getTypefaceStyle()), | |||
| ascent (0), | |||
| descent (0) | |||
| { | |||
| jint flags = 0; | |||
| if (font.isBold()) flags = 1; | |||
| if (font.isItalic()) flags += 2; | |||
| JNIEnv* const env = getEnv(); | |||
| JNIEnv* env = getEnv(); | |||
| const bool isBold = style.contains ("Bold"); | |||
| const bool isItalic = style.contains ("Italic"); | |||
| File fontFile (getFontFile (name, style)); | |||
| File fontFile (File ("/system/fonts").getChildFile (name).withFileExtension (".ttf")); | |||
| if (! fontFile.exists()) | |||
| fontFile = findFontFile (name, isBold, isItalic); | |||
| if (fontFile.exists()) | |||
| typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile, | |||
| javaString (fontFile.getFullPathName()).get())); | |||
| else | |||
| typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create, | |||
| javaString (getName()).get(), flags)); | |||
| javaString (getName()).get(), | |||
| (isBold ? 1 : 0) + (isItalic ? 2 : 0))); | |||
| rect = GlobalRef (env->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0)); | |||
| @@ -212,6 +230,41 @@ public: | |||
| float ascent, descent, unitsToHeightScaleFactor; | |||
| private: | |||
| static File findFontFile (const String& family, | |||
| const bool bold, const bool italic) | |||
| { | |||
| File file; | |||
| if (bold || italic) | |||
| { | |||
| String suffix; | |||
| if (bold) suffix = "Bold"; | |||
| if (italic) suffix << "Italic"; | |||
| file = getFontFile (family, suffix); | |||
| if (file.exists()) | |||
| return file; | |||
| } | |||
| file = getFontFile (family, "Regular"); | |||
| if (! file.exists()) | |||
| file = getFontFile (family, String::empty); | |||
| return file; | |||
| } | |||
| static File getFontFile (const String& family, const String& style) | |||
| { | |||
| String path ("/system/fonts/" + family); | |||
| if (style.isNotEmpty()) | |||
| path << '-' << style; | |||
| return File (path + ".ttf"); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidTypeface); | |||
| }; | |||
| @@ -222,10 +222,29 @@ public: | |||
| } | |||
| //============================================================================== | |||
| void getFamilyNames (StringArray& familyNames) const | |||
| StringArray findAllFamilyNames() const | |||
| { | |||
| StringArray s; | |||
| for (int i = 0; i < faces.size(); i++) | |||
| familyNames.addIfNotAlreadyThere (faces.getUnchecked(i)->family); | |||
| s.addIfNotAlreadyThere (faces.getUnchecked(i)->family); | |||
| return s; | |||
| } | |||
| StringArray findAllTypefaceStyles (const String& family) const | |||
| { | |||
| StringArray s; | |||
| for (int i = 0; i < faces.size(); i++) | |||
| { | |||
| const KnownTypeface* const face = faces.getUnchecked(i); | |||
| if (face->family == family) | |||
| s.addIfNotAlreadyThere (FontStyleHelpers::getStyleName (face->isBold, face->isItalic)); | |||
| } | |||
| return s; | |||
| } | |||
| void getMonospacedNames (StringArray& monoSpaced) const | |||
| @@ -298,14 +317,13 @@ public: | |||
| if (faceWrapper != nullptr) | |||
| { | |||
| setCharacteristics (font.getTypefaceName(), | |||
| font.getTypefaceStyle(), | |||
| faceWrapper->face->ascender / (float) (faceWrapper->face->ascender - faceWrapper->face->descender), | |||
| font.isBold(), font.isItalic(), | |||
| L' '); | |||
| } | |||
| else | |||
| { | |||
| DBG ("Failed to create typeface: " << font.getTypefaceName() << " " | |||
| << (font.isBold() ? 'B' : ' ') << (font.isItalic() ? 'I' : ' ')); | |||
| DBG ("Failed to create typeface: " << font.toString()); | |||
| } | |||
| } | |||
| @@ -457,10 +475,12 @@ Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) | |||
| StringArray Font::findAllTypefaceNames() | |||
| { | |||
| StringArray s; | |||
| FTTypefaceList::getInstance()->getFamilyNames (s); | |||
| s.sort (true); | |||
| return s; | |||
| return FTTypefaceList::getInstance()->findAllFamilyNames(); | |||
| } | |||
| StringArray Font::findAllTypefaceStyles (const String& family) | |||
| { | |||
| return FTTypefaceList::getInstance()->findAllTypefaceStyles (family); | |||
| } | |||
| //============================================================================== | |||
| @@ -480,17 +500,16 @@ private: | |||
| { | |||
| const StringArray choices (choicesArray); | |||
| int j; | |||
| for (j = 0; j < choices.size(); ++j) | |||
| for (int j = 0; j < choices.size(); ++j) | |||
| if (names.contains (choices[j], true)) | |||
| return choices[j]; | |||
| for (j = 0; j < choices.size(); ++j) | |||
| for (int j = 0; j < choices.size(); ++j) | |||
| for (int i = 0; i < names.size(); ++i) | |||
| if (names[i].startsWithIgnoreCase (choices[j])) | |||
| return names[i]; | |||
| for (j = 0; j < choices.size(); ++j) | |||
| for (int j = 0; j < choices.size(); ++j) | |||
| for (int i = 0; i < names.size(); ++i) | |||
| if (names[i].containsIgnoreCase (choices[j])) | |||
| return names[i]; | |||
| @@ -34,52 +34,37 @@ | |||
| namespace CoreTextTypeLayout | |||
| { | |||
| static CTFontRef createCTFont (const Font& font, const float fontSize, | |||
| const bool applyScaleFactor, bool& needsItalicTransform) | |||
| const bool applyScaleFactor) | |||
| { | |||
| CFStringRef cfName = font.getTypefaceName().toCFString(); | |||
| CTFontRef ctFontRef = CTFontCreateWithName (cfName, fontSize, nullptr); | |||
| CFRelease (cfName); | |||
| if (ctFontRef != nullptr) | |||
| CFStringRef cfFontFamily = font.getTypefaceName().toCFString(); | |||
| CFStringRef cfFontStyle = font.getTypefaceStyle().toCFString(); | |||
| CFStringRef keys[] = { kCTFontFamilyNameAttribute, kCTFontStyleNameAttribute }; | |||
| CFTypeRef values[] = { cfFontFamily, cfFontStyle }; | |||
| CFDictionaryRef fontDescAttributes = CFDictionaryCreate (nullptr, (const void**) &keys, | |||
| (const void**) &values, | |||
| numElementsInArray (keys), | |||
| &kCFTypeDictionaryKeyCallBacks, | |||
| &kCFTypeDictionaryValueCallBacks); | |||
| CFRelease (cfFontStyle); | |||
| CFRelease (cfFontFamily); | |||
| CTFontDescriptorRef ctFontDescRef = CTFontDescriptorCreateWithAttributes (fontDescAttributes); | |||
| CFRelease (fontDescAttributes); | |||
| CTFontRef ctFontRef = CTFontCreateWithFontDescriptor (ctFontDescRef, fontSize, nullptr); | |||
| CFRelease (ctFontDescRef); | |||
| if (applyScaleFactor) | |||
| { | |||
| if (font.isItalic()) | |||
| { | |||
| CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits (ctFontRef, 0.0f, nullptr, | |||
| kCTFontItalicTrait, kCTFontItalicTrait); | |||
| if (newFont != nullptr) | |||
| { | |||
| CFRelease (ctFontRef); | |||
| ctFontRef = newFont; | |||
| } | |||
| else | |||
| { | |||
| needsItalicTransform = true; // couldn't find a proper italic version, so fake it with a transform.. | |||
| } | |||
| } | |||
| if (font.isBold()) | |||
| { | |||
| CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits (ctFontRef, 0.0f, nullptr, | |||
| kCTFontBoldTrait, kCTFontBoldTrait); | |||
| if (newFont != nullptr) | |||
| { | |||
| CFRelease (ctFontRef); | |||
| ctFontRef = newFont; | |||
| } | |||
| } | |||
| CGFontRef cgFontRef = CTFontCopyGraphicsFont (ctFontRef, nullptr); | |||
| const int totalHeight = std::abs (CGFontGetAscent (cgFontRef)) + std::abs (CGFontGetDescent (cgFontRef)); | |||
| const float factor = CGFontGetUnitsPerEm (cgFontRef) / (float) totalHeight; | |||
| CGFontRelease (cgFontRef); | |||
| if (applyScaleFactor) | |||
| { | |||
| CGFontRef cgFontRef = CTFontCopyGraphicsFont (ctFontRef, nullptr); | |||
| const int totalHeight = std::abs (CGFontGetAscent (cgFontRef)) + std::abs (CGFontGetDescent (cgFontRef)); | |||
| const float factor = CGFontGetUnitsPerEm (cgFontRef) / (float) totalHeight; | |||
| CGFontRelease (cgFontRef); | |||
| CTFontRef newFont = CTFontCreateCopyWithAttributes (ctFontRef, fontSize * factor, nullptr, nullptr); | |||
| CFRelease (ctFontRef); | |||
| ctFontRef = newFont; | |||
| } | |||
| CTFontRef newFont = CTFontCreateCopyWithAttributes (ctFontRef, fontSize * factor, nullptr, nullptr); | |||
| CFRelease (ctFontRef); | |||
| ctFontRef = newFont; | |||
| } | |||
| return ctFontRef; | |||
| @@ -164,8 +149,7 @@ namespace CoreTextTypeLayout | |||
| if (attr->getFont() != nullptr) | |||
| { | |||
| const Font& f = *attr->getFont(); | |||
| bool needsItalicTransform = false; | |||
| CTFontRef ctFontRef = createCTFont (f, f.getHeight(), true, needsItalicTransform); | |||
| CTFontRef ctFontRef = createCTFont (f, f.getHeight(), true); | |||
| CFAttributedStringSetAttribute (attribString, CFRangeMake (range.getStart(), range.getLength()), | |||
| kCTFontAttributeName, ctFontRef); | |||
| @@ -317,17 +301,24 @@ namespace CoreTextTypeLayout | |||
| CTFontRef ctRunFont; | |||
| if (CFDictionaryGetValueIfPresent (runAttributes, kCTFontAttributeName, (const void **) &ctRunFont)) | |||
| { | |||
| CFStringRef cfsFontName = CTFontCopyPostScriptName (ctRunFont); | |||
| CTFontRef ctFontRef = CTFontCreateWithName (cfsFontName, 1024, nullptr); | |||
| CTFontDescriptorRef ctFontDescRef = CTFontCopyFontDescriptor (ctRunFont); | |||
| CFDictionaryRef fontDescAttributes = CTFontDescriptorCopyAttributes (ctFontDescRef); | |||
| CTFontRef ctFontRef = CTFontCreateWithFontDescriptor (ctFontDescRef, 1024, nullptr); | |||
| CFRelease (ctFontDescRef); | |||
| CGFontRef cgFontRef = CTFontCopyGraphicsFont (ctFontRef, nullptr); | |||
| CFRelease (ctFontRef); | |||
| const int totalHeight = std::abs (CGFontGetAscent (cgFontRef)) + std::abs (CGFontGetDescent (cgFontRef)); | |||
| const float fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (cgFontRef) / (float) totalHeight; | |||
| CGFontRelease (cgFontRef); | |||
| glyphRun->font = Font (String::fromCFString (cfsFontName), | |||
| CTFontGetSize (ctRunFont) / fontHeightToCGSizeFactor, 0); // XXX bold/italic flags? | |||
| CFRelease (cfsFontName); | |||
| CFStringRef cfsFontFamily = (CFStringRef) CFDictionaryGetValue (fontDescAttributes, kCTFontFamilyNameAttribute); | |||
| CFStringRef cfsFontStyle = (CFStringRef) CFDictionaryGetValue (fontDescAttributes, kCTFontStyleNameAttribute); | |||
| glyphRun->font = Font (String::fromCFString (cfsFontFamily), | |||
| String::fromCFString (cfsFontStyle), | |||
| CTFontGetSize (ctRunFont) / fontHeightToCGSizeFactor); | |||
| CFRelease (fontDescAttributes); | |||
| } | |||
| CGColorRef cgRunColor; | |||
| @@ -360,7 +351,8 @@ class OSXTypeface : public Typeface | |||
| { | |||
| public: | |||
| OSXTypeface (const Font& font) | |||
| : Typeface (font.getTypefaceName()), | |||
| : Typeface (font.getTypefaceName(), | |||
| font.getTypefaceStyle()), | |||
| fontRef (nullptr), | |||
| fontHeightToCGSizeFactor (1.0f), | |||
| renderingTransform (CGAffineTransformIdentity), | |||
| @@ -369,8 +361,7 @@ public: | |||
| ascent (0.0f), | |||
| unitsToHeightScaleFactor (0.0f) | |||
| { | |||
| bool needsItalicTransform = false; | |||
| ctFontRef = CoreTextTypeLayout::createCTFont (font, 1024.0f, false, needsItalicTransform); | |||
| ctFontRef = CoreTextTypeLayout::createCTFont (font, 1024.0f, false); | |||
| if (ctFontRef != nullptr) | |||
| { | |||
| @@ -380,12 +371,6 @@ public: | |||
| pathTransform = AffineTransform::identity.scale (1.0f / totalSize, 1.0f / totalSize); | |||
| if (needsItalicTransform) | |||
| { | |||
| pathTransform = pathTransform.sheared (-0.15f, 0.0f); | |||
| renderingTransform.c = 0.15f; | |||
| } | |||
| fontRef = CTFontCopyGraphicsFont (ctFontRef, nullptr); | |||
| const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef)); | |||
| @@ -550,6 +535,87 @@ private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface); | |||
| }; | |||
| StringArray Font::findAllTypefaceNames() | |||
| { | |||
| StringArray names; | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5 && ! JUCE_IOS | |||
| // CTFontManager only exists on OS X 10.6 and later, it does not exist on iOS | |||
| CFArrayRef fontFamilyArray = CTFontManagerCopyAvailableFontFamilyNames(); | |||
| for (CFIndex i = 0; i < CFArrayGetCount (fontFamilyArray); ++i) | |||
| { | |||
| const String family (String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (fontFamilyArray, i))); | |||
| if (! family.startsWithChar ('.')) // ignore fonts that start with a '.' | |||
| names.addIfNotAlreadyThere (family); | |||
| } | |||
| CFRelease (fontFamilyArray); | |||
| #else | |||
| CTFontCollectionRef fontCollectionRef = CTFontCollectionCreateFromAvailableFonts (nullptr); | |||
| CFArrayRef fontDescriptorArray = CTFontCollectionCreateMatchingFontDescriptors (fontCollectionRef); | |||
| CFRelease (fontCollectionRef); | |||
| for (CFIndex i = 0; i < CFArrayGetCount (fontDescriptorArray); ++i) | |||
| { | |||
| CTFontDescriptorRef ctFontDescriptorRef = (CTFontDescriptorRef) CFArrayGetValueAtIndex (fontDescriptorArray, i); | |||
| CFStringRef cfsFontFamily = (CFStringRef) CTFontDescriptorCopyAttribute (ctFontDescriptorRef, kCTFontFamilyNameAttribute); | |||
| names.addIfNotAlreadyThere (String::fromCFString (cfsFontFamily)); | |||
| CFRelease (cfsFontFamily); | |||
| } | |||
| CFRelease (fontDescriptorArray); | |||
| #endif | |||
| names.sort (true); | |||
| return names; | |||
| } | |||
| StringArray Font::findAllTypefaceStyles (const String& family) | |||
| { | |||
| if (FontStyleHelpers::isPlaceholderFamilyName (family)) | |||
| return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family)); | |||
| StringArray results; | |||
| CFStringRef cfsFontFamily = family.toCFString(); | |||
| CFStringRef keys[] = { kCTFontFamilyNameAttribute }; | |||
| CFTypeRef values[] = { cfsFontFamily }; | |||
| CFDictionaryRef fontDescAttributes = CFDictionaryCreate (nullptr, (const void**) &keys, (const void**) &values, numElementsInArray (keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |||
| CFRelease (cfsFontFamily); | |||
| CTFontDescriptorRef ctFontDescRef = CTFontDescriptorCreateWithAttributes (fontDescAttributes); | |||
| CFRelease (fontDescAttributes); | |||
| CFArrayRef fontFamilyArray = CFArrayCreate(kCFAllocatorDefault, (const void**) &ctFontDescRef, 1, &kCFTypeArrayCallBacks); | |||
| CFRelease (ctFontDescRef); | |||
| CTFontCollectionRef fontCollectionRef = CTFontCollectionCreateWithFontDescriptors (fontFamilyArray, nullptr); | |||
| CFRelease (fontFamilyArray); | |||
| CFArrayRef fontDescriptorArray = CTFontCollectionCreateMatchingFontDescriptors (fontCollectionRef); | |||
| CFRelease (fontCollectionRef); | |||
| if (fontDescriptorArray != nullptr) | |||
| { | |||
| for (CFIndex i = 0; i < CFArrayGetCount (fontDescriptorArray); ++i) | |||
| { | |||
| CTFontDescriptorRef ctFontDescriptorRef = (CTFontDescriptorRef) CFArrayGetValueAtIndex (fontDescriptorArray, i); | |||
| CFStringRef cfsFontStyle = (CFStringRef) CTFontDescriptorCopyAttribute (ctFontDescriptorRef, kCTFontStyleNameAttribute); | |||
| results.add (String::fromCFString (cfsFontStyle)); | |||
| CFRelease (cfsFontStyle); | |||
| } | |||
| CFRelease (fontDescriptorArray); | |||
| } | |||
| return results; | |||
| } | |||
| #else | |||
| //============================================================================== | |||
| @@ -580,49 +646,13 @@ class OSXTypeface : public Typeface | |||
| { | |||
| public: | |||
| OSXTypeface (const Font& font) | |||
| : Typeface (font.getTypefaceName()) | |||
| : Typeface (font.getTypefaceName(), font.getTypefaceStyle()) | |||
| { | |||
| JUCE_AUTORELEASEPOOL | |||
| renderingTransform = CGAffineTransformIdentity; | |||
| bool needsItalicTransform = false; | |||
| #if JUCE_IOS | |||
| NSString* fontName = juceStringToNS (font.getTypefaceName()); | |||
| if (font.isItalic() || font.isBold()) | |||
| { | |||
| NSArray* familyFonts = [UIFont fontNamesForFamilyName: juceStringToNS (font.getTypefaceName())]; | |||
| for (NSString* i in familyFonts) | |||
| { | |||
| const String fn (nsStringToJuce (i)); | |||
| const String afterDash (fn.fromFirstOccurrenceOf ("-", false, false)); | |||
| const bool probablyBold = afterDash.containsIgnoreCase ("bold") || fn.endsWithIgnoreCase ("bold"); | |||
| const bool probablyItalic = afterDash.containsIgnoreCase ("oblique") | |||
| || afterDash.containsIgnoreCase ("italic") | |||
| || fn.endsWithIgnoreCase ("oblique") | |||
| || fn.endsWithIgnoreCase ("italic"); | |||
| if (probablyBold == font.isBold() | |||
| && probablyItalic == font.isItalic()) | |||
| { | |||
| fontName = i; | |||
| needsItalicTransform = false; | |||
| break; | |||
| } | |||
| else if (probablyBold && (! probablyItalic) && probablyBold == font.isBold()) | |||
| { | |||
| fontName = i; | |||
| needsItalicTransform = true; // not ideal, so carry on in case we find a better one | |||
| } | |||
| } | |||
| if (needsItalicTransform) | |||
| renderingTransform.c = 0.15f; | |||
| } | |||
| NSString* fontName = juceStringToNS (style); | |||
| fontRef = CGFontCreateWithFontName ((CFStringRef) fontName); | |||
| if (fontRef == 0) | |||
| @@ -638,21 +668,12 @@ public: | |||
| unitsToHeightScaleFactor = 1.0f / totalHeight; | |||
| fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / totalHeight; | |||
| #else | |||
| nsFont = [NSFont fontWithName: juceStringToNS (font.getTypefaceName()) size: 1024]; | |||
| NSDictionary* nsDict = [NSDictionary dictionaryWithObjectsAndKeys: | |||
| juceStringToNS (name), NSFontFamilyAttribute, | |||
| juceStringToNS (style), NSFontFaceAttribute, nil]; | |||
| if (font.isItalic()) | |||
| { | |||
| NSFont* newFont = [[NSFontManager sharedFontManager] convertFont: nsFont | |||
| toHaveTrait: NSItalicFontMask]; | |||
| if (newFont == nsFont) | |||
| needsItalicTransform = true; // couldn't find a proper italic version, so fake it with a transform.. | |||
| nsFont = newFont; | |||
| } | |||
| if (font.isBold()) | |||
| nsFont = [[NSFontManager sharedFontManager] convertFont: nsFont toHaveTrait: NSBoldFontMask]; | |||
| NSFontDescriptor* nsFontDesc = [NSFontDescriptor fontDescriptorWithFontAttributes: nsDict]; | |||
| nsFont = [NSFont fontWithDescriptor: nsFontDesc size: 1024]; | |||
| [nsFont retain]; | |||
| @@ -662,12 +683,6 @@ public: | |||
| pathTransform = AffineTransform::identity.scale (1.0f / totalSize, 1.0f / totalSize); | |||
| if (needsItalicTransform) | |||
| { | |||
| pathTransform = pathTransform.sheared (-0.15f, 0.0f); | |||
| renderingTransform.c = 0.15f; | |||
| } | |||
| #if SUPPORT_ONLY_10_4_FONTS | |||
| ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault); | |||
| @@ -910,7 +925,7 @@ private: | |||
| #endif | |||
| } | |||
| #if ! SUPPORT_ONLY_10_4_FONTS | |||
| #if ! SUPPORT_ONLY_10_4_FONTS | |||
| // Reads a CGFontRef's character map table to convert unicode into glyph numbers | |||
| class CharToGlyphMapper | |||
| { | |||
| @@ -1009,23 +1024,14 @@ private: | |||
| }; | |||
| ScopedPointer <CharToGlyphMapper> charToGlyphMapper; | |||
| #endif | |||
| #endif | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface); | |||
| }; | |||
| #endif | |||
| //============================================================================== | |||
| Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) | |||
| { | |||
| return new OSXTypeface (font); | |||
| } | |||
| StringArray Font::findAllTypefaceNames() | |||
| { | |||
| StringArray names; | |||
| JUCE_AUTORELEASEPOOL | |||
| #if JUCE_IOS | |||
| @@ -1041,6 +1047,43 @@ StringArray Font::findAllTypefaceNames() | |||
| return names; | |||
| } | |||
| StringArray Font::findAllTypefaceStyles (const String& family) | |||
| { | |||
| if (FontStyleHelpers::isPlaceholderFamilyName (family)) | |||
| return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family)); | |||
| StringArray results; | |||
| JUCE_AUTORELEASEPOOL | |||
| #if JUCE_IOS | |||
| NSArray* styles = [UIFont fontNamesForFamilyName: juceStringToNS (family)]; | |||
| #else | |||
| NSArray* styles = [[NSFontManager sharedFontManager] availableMembersOfFontFamily: juceStringToNS (family)]; | |||
| #endif | |||
| for (unsigned int i = 0; i < [styles count]; ++i) | |||
| { | |||
| #if JUCE_IOS | |||
| // Fonts are returned in the form of "Arial-BoldMT" | |||
| results.add (nsStringToJuce ((NSString*) [styles objectAtIndex: i])); | |||
| #else | |||
| NSArray* style = [styles objectAtIndex: i]; | |||
| results.add (nsStringToJuce ((NSString*) [style objectAtIndex: 1])); | |||
| #endif | |||
| } | |||
| return results; | |||
| } | |||
| #endif | |||
| //============================================================================== | |||
| Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) | |||
| { | |||
| return new OSXTypeface (font); | |||
| } | |||
| struct DefaultFontNames | |||
| { | |||
| DefaultFontNames() | |||
| @@ -1064,15 +1107,24 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) | |||
| { | |||
| static DefaultFontNames defaultNames; | |||
| String faceName (font.getTypefaceName()); | |||
| Font newFont (font); | |||
| const String& faceName = font.getTypefaceName(); | |||
| if (faceName == Font::getDefaultSansSerifFontName()) faceName = defaultNames.defaultSans; | |||
| else if (faceName == Font::getDefaultSerifFontName()) faceName = defaultNames.defaultSerif; | |||
| else if (faceName == Font::getDefaultMonospacedFontName()) faceName = defaultNames.defaultFixed; | |||
| if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans); | |||
| else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif); | |||
| else if (faceName == getDefaultMonospacedFontName()) newFont.setTypefaceName (defaultNames.defaultFixed); | |||
| if (font.getTypefaceStyle() == getDefaultStyle()) | |||
| newFont.setTypefaceStyle ("Regular"); | |||
| #if JUCE_IOS && ! JUCE_CORETEXT_AVAILABLE | |||
| // Fonts style names on Cocoa Touch are unusual like "Arial-BoldMT" | |||
| // No font will be found for the style of "Regular" so we must modify the style | |||
| if (newFont.getTypefaceStyle() == "Regular") | |||
| newFont.setTypefaceStyle (faceName); | |||
| #endif | |||
| Font f (font); | |||
| f.setTypefaceName (faceName); | |||
| return Typeface::createSystemTypefaceFor (f); | |||
| return Typeface::createSystemTypefaceFor (newFont); | |||
| } | |||
| bool TextLayout::createNativeLayout (const AttributedString& text) | |||
| @@ -89,8 +89,8 @@ namespace DirectWriteTypeLayout | |||
| glyphLine.ascent = jmax (glyphLine.ascent, scaledFontSize (dwFontMetrics.ascent, dwFontMetrics, glyphRun)); | |||
| glyphLine.descent = jmax (glyphLine.descent, scaledFontSize (dwFontMetrics.descent, dwFontMetrics, glyphRun)); | |||
| int styleFlags = 0; | |||
| const String fontName (getFontName (glyphRun, styleFlags)); | |||
| String fontFamily, fontStyle; | |||
| getFontFamilyAndStyle (glyphRun, fontFamily, fontStyle); | |||
| TextLayout::Run* const glyphRunLayout = new TextLayout::Run (Range<int> (runDescription->textPosition, | |||
| runDescription->textPosition + runDescription->stringLength), | |||
| @@ -102,7 +102,7 @@ namespace DirectWriteTypeLayout | |||
| const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent); | |||
| const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight; | |||
| glyphRunLayout->font = Font (fontName, glyphRun->fontEmSize / fontHeightToEmSizeFactor, styleFlags); | |||
| glyphRunLayout->font = Font (fontFamily, fontStyle, glyphRun->fontEmSize / fontHeightToEmSizeFactor); | |||
| glyphRunLayout->colour = getColourOf (static_cast<ID2D1SolidColorBrush*> (clientDrawingEffect)); | |||
| const Point<float> lineOrigin (layout->getLine (currentLine).lineOrigin); | |||
| @@ -145,62 +145,29 @@ namespace DirectWriteTypeLayout | |||
| return Colour::fromFloatRGBA (colour.r, colour.g, colour.b, colour.a); | |||
| } | |||
| String getFontName (DWRITE_GLYPH_RUN const* glyphRun, int& styleFlags) const | |||
| void getFontFamilyAndStyle (DWRITE_GLYPH_RUN const* glyphRun, String& family, String& style) const | |||
| { | |||
| ComSmartPtr<IDWriteFont> dwFont; | |||
| HRESULT hr = fontCollection->GetFontFromFontFace (glyphRun->fontFace, dwFont.resetAndGetPointerAddress()); | |||
| jassert (dwFont != nullptr); | |||
| if (dwFont->GetWeight() == DWRITE_FONT_WEIGHT_BOLD) styleFlags |= Font::bold; | |||
| if (dwFont->GetStyle() == DWRITE_FONT_STYLE_ITALIC) styleFlags |= Font::italic; | |||
| ComSmartPtr<IDWriteFontFamily> dwFontFamily; | |||
| hr = dwFont->GetFontFamily (dwFontFamily.resetAndGetPointerAddress()); | |||
| jassert (dwFontFamily != nullptr); | |||
| // Get the Font Family Names | |||
| ComSmartPtr<IDWriteLocalizedStrings> dwFamilyNames; | |||
| hr = dwFontFamily->GetFamilyNames (dwFamilyNames.resetAndGetPointerAddress()); | |||
| jassert (dwFamilyNames != nullptr); | |||
| UINT32 index = 0; | |||
| BOOL exists = false; | |||
| hr = dwFamilyNames->FindLocaleName (L"en-us", &index, &exists); | |||
| if (! exists) | |||
| index = 0; | |||
| UINT32 length = 0; | |||
| hr = dwFamilyNames->GetStringLength (index, &length); | |||
| HeapBlock <wchar_t> name (length + 1); | |||
| hr = dwFamilyNames->GetString (index, name, length + 1); | |||
| { | |||
| ComSmartPtr<IDWriteFontFamily> dwFontFamily; | |||
| hr = dwFont->GetFontFamily (dwFontFamily.resetAndGetPointerAddress()); | |||
| family = getFontFamilyName (dwFontFamily); | |||
| } | |||
| return String (name); | |||
| style = getFontFaceName (dwFont); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomDirectWriteTextRenderer); | |||
| }; | |||
| //================================================================================================== | |||
| float getFontHeightToEmSizeFactor (const Font& font, IDWriteFontCollection& dwFontCollection) | |||
| float getFontHeightToEmSizeFactor (IDWriteFont* const dwFont) | |||
| { | |||
| BOOL fontFound = false; | |||
| uint32 fontIndex; | |||
| dwFontCollection.FindFamilyName (font.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound); | |||
| if (! fontFound) | |||
| fontIndex = 0; | |||
| ComSmartPtr<IDWriteFontFamily> dwFontFamily; | |||
| HRESULT hr = dwFontCollection.GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); | |||
| ComSmartPtr<IDWriteFont> dwFont; | |||
| hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, | |||
| dwFont.resetAndGetPointerAddress()); | |||
| ComSmartPtr<IDWriteFontFace> dwFontFace; | |||
| hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress()); | |||
| dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress()); | |||
| DWRITE_FONT_METRICS dwFontMetrics; | |||
| dwFontFace->GetMetrics (&dwFontMetrics); | |||
| @@ -251,13 +218,35 @@ namespace DirectWriteTypeLayout | |||
| if (font != nullptr) | |||
| { | |||
| textLayout->SetFontFamilyName (font->getTypefaceName().toWideCharPointer(), range); | |||
| BOOL fontFound = false; | |||
| uint32 fontIndex; | |||
| fontCollection->FindFamilyName (font->getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound); | |||
| const float fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*font, *fontCollection); | |||
| textLayout->SetFontSize (font->getHeight() * fontHeightToEmSizeFactor, range); | |||
| if (! fontFound) | |||
| fontIndex = 0; | |||
| if (font->isBold()) textLayout->SetFontWeight (DWRITE_FONT_WEIGHT_BOLD, range); | |||
| if (font->isItalic()) textLayout->SetFontStyle (DWRITE_FONT_STYLE_ITALIC, range); | |||
| ComSmartPtr<IDWriteFontFamily> fontFamily; | |||
| HRESULT hr = fontCollection->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress()); | |||
| ComSmartPtr<IDWriteFont> dwFont; | |||
| uint32 fontFacesCount = 0; | |||
| fontFacesCount = fontFamily->GetFontCount(); | |||
| for (uint32 i = 0; i < fontFacesCount; ++i) | |||
| { | |||
| hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); | |||
| if (attr.getFont()->getTypefaceStyle() == getFontFaceName (dwFont)) | |||
| break; | |||
| } | |||
| textLayout->SetFontFamilyName (attr.getFont()->getTypefaceName().toWideCharPointer(), range); | |||
| textLayout->SetFontWeight (dwFont->GetWeight(), range); | |||
| textLayout->SetFontStretch (dwFont->GetStretch(), range); | |||
| textLayout->SetFontStyle (dwFont->GetStyle(), range); | |||
| const float fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (dwFont); | |||
| textLayout->SetFontSize (font->getHeight() * fontHeightToEmSizeFactor, range); | |||
| } | |||
| if (attr.getColour() != nullptr) | |||
| @@ -290,7 +279,21 @@ namespace DirectWriteTypeLayout | |||
| HRESULT hr = direct2dFactory->CreateDCRenderTarget (&d2dRTProp, renderTarget.resetAndGetPointerAddress()); | |||
| Font defaultFont; | |||
| const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (defaultFont, *fontCollection); | |||
| BOOL fontFound = false; | |||
| uint32 fontIndex; | |||
| fontCollection->FindFamilyName (defaultFont.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound); | |||
| if (! fontFound) | |||
| fontIndex = 0; | |||
| ComSmartPtr<IDWriteFontFamily> dwFontFamily; | |||
| hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); | |||
| ComSmartPtr<IDWriteFont> dwFont; | |||
| hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, | |||
| dwFont.resetAndGetPointerAddress()); | |||
| const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (dwFont); | |||
| jassert (directWriteFactory != nullptr); | |||
| @@ -24,6 +24,47 @@ | |||
| */ | |||
| #if JUCE_USE_DIRECTWRITE | |||
| namespace | |||
| { | |||
| static String getLocalisedName (IDWriteLocalizedStrings* names) | |||
| { | |||
| jassert (names != nullptr); | |||
| uint32 index = 0; | |||
| BOOL exists = false; | |||
| HRESULT hr = names->FindLocaleName (L"en-us", &index, &exists); | |||
| if (! exists) | |||
| index = 0; | |||
| uint32 length = 0; | |||
| hr = names->GetStringLength (index, &length); | |||
| HeapBlock<wchar_t> name (length + 1); | |||
| hr = names->GetString (index, name, length + 1); | |||
| return static_cast <const wchar_t*> (name); | |||
| } | |||
| static String getFontFamilyName (IDWriteFontFamily* family) | |||
| { | |||
| jassert (family != nullptr); | |||
| ComSmartPtr<IDWriteLocalizedStrings> familyNames; | |||
| HRESULT hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress()); | |||
| jassert (SUCCEEDED (hr)); (void) hr; | |||
| return getLocalisedName (familyNames); | |||
| } | |||
| static String getFontFaceName (IDWriteFont* font) | |||
| { | |||
| jassert (font != nullptr); | |||
| ComSmartPtr<IDWriteLocalizedStrings> faceNames; | |||
| HRESULT hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress()); | |||
| jassert (SUCCEEDED (hr)); (void) hr; | |||
| return getLocalisedName (faceNames); | |||
| } | |||
| } | |||
| class Direct2DFactories | |||
| { | |||
| public: | |||
| @@ -86,7 +127,7 @@ class WindowsDirectWriteTypeface : public Typeface | |||
| { | |||
| public: | |||
| WindowsDirectWriteTypeface (const Font& font, IDWriteFontCollection* fontCollection) | |||
| : Typeface (font.getTypefaceName()), | |||
| : Typeface (font.getTypefaceName(), font.getTypefaceStyle()), | |||
| ascent (0.0f) | |||
| { | |||
| jassert (fontCollection != nullptr); | |||
| @@ -102,12 +143,22 @@ public: | |||
| ComSmartPtr<IDWriteFontFamily> dwFontFamily; | |||
| hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); | |||
| // Get a specific font in the font family using certain weight and style flags | |||
| // Get a specific font in the font family using typeface style | |||
| ComSmartPtr<IDWriteFont> dwFont; | |||
| DWRITE_FONT_WEIGHT dwWeight = font.isBold() ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL; | |||
| DWRITE_FONT_STYLE dwStyle = font.isItalic() ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; | |||
| uint32 fontFacesCount = 0; | |||
| fontFacesCount = dwFontFamily->GetFontCount(); | |||
| for (uint32 i = 0; i < fontFacesCount; ++i) | |||
| { | |||
| hr = dwFontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); | |||
| ComSmartPtr<IDWriteLocalizedStrings> faceNames; | |||
| hr = dwFont->GetFaceNames (faceNames.resetAndGetPointerAddress()); | |||
| if (font.getTypefaceStyle() == getLocalisedName (faceNames)) | |||
| break; | |||
| } | |||
| hr = dwFontFamily->GetFirstMatchingFont (dwWeight, DWRITE_FONT_STRETCH_NORMAL, dwStyle, dwFont.resetAndGetPointerAddress()); | |||
| hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress()); | |||
| DWRITE_FONT_METRICS dwFontMetrics; | |||
| @@ -25,7 +25,7 @@ | |||
| namespace FontEnumerators | |||
| { | |||
| int CALLBACK fontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) | |||
| static int CALLBACK fontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) | |||
| { | |||
| if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) | |||
| { | |||
| @@ -36,7 +36,7 @@ namespace FontEnumerators | |||
| return 1; | |||
| } | |||
| int CALLBACK fontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) | |||
| static int CALLBACK fontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) | |||
| { | |||
| if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) | |||
| { | |||
| @@ -65,28 +65,99 @@ namespace FontEnumerators | |||
| StringArray Font::findAllTypefaceNames() | |||
| { | |||
| StringArray results; | |||
| HDC dc = CreateCompatibleDC (0); | |||
| #if JUCE_USE_DIRECTWRITE | |||
| const Direct2DFactories& factories = Direct2DFactories::getInstance(); | |||
| if (factories.systemFonts != nullptr) | |||
| { | |||
| LOGFONTW lf = { 0 }; | |||
| lf.lfWeight = FW_DONTCARE; | |||
| lf.lfOutPrecision = OUT_OUTLINE_PRECIS; | |||
| lf.lfQuality = DEFAULT_QUALITY; | |||
| lf.lfCharSet = DEFAULT_CHARSET; | |||
| lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; | |||
| lf.lfPitchAndFamily = FF_DONTCARE; | |||
| ComSmartPtr<IDWriteFontFamily> fontFamily; | |||
| uint32 fontFamilyCount = 0; | |||
| fontFamilyCount = factories.systemFonts->GetFontFamilyCount(); | |||
| for (uint32 i = 0; i < fontFamilyCount; ++i) | |||
| { | |||
| HRESULT hr = factories.systemFonts->GetFontFamily (i, fontFamily.resetAndGetPointerAddress()); | |||
| EnumFontFamiliesEx (dc, &lf, | |||
| (FONTENUMPROCW) &FontEnumerators::fontEnum1, | |||
| (LPARAM) &results, 0); | |||
| if (SUCCEEDED (hr)) | |||
| results.addIfNotAlreadyThere (getFontFamilyName (fontFamily)); | |||
| } | |||
| } | |||
| else | |||
| #endif | |||
| { | |||
| HDC dc = CreateCompatibleDC (0); | |||
| { | |||
| LOGFONTW lf = { 0 }; | |||
| lf.lfWeight = FW_DONTCARE; | |||
| lf.lfOutPrecision = OUT_OUTLINE_PRECIS; | |||
| lf.lfQuality = DEFAULT_QUALITY; | |||
| lf.lfCharSet = DEFAULT_CHARSET; | |||
| lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; | |||
| lf.lfPitchAndFamily = FF_DONTCARE; | |||
| EnumFontFamiliesEx (dc, &lf, | |||
| (FONTENUMPROCW) &FontEnumerators::fontEnum1, | |||
| (LPARAM) &results, 0); | |||
| } | |||
| DeleteDC (dc); | |||
| DeleteDC (dc); | |||
| } | |||
| results.sort (true); | |||
| return results; | |||
| } | |||
| StringArray Font::findAllTypefaceStyles (const String& family) | |||
| { | |||
| if (FontStyleHelpers::isPlaceholderFamilyName (family)) | |||
| return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family)); | |||
| StringArray results; | |||
| #if JUCE_USE_DIRECTWRITE | |||
| const Direct2DFactories& factories = Direct2DFactories::getInstance(); | |||
| if (factories.systemFonts != nullptr) | |||
| { | |||
| BOOL fontFound = false; | |||
| uint32 fontIndex = 0; | |||
| HRESULT hr = factories.systemFonts->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound); | |||
| if (! fontFound) | |||
| fontIndex = 0; | |||
| // Get the font family using the search results | |||
| // Fonts like: Times New Roman, Times New Roman Bold, Times New Roman Italic are all in the same font family | |||
| ComSmartPtr<IDWriteFontFamily> fontFamily; | |||
| hr = factories.systemFonts->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress()); | |||
| // Get the font faces | |||
| ComSmartPtr<IDWriteFont> dwFont; | |||
| uint32 fontFacesCount = 0; | |||
| fontFacesCount = fontFamily->GetFontCount(); | |||
| for (uint32 i = 0; i < fontFacesCount; ++i) | |||
| { | |||
| hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); | |||
| // Ignore any algorithmically generated bold and oblique styles.. | |||
| if (dwFont->GetSimulations() == DWRITE_FONT_SIMULATIONS_NONE) | |||
| results.addIfNotAlreadyThere (getFontFaceName (dwFont)); | |||
| } | |||
| } | |||
| else | |||
| #endif | |||
| { | |||
| results.add ("Regular"); | |||
| results.add ("Italic"); | |||
| results.add ("Bold"); | |||
| results.add ("Bold Italic"); | |||
| } | |||
| return results; | |||
| } | |||
| extern bool juce_IsRunningInWine(); | |||
| struct DefaultFontNames | |||
| @@ -116,15 +187,17 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) | |||
| { | |||
| static DefaultFontNames defaultNames; | |||
| String faceName (font.getTypefaceName()); | |||
| Font newFont (font); | |||
| const String& faceName = font.getTypefaceName(); | |||
| if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans); | |||
| else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif); | |||
| else if (faceName == getDefaultMonospacedFontName()) newFont.setTypefaceName (defaultNames.defaultFixed); | |||
| if (faceName == Font::getDefaultSansSerifFontName()) faceName = defaultNames.defaultSans; | |||
| else if (faceName == Font::getDefaultSerifFontName()) faceName = defaultNames.defaultSerif; | |||
| else if (faceName == Font::getDefaultMonospacedFontName()) faceName = defaultNames.defaultFixed; | |||
| if (font.getTypefaceStyle() == getDefaultStyle()) | |||
| newFont.setTypefaceStyle ("Regular"); | |||
| Font f (font); | |||
| f.setTypefaceName (faceName); | |||
| return Typeface::createSystemTypefaceFor (f); | |||
| return Typeface::createSystemTypefaceFor (newFont); | |||
| } | |||
| //============================================================================== | |||
| @@ -132,14 +205,13 @@ class WindowsTypeface : public Typeface | |||
| { | |||
| public: | |||
| WindowsTypeface (const Font& font) | |||
| : Typeface (font.getTypefaceName()), | |||
| : Typeface (font.getTypefaceName(), | |||
| font.getTypefaceStyle()), | |||
| fontH (0), | |||
| previousFontH (0), | |||
| dc (CreateCompatibleDC (0)), | |||
| ascent (1.0f), | |||
| defaultGlyph (-1), | |||
| bold (font.isBold()), | |||
| italic (font.isItalic()) | |||
| defaultGlyph (-1) | |||
| { | |||
| loadFont(); | |||
| @@ -282,7 +354,6 @@ private: | |||
| TEXTMETRIC tm; | |||
| float ascent; | |||
| int defaultGlyph; | |||
| bool bold, italic; | |||
| struct KerningPair | |||
| { | |||
| @@ -314,8 +385,8 @@ private: | |||
| lf.lfOutPrecision = OUT_OUTLINE_PRECIS; | |||
| lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; | |||
| lf.lfQuality = PROOF_QUALITY; | |||
| lf.lfItalic = (BYTE) (italic ? TRUE : FALSE); | |||
| lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; | |||
| lf.lfItalic = (BYTE) (style == "Italic" ? TRUE : FALSE); | |||
| lf.lfWeight = style == "Bold" ? FW_BOLD : FW_NORMAL; | |||
| lf.lfHeight = -256; | |||
| name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); | |||