• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "Font.h"
33 #include "FontCache.h"
34 #include "FloatRect.h"
35 #include "FontDescription.h"
36 #include <mlang.h>
37 #include <unicode/uchar.h>
38 #include <unicode/unorm.h>
39 #include <winsock2.h>
40 #include <wtf/MathExtras.h>
41 
42 #if USE(CG)
43 #include <ApplicationServices/ApplicationServices.h>
44 #include <WebKitSystemInterface/WebKitSystemInterface.h>
45 #endif
46 
47 namespace WebCore {
48 
49 using std::max;
50 
51 const float cSmallCapsFontSizeMultiplier = 0.7f;
52 
53 static bool g_shouldApplyMacAscentHack;
54 
setShouldApplyMacAscentHack(bool b)55 void SimpleFontData::setShouldApplyMacAscentHack(bool b)
56 {
57     g_shouldApplyMacAscentHack = b;
58 }
59 
shouldApplyMacAscentHack()60 bool SimpleFontData::shouldApplyMacAscentHack()
61 {
62     return g_shouldApplyMacAscentHack;
63 }
64 
initGDIFont()65 void SimpleFontData::initGDIFont()
66 {
67     if (!m_platformData.size()) {
68         m_fontMetrics.reset();
69         m_avgCharWidth = 0;
70         m_maxCharWidth = 0;
71         return;
72     }
73 
74      HDC hdc = GetDC(0);
75      HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
76      OUTLINETEXTMETRIC metrics;
77      GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
78      TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
79      float ascent = textMetrics.tmAscent;
80      float descent = textMetrics.tmDescent;
81      float lineGap = textMetrics.tmExternalLeading;
82      m_fontMetrics.setAscent(ascent);
83      m_fontMetrics.setDescent(descent);
84      m_fontMetrics.setLineGap(lineGap);
85      m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap));
86      m_avgCharWidth = textMetrics.tmAveCharWidth;
87      m_maxCharWidth = textMetrics.tmMaxCharWidth;
88      float xHeight = ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
89 
90      GLYPHMETRICS gm;
91      MAT2 mat = { 1, 0, 0, 1 };
92      DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
93      if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
94          xHeight = gm.gmptGlyphOrigin.y;
95 
96      m_fontMetrics.setXHeight(xHeight);
97      m_fontMetrics.setUnitsPerEm(metrics.otmEMSquare);
98 
99      SelectObject(hdc, oldFont);
100      ReleaseDC(0, hdc);
101 
102      return;
103 }
104 
platformDestroy()105 void SimpleFontData::platformDestroy()
106 {
107     ScriptFreeCache(&m_scriptCache);
108     delete m_scriptFontProperties;
109 }
110 
scaledFontData(const FontDescription & fontDescription,float scaleFactor) const111 SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
112 {
113         float scaledSize = scaleFactor * m_platformData.size();
114         if (isCustomFont()) {
115             FontPlatformData scaledFont(m_platformData);
116             scaledFont.setSize(scaledSize);
117             return new SimpleFontData(scaledFont, true, false);
118         }
119 
120         LOGFONT winfont;
121         GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont);
122         winfont.lfHeight = -lroundf(scaledSize * (m_platformData.useGDI() ? 1 : 32));
123         HFONT hfont = CreateFontIndirect(&winfont);
124         return new SimpleFontData(FontPlatformData(hfont, scaledSize, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI()), isCustomFont(), false);
125 }
126 
smallCapsFontData(const FontDescription & fontDescription) const127 SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
128 {
129     if (!m_derivedFontData)
130         m_derivedFontData = DerivedFontData::create(isCustomFont());
131     if (!m_derivedFontData->smallCaps)
132         m_derivedFontData->smallCaps = scaledFontData(fontDescription, cSmallCapsFontSizeMultiplier);
133 
134     return m_derivedFontData->smallCaps.get();
135 }
136 
emphasisMarkFontData(const FontDescription & fontDescription) const137 SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
138 {
139     if (!m_derivedFontData)
140         m_derivedFontData = DerivedFontData::create(isCustomFont());
141     if (!m_derivedFontData->emphasisMark)
142         m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
143 
144     return m_derivedFontData->emphasisMark.get();
145 }
146 
containsCharacters(const UChar * characters,int length) const147 bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
148 {
149     // FIXME: Support custom fonts.
150     if (isCustomFont())
151         return false;
152 
153     // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC
154     // merely by testing code page intersection.  This seems suspect though.  Can't a font only partially
155     // cover a given code page?
156     IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
157     if (!langFontLink)
158         return false;
159 
160     HDC dc = GetDC(0);
161 
162     DWORD acpCodePages;
163     langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
164 
165     DWORD fontCodePages;
166     langFontLink->GetFontCodePages(dc, m_platformData.hfont(), &fontCodePages);
167 
168     DWORD actualCodePages;
169     long numCharactersProcessed;
170     long offset = 0;
171     while (offset < length) {
172         langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed);
173         if ((actualCodePages & fontCodePages) == 0)
174             return false;
175         offset += numCharactersProcessed;
176     }
177 
178     ReleaseDC(0, dc);
179 
180     return true;
181 }
182 
determinePitch()183 void SimpleFontData::determinePitch()
184 {
185     if (isCustomFont()) {
186         m_treatAsFixedPitch = false;
187         return;
188     }
189 
190     // TEXTMETRICS have this.  Set m_treatAsFixedPitch based off that.
191     HDC dc = GetDC(0);
192     SaveDC(dc);
193     SelectObject(dc, m_platformData.hfont());
194 
195     // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
196     // is *not* fixed pitch.  Unbelievable but true.
197     TEXTMETRIC tm;
198     GetTextMetrics(dc, &tm);
199     m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
200 
201     RestoreDC(dc, -1);
202     ReleaseDC(0, dc);
203 }
204 
boundsForGDIGlyph(Glyph glyph) const205 FloatRect SimpleFontData::boundsForGDIGlyph(Glyph glyph) const
206 {
207     HDC hdc = GetDC(0);
208     SetGraphicsMode(hdc, GM_ADVANCED);
209     HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
210 
211     GLYPHMETRICS gdiMetrics;
212     static const MAT2 identity = { 0, 1,  0, 0,  0, 0,  0, 1 };
213     GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity);
214 
215     SelectObject(hdc, oldFont);
216     ReleaseDC(0, hdc);
217 
218     return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y,
219         gdiMetrics.gmBlackBoxX + m_syntheticBoldOffset, gdiMetrics.gmBlackBoxY);
220 }
221 
widthForGDIGlyph(Glyph glyph) const222 float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
223 {
224     HDC hdc = GetDC(0);
225     SetGraphicsMode(hdc, GM_ADVANCED);
226     HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
227 
228     GLYPHMETRICS gdiMetrics;
229     static const MAT2 identity = { 0, 1,  0, 0,  0, 0,  0, 1 };
230     GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity);
231 
232     SelectObject(hdc, oldFont);
233     ReleaseDC(0, hdc);
234 
235     return gdiMetrics.gmCellIncX + m_syntheticBoldOffset;
236 }
237 
scriptFontProperties() const238 SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const
239 {
240     if (!m_scriptFontProperties) {
241         m_scriptFontProperties = new SCRIPT_FONTPROPERTIES;
242         memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES));
243         m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
244         HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties);
245         if (result == E_PENDING) {
246             HDC dc = GetDC(0);
247             SaveDC(dc);
248             SelectObject(dc, m_platformData.hfont());
249             ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties);
250             RestoreDC(dc, -1);
251             ReleaseDC(0, dc);
252         }
253     }
254     return m_scriptFontProperties;
255 }
256 
257 }
258