Home | History | Annotate | Download | only in cocoa
      1 /*
      2  * This file is part of the internal font implementation.
      3  *
      4  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      5  * Copyright (c) 2010 Google Inc. All rights reserved.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  *
     22  */
     23 
     24 #import "config.h"
     25 #import "platform/fonts/FontPlatformData.h"
     26 
     27 #import <AppKit/NSFont.h>
     28 #import <AvailabilityMacros.h>
     29 #import <wtf/text/WTFString.h>
     30 
     31 #import "platform/fonts/harfbuzz/HarfBuzzFace.h"
     32 #include "third_party/skia/include/ports/SkTypeface_mac.h"
     33 
     34 namespace blink {
     35 
     36 unsigned FontPlatformData::hash() const
     37 {
     38     ASSERT(m_font || !m_cgFont);
     39     uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, static_cast<uintptr_t>(m_isHashTableDeletedValue << 3 | m_orientation << 2 | m_syntheticBold << 1 | m_syntheticItalic) };
     40     return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes);
     41 }
     42 
     43 // These CoreText Text Spacing feature selectors are not defined in CoreText.
     44 enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth };
     45 
     46 FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticItalic, FontOrientation orientation, FontWidthVariant widthVariant)
     47     : m_textSize(size)
     48     , m_syntheticBold(syntheticBold)
     49     , m_syntheticItalic(syntheticItalic)
     50     , m_orientation(orientation)
     51     , m_isColorBitmapFont(false)
     52     , m_isCompositeFontReference(false)
     53     , m_widthVariant(widthVariant)
     54     , m_font(nsFont)
     55     , m_isHashTableDeletedValue(false)
     56 {
     57     ASSERT_ARG(nsFont, nsFont);
     58 
     59     CGFontRef cgFont = 0;
     60     loadFont(nsFont, size, m_font, cgFont);
     61 
     62 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
     63     // FIXME: Chromium: The following code isn't correct for the Chromium port since the sandbox might
     64     // have blocked font loading, in which case we'll only have the real loaded font file after the call to loadFont().
     65     {
     66         CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font));
     67         m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait;
     68 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
     69         m_isCompositeFontReference = traits & kCTFontCompositeTrait;
     70 #endif
     71     }
     72 #endif
     73 
     74     if (m_font)
     75         CFRetain(m_font);
     76 
     77     m_cgFont.adoptCF(cgFont);
     78 }
     79 
     80 void FontPlatformData::platformDataInit(const FontPlatformData& f)
     81 {
     82     m_font = f.m_font ? [f.m_font retain] : f.m_font;
     83 
     84     m_cgFont = f.m_cgFont;
     85     m_CTFont = f.m_CTFont;
     86 
     87     m_inMemoryFont = f.m_inMemoryFont;
     88     m_harfBuzzFace = f.m_harfBuzzFace;
     89     m_typeface = f.m_typeface;
     90 }
     91 
     92 const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& f)
     93 {
     94     m_cgFont = f.m_cgFont;
     95     if (m_font == f.m_font)
     96         return *this;
     97     if (f.m_font)
     98         CFRetain(f.m_font);
     99     if (m_font)
    100         CFRelease(m_font);
    101     m_font = f.m_font;
    102     m_CTFont = f.m_CTFont;
    103 
    104     m_inMemoryFont = f.m_inMemoryFont;
    105     m_harfBuzzFace = f.m_harfBuzzFace;
    106     m_typeface = f.m_typeface;
    107 
    108     return *this;
    109 }
    110 
    111 
    112 void FontPlatformData::setFont(NSFont *font)
    113 {
    114     ASSERT_ARG(font, font);
    115 
    116     if (m_font == font)
    117         return;
    118 
    119     CFRetain(font);
    120     if (m_font)
    121         CFRelease(m_font);
    122     m_font = font;
    123     m_textSize = [font pointSize];
    124 
    125     CGFontRef cgFont = 0;
    126     NSFont* loadedFont = 0;
    127     loadFont(m_font, m_textSize, loadedFont, cgFont);
    128 
    129     // If loadFont replaced m_font with a fallback font, then release the
    130     // previous font to counter the retain above. Then retain the new font.
    131     if (loadedFont != m_font) {
    132         CFRelease(m_font);
    133         CFRetain(loadedFont);
    134         m_font = loadedFont;
    135     }
    136 
    137     m_cgFont.adoptCF(cgFont);
    138 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
    139     {
    140         CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font));
    141         m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait;
    142 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
    143         m_isCompositeFontReference = traits & kCTFontCompositeTrait;
    144 #endif
    145     }
    146 #endif
    147     m_CTFont = 0;
    148 }
    149 
    150 bool FontPlatformData::roundsGlyphAdvances() const
    151 {
    152     return [m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
    153 }
    154 
    155 bool FontPlatformData::allowsLigatures() const
    156 {
    157     return ![[m_font coveredCharacterSet] characterIsMember:'a'];
    158 }
    159 
    160 inline int mapFontWidthVariantToCTFeatureSelector(FontWidthVariant variant)
    161 {
    162     switch(variant) {
    163     case RegularWidth:
    164         return TextSpacingProportional;
    165 
    166     case HalfWidth:
    167         return TextSpacingHalfWidth;
    168 
    169     case ThirdWidth:
    170         return TextSpacingThirdWidth;
    171 
    172     case QuarterWidth:
    173         return TextSpacingQuarterWidth;
    174     }
    175 
    176     ASSERT_NOT_REACHED();
    177     return TextSpacingProportional;
    178 }
    179 
    180 static CFDictionaryRef createFeatureSettingDictionary(int featureTypeIdentifier, int featureSelectorIdentifier)
    181 {
    182     RetainPtr<CFNumberRef> featureTypeIdentifierNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeIdentifier));
    183     RetainPtr<CFNumberRef> featureSelectorIdentifierNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorIdentifier));
    184 
    185     const void* settingKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey };
    186     const void* settingValues[] = { featureTypeIdentifierNumber.get(), featureSelectorIdentifierNumber.get() };
    187 
    188     return CFDictionaryCreate(kCFAllocatorDefault, settingKeys, settingValues, WTF_ARRAY_LENGTH(settingKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    189 }
    190 
    191 static CTFontDescriptorRef cascadeToLastResortFontDescriptor()
    192 {
    193     static CTFontDescriptorRef descriptor;
    194     if (descriptor)
    195         return descriptor;
    196 
    197     const void* keys[] = { kCTFontCascadeListAttribute };
    198     const void* descriptors[] = { CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0) };
    199     const void* values[] = { CFArrayCreate(kCFAllocatorDefault, descriptors, WTF_ARRAY_LENGTH(descriptors), &kCFTypeArrayCallBacks) };
    200     RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    201 
    202     descriptor = CTFontDescriptorCreateWithAttributes(attributes.get());
    203 
    204     return descriptor;
    205 }
    206 
    207 static CTFontDescriptorRef cascadeToLastResortAndDisableSwashesFontDescriptor()
    208 {
    209     static CTFontDescriptorRef descriptor;
    210     if (descriptor)
    211         return descriptor;
    212 
    213     RetainPtr<CFDictionaryRef> lineInitialSwashesOffSetting(AdoptCF, createFeatureSettingDictionary(kSmartSwashType, kLineInitialSwashesOffSelector));
    214     RetainPtr<CFDictionaryRef> lineFinalSwashesOffSetting(AdoptCF, createFeatureSettingDictionary(kSmartSwashType, kLineFinalSwashesOffSelector));
    215 
    216     const void* settingDictionaries[] = { lineInitialSwashesOffSetting.get(), lineFinalSwashesOffSetting.get() };
    217     RetainPtr<CFArrayRef> featureSettings(AdoptCF, CFArrayCreate(kCFAllocatorDefault, settingDictionaries, WTF_ARRAY_LENGTH(settingDictionaries), &kCFTypeArrayCallBacks));
    218 
    219     const void* keys[] = { kCTFontFeatureSettingsAttribute };
    220     const void* values[] = { featureSettings.get() };
    221     RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    222 
    223     descriptor = CTFontDescriptorCreateCopyWithAttributes(cascadeToLastResortFontDescriptor(), attributes.get());
    224 
    225     return descriptor;
    226 }
    227 
    228 CTFontRef FontPlatformData::ctFont() const
    229 {
    230     if (m_CTFont)
    231         return m_CTFont.get();
    232 
    233     if (m_inMemoryFont) {
    234         m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_inMemoryFont->cgFont(), m_textSize, 0, cascadeToLastResortFontDescriptor()));
    235         return m_CTFont.get();
    236     }
    237 
    238     m_CTFont = toCTFontRef(m_font);
    239     if (m_CTFont) {
    240         CTFontDescriptorRef fontDescriptor;
    241         RetainPtr<CFStringRef> postScriptName(AdoptCF, CTFontCopyPostScriptName(m_CTFont.get()));
    242         // Hoefler Text Italic has line-initial and -final swashes enabled by default, so disable them.
    243         if (CFEqual(postScriptName.get(), CFSTR("HoeflerText-Italic")) || CFEqual(postScriptName.get(), CFSTR("HoeflerText-BlackItalic")))
    244             fontDescriptor = cascadeToLastResortAndDisableSwashesFontDescriptor();
    245         else
    246             fontDescriptor = cascadeToLastResortFontDescriptor();
    247         m_CTFont.adoptCF(CTFontCreateCopyWithAttributes(m_CTFont.get(), m_textSize, 0, fontDescriptor));
    248     } else
    249         m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_textSize, 0, cascadeToLastResortFontDescriptor()));
    250 
    251     if (m_widthVariant != RegularWidth) {
    252         int featureTypeValue = kTextSpacingType;
    253         int featureSelectorValue = mapFontWidthVariantToCTFeatureSelector(m_widthVariant);
    254         RetainPtr<CTFontDescriptorRef> sourceDescriptor(AdoptCF, CTFontCopyFontDescriptor(m_CTFont.get()));
    255         RetainPtr<CFNumberRef> featureType(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeValue));
    256         RetainPtr<CFNumberRef> featureSelector(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue));
    257         RetainPtr<CTFontDescriptorRef> newDescriptor(AdoptCF, CTFontDescriptorCreateCopyWithFeature(sourceDescriptor.get(), featureType.get(), featureSelector.get()));
    258         RetainPtr<CTFontRef> newFont(AdoptCF, CTFontCreateWithFontDescriptor(newDescriptor.get(), m_textSize, 0));
    259 
    260         if (newFont)
    261             m_CTFont = newFont;
    262     }
    263 
    264     return m_CTFont.get();
    265 }
    266 
    267 bool FontPlatformData::isAATFont(CTFontRef ctFont) const
    268 {
    269     CFDataRef table = CTFontCopyTable(ctFont, kCTFontTableMort, 0);
    270     if (table) {
    271         CFRelease(table);
    272         return true;
    273     }
    274     table = CTFontCopyTable(ctFont, kCTFontTableMorx, 0);
    275     if (table) {
    276         CFRelease(table);
    277         return true;
    278     }
    279     return false;
    280 }
    281 
    282 } // namespace blink
    283