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 "FontPlatformData.h"
26
27#import "PlatformString.h"
28#import "WebCoreSystemInterface.h"
29#import <AppKit/NSFont.h>
30
31namespace WebCore {
32
33// These CoreText Text Spacing feature selectors are not defined in CoreText.
34enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth };
35
36#if PLATFORM(MAC)
37void FontPlatformData::loadFont(NSFont* nsFont, float, NSFont*& outNSFont, CGFontRef& cgFont)
38{
39    outNSFont = nsFont;
40#ifndef BUILDING_ON_TIGER
41    cgFont = CTFontCopyGraphicsFont(toCTFontRef(nsFont), 0);
42#else
43    cgFont = wkGetCGFontFromNSFont(nsFont);
44#endif
45}
46#endif  // PLATFORM(MAC)
47
48FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation,
49                                   TextOrientation textOrientation, FontWidthVariant widthVariant)
50    : m_syntheticBold(syntheticBold)
51    , m_syntheticOblique(syntheticOblique)
52    , m_orientation(orientation)
53    , m_textOrientation(textOrientation)
54    , m_size(size)
55    , m_widthVariant(widthVariant)
56    , m_font(nsFont)
57#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
58    // FIXME: Chromium: The following code isn't correct for the Chromium port since the sandbox might
59    // have blocked font loading, in which case we'll only have the real loaded font file after the call to loadFont().
60    , m_isColorBitmapFont(CTFontGetSymbolicTraits(toCTFontRef(nsFont)) & kCTFontColorGlyphsTrait)
61#else
62    , m_isColorBitmapFont(false)
63#endif
64{
65    ASSERT_ARG(nsFont, nsFont);
66
67    CGFontRef cgFont = 0;
68    loadFont(nsFont, size, m_font, cgFont);
69
70    if (m_font)
71        CFRetain(m_font);
72
73#ifndef BUILDING_ON_TIGER
74    m_cgFont.adoptCF(cgFont);
75#else
76    m_cgFont = cgFont;
77#endif
78}
79
80FontPlatformData:: ~FontPlatformData()
81{
82    if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
83        CFRelease(m_font);
84}
85
86void FontPlatformData::platformDataInit(const FontPlatformData& f)
87{
88    m_font = f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1) ? const_cast<NSFont *>(static_cast<const NSFont *>(CFRetain(f.m_font))) : f.m_font;
89
90    m_cgFont = f.m_cgFont;
91    m_CTFont = f.m_CTFont;
92
93#if PLATFORM(CHROMIUM) && OS(DARWIN)
94    m_inMemoryFont = f.m_inMemoryFont;
95#endif
96}
97
98const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& f)
99{
100    m_cgFont = f.m_cgFont;
101    if (m_font == f.m_font)
102        return *this;
103    if (f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1))
104        CFRetain(f.m_font);
105    if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
106        CFRelease(m_font);
107    m_font = f.m_font;
108    m_CTFont = f.m_CTFont;
109#if PLATFORM(CHROMIUM) && OS(DARWIN)
110    m_inMemoryFont = f.m_inMemoryFont;
111#endif
112    return *this;
113}
114
115bool FontPlatformData::platformIsEqual(const FontPlatformData& other) const
116{
117    return m_font == other.m_font
118        && m_cgFont == other.m_cgFont;
119}
120
121void FontPlatformData::setFont(NSFont *font)
122{
123    ASSERT_ARG(font, font);
124    ASSERT(m_font != reinterpret_cast<NSFont *>(-1));
125
126    if (m_font == font)
127        return;
128
129    CFRetain(font);
130    if (m_font)
131        CFRelease(m_font);
132    m_font = font;
133    m_size = [font pointSize];
134
135    CGFontRef cgFont = 0;
136    NSFont* loadedFont = 0;
137    loadFont(m_font, m_size, loadedFont, cgFont);
138
139#if PLATFORM(CHROMIUM) && OS(DARWIN)
140    // If loadFont replaced m_font with a fallback font, then release the
141    // previous font to counter the retain above. Then retain the new font.
142    if (loadedFont != m_font) {
143        CFRelease(m_font);
144        CFRetain(loadedFont);
145        m_font = loadedFont;
146    }
147#endif
148
149#ifndef BUILDING_ON_TIGER
150    m_cgFont.adoptCF(cgFont);
151#else
152    m_cgFont = cgFont;
153#endif
154#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
155    m_isColorBitmapFont = CTFontGetSymbolicTraits(toCTFontRef(m_font)) & kCTFontColorGlyphsTrait;
156#endif
157    m_CTFont = 0;
158}
159
160bool FontPlatformData::roundsGlyphAdvances() const
161{
162    return [m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
163}
164
165bool FontPlatformData::allowsLigatures() const
166{
167    return ![[m_font coveredCharacterSet] characterIsMember:'a'];
168}
169
170inline int mapFontWidthVariantToCTFeatureSelector(FontWidthVariant variant)
171{
172    switch(variant) {
173    case RegularWidth:
174        return TextSpacingProportional;
175
176    case HalfWidth:
177        return TextSpacingHalfWidth;
178
179    case ThirdWidth:
180        return TextSpacingThirdWidth;
181
182    case QuarterWidth:
183        return TextSpacingQuarterWidth;
184    }
185
186    ASSERT_NOT_REACHED();
187    return TextSpacingProportional;
188}
189
190CTFontRef FontPlatformData::ctFont() const
191{
192    if (m_widthVariant == RegularWidth) {
193        if (m_font)
194            return toCTFontRef(m_font);
195        if (!m_CTFont)
196            m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, 0));
197        return m_CTFont.get();
198    }
199
200    if (!m_CTFont) {
201        int featureTypeValue = kTextSpacingType;
202        int featureSelectorValue = mapFontWidthVariantToCTFeatureSelector(m_widthVariant);
203        RetainPtr<CTFontRef> sourceFont(AdoptCF, CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, 0));
204        RetainPtr<CTFontDescriptorRef> sourceDescriptor(AdoptCF, CTFontCopyFontDescriptor(sourceFont.get()));
205        RetainPtr<CFNumberRef> featureType(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeValue));
206        RetainPtr<CFNumberRef> featureSelector(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue));
207        RetainPtr<CTFontDescriptorRef> newDescriptor(AdoptCF, CTFontDescriptorCreateCopyWithFeature(sourceDescriptor.get(), featureType.get(), featureSelector.get()));
208        RetainPtr<CTFontRef> newFont(AdoptCF, CTFontCreateWithFontDescriptor(newDescriptor.get(), m_size, 0));
209
210        m_CTFont = newFont.get() ? newFont : sourceFont;
211    }
212    return m_CTFont.get();
213}
214
215#ifndef NDEBUG
216String FontPlatformData::description() const
217{
218    RetainPtr<CFStringRef> cgFontDescription(AdoptCF, CFCopyDescription(cgFont()));
219    return String(cgFontDescription.get()) + " " + String::number(m_size)
220            + (m_syntheticBold ? " synthetic bold" : "") + (m_syntheticOblique ? " synthetic oblique" : "") + (m_orientation ? " vertical orientation" : "");
221}
222#endif
223
224} // namespace WebCore
225