SimpleFontDataWin.cpp revision cad810f21b803229eb11403f9209855525a25d57
1/* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 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 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "SimpleFontData.h" 31 32#include <winsock2.h> 33#include "Font.h" 34#include "FontCache.h" 35#include "FloatRect.h" 36#include "FontDescription.h" 37#include <wtf/MathExtras.h> 38#include <unicode/uchar.h> 39#include <unicode/unorm.h> 40#include <mlang.h> 41#include <tchar.h> 42 43#if PLATFORM(CG) 44#include <ApplicationServices/ApplicationServices.h> 45#include <WebKitSystemInterface/WebKitSystemInterface.h> 46#endif 47 48namespace WebCore { 49 50using std::max; 51 52const float cSmallCapsFontSizeMultiplier = 0.7f; 53 54static bool g_shouldApplyMacAscentHack; 55 56void SimpleFontData::setShouldApplyMacAscentHack(bool b) 57{ 58 g_shouldApplyMacAscentHack = b; 59} 60 61bool SimpleFontData::shouldApplyMacAscentHack() 62{ 63 return g_shouldApplyMacAscentHack; 64} 65 66void SimpleFontData::initGDIFont() 67{ 68 if (!m_platformData.size()) { 69 m_ascent = 0; 70 m_descent = 0; 71 m_lineGap = 0; 72 m_lineSpacing = 0; 73 m_avgCharWidth = 0; 74 m_maxCharWidth = 0; 75 m_xHeight = 0; 76 m_unitsPerEm = 0; 77 return; 78 } 79 80 HDC hdc = GetDC(0); 81 HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); 82 OUTLINETEXTMETRIC metrics; 83 GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics); 84 TEXTMETRIC& textMetrics = metrics.otmTextMetrics; 85 m_ascent = textMetrics.tmAscent; 86 m_descent = textMetrics.tmDescent; 87 m_lineGap = textMetrics.tmExternalLeading; 88 m_lineSpacing = m_ascent + m_descent + m_lineGap; 89 m_avgCharWidth = textMetrics.tmAveCharWidth; 90 m_maxCharWidth = textMetrics.tmMaxCharWidth; 91 m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present. 92 93 GLYPHMETRICS gm; 94 MAT2 mat = { 1, 0, 0, 1 }; 95 DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat); 96 if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0) 97 m_xHeight = gm.gmptGlyphOrigin.y; 98 99 m_unitsPerEm = metrics.otmEMSquare; 100 101 SelectObject(hdc, oldFont); 102 ReleaseDC(0, hdc); 103 104 return; 105} 106 107void SimpleFontData::platformDestroy() 108{ 109 ScriptFreeCache(&m_scriptCache); 110 delete m_scriptFontProperties; 111} 112 113SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const 114{ 115 float scaledSize = scaleFactor * m_platformData.size(); 116 if (isCustomFont()) { 117 FontPlatformData scaledFont(m_platformData); 118 scaledFont.setSize(scaledSize); 119 return new SimpleFontData(scaledFont, true, false); 120 } 121 122 LOGFONT winfont; 123 GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont); 124 winfont.lfHeight = -lroundf(scaledSize * (m_platformData.useGDI() ? 1 : 32)); 125 HFONT hfont = CreateFontIndirect(&winfont); 126 return new SimpleFontData(FontPlatformData(hfont, scaledSize, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI()), isCustomFont(), false); 127} 128 129SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const 130{ 131 if (!m_derivedFontData) 132 m_derivedFontData = DerivedFontData::create(isCustomFont()); 133 if (!m_derivedFontData->smallCaps) 134 m_derivedFontData->smallCaps = scaledFontData(fontDescription, cSmallCapsFontSizeMultiplier); 135 136 return m_derivedFontData->smallCaps.get(); 137} 138 139SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const 140{ 141 if (!m_derivedFontData) 142 m_derivedFontData = DerivedFontData::create(isCustomFont()); 143 if (!m_derivedFontData->emphasisMark) 144 m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); 145 146 return m_derivedFontData->emphasisMark.get(); 147} 148 149bool SimpleFontData::containsCharacters(const UChar* characters, int length) const 150{ 151 // FIXME: Support custom fonts. 152 if (isCustomFont()) 153 return false; 154 155 // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC 156 // merely by testing code page intersection. This seems suspect though. Can't a font only partially 157 // cover a given code page? 158 IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface(); 159 if (!langFontLink) 160 return false; 161 162 HDC dc = GetDC(0); 163 164 DWORD acpCodePages; 165 langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages); 166 167 DWORD fontCodePages; 168 langFontLink->GetFontCodePages(dc, m_platformData.hfont(), &fontCodePages); 169 170 DWORD actualCodePages; 171 long numCharactersProcessed; 172 long offset = 0; 173 while (offset < length) { 174 langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed); 175 if ((actualCodePages & fontCodePages) == 0) 176 return false; 177 offset += numCharactersProcessed; 178 } 179 180 ReleaseDC(0, dc); 181 182 return true; 183} 184 185void SimpleFontData::determinePitch() 186{ 187 if (isCustomFont()) { 188 m_treatAsFixedPitch = false; 189 return; 190 } 191 192 // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. 193 HDC dc = GetDC(0); 194 SaveDC(dc); 195 SelectObject(dc, m_platformData.hfont()); 196 197 // Yes, this looks backwards, but the fixed pitch bit is actually set if the font 198 // is *not* fixed pitch. Unbelievable but true. 199 TEXTMETRIC tm; 200 GetTextMetrics(dc, &tm); 201 m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0); 202 203 RestoreDC(dc, -1); 204 ReleaseDC(0, dc); 205} 206 207FloatRect SimpleFontData::boundsForGDIGlyph(Glyph glyph) const 208{ 209 HDC hdc = GetDC(0); 210 SetGraphicsMode(hdc, GM_ADVANCED); 211 HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); 212 213 GLYPHMETRICS gdiMetrics; 214 static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; 215 GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity); 216 217 SelectObject(hdc, oldFont); 218 ReleaseDC(0, hdc); 219 220 return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y, 221 gdiMetrics.gmBlackBoxX + m_syntheticBoldOffset, gdiMetrics.gmBlackBoxY); 222} 223 224float SimpleFontData::widthForGDIGlyph(Glyph glyph) const 225{ 226 HDC hdc = GetDC(0); 227 SetGraphicsMode(hdc, GM_ADVANCED); 228 HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); 229 230 GLYPHMETRICS gdiMetrics; 231 static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; 232 GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity); 233 234 SelectObject(hdc, oldFont); 235 ReleaseDC(0, hdc); 236 237 return gdiMetrics.gmCellIncX + m_syntheticBoldOffset; 238} 239 240SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const 241{ 242 if (!m_scriptFontProperties) { 243 m_scriptFontProperties = new SCRIPT_FONTPROPERTIES; 244 memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES)); 245 m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES); 246 HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties); 247 if (result == E_PENDING) { 248 HDC dc = GetDC(0); 249 SaveDC(dc); 250 SelectObject(dc, m_platformData.hfont()); 251 ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties); 252 RestoreDC(dc, -1); 253 ReleaseDC(0, dc); 254 } 255 } 256 return m_scriptFontProperties; 257} 258 259} 260