1/* 2 * Copyright (C) 2005, 2006, 2010, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 Alexey Proskuryakov 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 24 * THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#import "config.h" 28#import "SimpleFontData.h" 29 30#import "BlockExceptions.h" 31#import "Font.h" 32#import "FontCache.h" 33#import "FontDescription.h" 34#import "FontServicesIOS.h" 35#import <CoreGraphics/CGFontInfo.h> 36#import <CoreText/CoreText.h> 37#import <float.h> 38#import <unicode/uchar.h> 39#import <wtf/Assertions.h> 40#import <wtf/StdLibExtras.h> 41 42namespace WebCore { 43 44static bool fontFamilyShouldNotBeUsedForArabic(CFStringRef fontFamilyName) 45{ 46 if (!fontFamilyName) 47 return false; 48 49 // Times New Roman contains Arabic glyphs, but Core Text doesn't know how to shape them. <rdar://problem/9823975> 50 // FIXME <rdar://problem/12096835> remove this function once the above bug is fixed. 51 // Arial and Tahoma are have performance issues so don't use them as well. 52 return (CFStringCompare(CFSTR("Times New Roman"), fontFamilyName, 0) == kCFCompareEqualTo) 53 || (CFStringCompare(CFSTR("Arial"), fontFamilyName, 0) == kCFCompareEqualTo) 54 || (CFStringCompare(CFSTR("Tahoma"), fontFamilyName, 0) == kCFCompareEqualTo); 55} 56 57static bool fontHasVerticalGlyphs(CTFontRef ctFont) 58{ 59 // The check doesn't look neat but this is what AppKit does for vertical writing... 60 RetainPtr<CFArrayRef> tableTags = adoptCF(CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions)); 61 CFIndex numTables = CFArrayGetCount(tableTags.get()); 62 for (CFIndex index = 0; index < numTables; ++index) { 63 CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tableTags.get(), index); 64 if (tag == kCTFontTableVhea || tag == kCTFontTableVORG) 65 return true; 66 } 67 return false; 68} 69 70void SimpleFontData::platformInit() 71{ 72 m_syntheticBoldOffset = m_platformData.m_syntheticBold ? ceilf(m_platformData.size() / 24.0f) : 0.f; 73 m_spaceGlyph = 0; 74 m_spaceWidth = 0; 75 unsigned unitsPerEm; 76 float ascent; 77 float descent; 78 float lineGap; 79 float lineSpacing; 80 float xHeight; 81 RetainPtr<CFStringRef> familyName; 82 if (CTFontRef ctFont = m_platformData.font()) { 83 FontServicesIOS fontService(ctFont); 84 ascent = ceilf(fontService.ascent()); 85 descent = ceilf(fontService.descent()); 86 lineSpacing = fontService.lineSpacing(); 87 lineGap = fontService.lineGap(); 88 xHeight = fontService.xHeight(); 89 unitsPerEm = fontService.unitsPerEm(); 90 familyName = adoptCF(CTFontCopyFamilyName(ctFont)); 91 } else { 92 CGFontRef cgFont = m_platformData.cgFont(); 93 94 unitsPerEm = CGFontGetUnitsPerEm(cgFont); 95 96 float pointSize = m_platformData.size(); 97 ascent = lroundf(scaleEmToUnits(CGFontGetAscent(cgFont), unitsPerEm) * pointSize); 98 descent = lroundf(-scaleEmToUnits(-abs(CGFontGetDescent(cgFont)), unitsPerEm) * pointSize); 99 lineGap = lroundf(scaleEmToUnits(CGFontGetLeading(cgFont), unitsPerEm) * pointSize); 100 xHeight = scaleEmToUnits(CGFontGetXHeight(cgFont), unitsPerEm) * pointSize; 101 102 lineSpacing = ascent + descent + lineGap; 103 familyName = adoptCF(CGFontCopyFamilyName(cgFont)); 104 } 105 106 m_fontMetrics.setUnitsPerEm(unitsPerEm); 107 m_fontMetrics.setAscent(ascent); 108 m_fontMetrics.setDescent(descent); 109 m_fontMetrics.setLineGap(lineGap); 110 m_fontMetrics.setLineSpacing(lineSpacing); 111 m_fontMetrics.setXHeight(xHeight); 112 m_shouldNotBeUsedForArabic = fontFamilyShouldNotBeUsedForArabic(familyName.get()); 113 114 if (platformData().orientation() == Vertical && !isTextOrientationFallback()) 115 m_hasVerticalGlyphs = fontHasVerticalGlyphs(m_platformData.ctFont()); 116 117 if (!m_platformData.m_isEmoji) 118 return; 119 120 int thirdOfSize = m_platformData.size() / 3; 121 m_fontMetrics.setAscent(thirdOfSize); 122 m_fontMetrics.setDescent(thirdOfSize); 123 m_fontMetrics.setLineGap(thirdOfSize); 124 m_fontMetrics.setLineSpacing(0); 125} 126 127void SimpleFontData::platformCharWidthInit() 128{ 129 m_avgCharWidth = 0; 130 m_maxCharWidth = 0; 131 132 // Fallback to a cross-platform estimate, which will populate these values if they are non-positive. 133 initCharWidths(); 134} 135 136PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const FontDescription&, float scaleFactor) const 137{ 138 if (isCustomFont()) { 139 FontPlatformData scaledFontData(m_platformData); 140 scaledFontData.m_size = scaledFontData.m_size * scaleFactor; 141 return SimpleFontData::create(scaledFontData, true, false); 142 } 143 144 float size = m_platformData.size() * scaleFactor; 145 CTFontSymbolicTraits fontTraits = CTFontGetSymbolicTraits(m_platformData.font()); 146 RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontCopyFontDescriptor(m_platformData.font())); 147 RetainPtr<CTFontRef> scaledFont = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor.get(), size, nullptr)); 148 FontPlatformData scaledFontData(scaledFont.get(), size, m_platformData.isPrinterFont(), false, false, m_platformData.orientation()); 149 150 if (scaledFontData.font()) { 151 if (m_platformData.m_syntheticBold) 152 fontTraits |= kCTFontBoldTrait; 153 if (m_platformData.m_syntheticOblique) 154 fontTraits |= kCTFontItalicTrait; 155 156 CTFontSymbolicTraits scaledFontTraits = CTFontGetSymbolicTraits(scaledFontData.font()); 157 scaledFontData.m_syntheticBold = (fontTraits & kCTFontBoldTrait) && !(scaledFontTraits & kCTFontTraitBold); 158 scaledFontData.m_syntheticOblique = (fontTraits & kCTFontItalicTrait) && !(scaledFontTraits & kCTFontTraitItalic); 159 160 return fontCache().getCachedFontData(&scaledFontData); 161 } 162 163 return nullptr; 164} 165 166bool SimpleFontData::containsCharacters(const UChar*, int) const 167{ 168 return false; 169} 170 171void SimpleFontData::determinePitch() 172{ 173 CTFontRef ctFont = m_platformData.font(); 174 m_treatAsFixedPitch = false; 175 if (!ctFont) 176 return; // CTFont is null in the case of SVG fonts for example. 177 178 RetainPtr<CFStringRef> fullName = adoptCF(CTFontCopyFullName(ctFont)); 179 RetainPtr<CFStringRef> familyName = adoptCF(CTFontCopyFamilyName(ctFont)); 180 181 m_treatAsFixedPitch = CGFontIsFixedPitch(m_platformData.cgFont()) || (fullName && (CFStringCompare(fullName.get(), CFSTR("Osaka-Mono"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare(fullName.get(), CFSTR("MS-PGothic"), kCFCompareCaseInsensitive) == kCFCompareEqualTo)); 182 if (familyName && CFStringCompare(familyName.get(), CFSTR("Courier New"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 183 // Special case Courier New to not be treated as fixed pitch, as this will make use of a hacked space width which is undesireable for iPhone (see rdar://6269783). 184 m_treatAsFixedPitch = false; 185 } 186} 187 188CGFontRenderingStyle SimpleFontData::renderingStyle() const 189{ 190 return kCGFontRenderingStyleAntialiasing | kCGFontRenderingStyleSubpixelPositioning | kCGFontRenderingStyleSubpixelQuantization | kCGFontAntialiasingStyleUnfiltered; 191} 192 193bool SimpleFontData::advanceForColorBitmapFont(Glyph, CGSize&) const 194{ 195 return false; 196} 197 198} // namespace WebCore 199