29c42bc7f95a8427e61708252873b9527f7681b5
[WebKit-https.git] / WebCore / platform / win / FontDataWin.cpp
1 /*
2  * Copyright (C) 2006, 2007 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 <winsock2.h>
31 #include "Font.h"
32 #include "FontCache.h"
33 #include "FontData.h"
34 #include "FloatRect.h"
35 #include "FontDescription.h"
36 #include <wtf/MathExtras.h>
37 #include <unicode/uchar.h>
38 #include <unicode/unorm.h>
39 #include <ApplicationServices/ApplicationServices.h>
40 #include <mlang.h>
41 #include <tchar.h>
42 #include <WebKitSystemInterface/WebKitSystemInterface.h>
43
44 namespace WebCore {
45
46 using std::max;
47
48 static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return unitsPerEm ? x / (float)unitsPerEm : x; }
49
50 void FontData::platformInit()
51 {    
52     HDC dc = GetDC(0);
53     SaveDC(dc);
54
55     SelectObject(dc, m_font.hfont());
56
57     int faceLength = GetTextFace(dc, 0, 0);
58     Vector<TCHAR> faceName(faceLength);
59     GetTextFace(dc, faceLength, faceName.data());
60
61     m_isMLangFont = false;
62
63     m_syntheticBoldOffset = m_font.syntheticBold() ? 1.0f : 0.f;
64
65     CGFontRef font = m_font.cgFont();
66     int iAscent = CGFontGetAscent(font);
67     int iDescent = CGFontGetDescent(font);
68     int iLineGap = CGFontGetLeading(font);
69     unsigned unitsPerEm = CGFontGetUnitsPerEm(font);
70     float pointSize = m_font.size();
71     float fAscent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize;
72     float fDescent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize;
73     float fLineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize;
74
75     m_isSystemFont = !_tcscmp(faceName.data(), _T("Lucida Grande"));
76     
77     // We need to adjust Times, Helvetica, and Courier to closely match the
78     // vertical metrics of their Microsoft counterparts that are the de facto
79     // web standard. The AppKit adjustment of 20% is too big and is
80     // incorrectly added to line spacing, so we use a 15% adjustment instead
81     // and add it to the ascent.
82     if (!_tcscmp(faceName.data(), _T("Times")) || !_tcscmp(faceName.data(), _T("Helvetica")) || !_tcscmp(faceName.data(), _T("Courier")))
83         fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f);
84
85     m_ascent = lroundf(fAscent);
86     m_descent = lroundf(fDescent);
87     m_lineGap = lroundf(fLineGap);
88     m_lineSpacing = m_ascent + m_descent + m_lineGap;
89
90     // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font.
91     // Unfortunately, NSFont will round this for us so we don't quite get the right value.
92     Glyph xGlyph = GlyphPageTreeNode::getRootChild(this, 0)->page()->glyphDataForCharacter('x').glyph;
93     if (xGlyph) {
94         CGRect xBox;
95         CGFontGetGlyphBBoxes(font, &xGlyph, 1, &xBox);
96         // Use the maximum of either width or height because "x" is nearly square
97         // and web pages that foolishly use this metric for width will be laid out
98         // poorly if we return an accurate height. Classic case is Times 13 point,
99         // which has an "x" that is 7x6 pixels.
100         m_xHeight = scaleEmToUnits(max(CGRectGetMaxX(xBox), CGRectGetMaxY(xBox)), unitsPerEm) * pointSize;
101     } else {
102         int iXHeight = CGFontGetXHeight(font);
103         m_xHeight = scaleEmToUnits(iXHeight, unitsPerEm) * pointSize;
104     }
105
106     RestoreDC(dc, -1);
107     ReleaseDC(0, dc);
108
109     m_scriptCache = 0;
110     m_scriptFontProperties = 0;
111 }
112
113 void FontData::platformDestroy()
114 {
115     CGFontRelease(m_font.cgFont());
116
117     if (m_isMLangFont) {
118         // We have to release the font instead of just deleting it, since we didn't make it.
119         IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface();
120         if (langFontLink)
121             langFontLink->ReleaseFont(m_font.hfont());
122     } else
123         DeleteObject(m_font.hfont());
124
125     // We don't hash this on Win32, so it's effectively owned by us.
126     delete m_smallCapsFontData;
127
128     ScriptFreeCache(&m_scriptCache);
129     delete m_scriptFontProperties;
130 }
131
132 FontData* FontData::smallCapsFontData(const FontDescription& fontDescription) const
133 {
134     if (!m_smallCapsFontData) {
135         LOGFONT winfont;
136         GetObject(m_font.hfont(), sizeof(LOGFONT), &winfont);
137         int smallCapsHeight = lroundf(0.70f * fontDescription.computedSize());
138         winfont.lfHeight = -smallCapsHeight * 32;
139         HFONT hfont = CreateFontIndirect(&winfont);
140         m_smallCapsFontData = new FontData(FontPlatformData(hfont, smallCapsHeight, fontDescription.bold(), fontDescription.italic()));
141     }
142     return m_smallCapsFontData;
143 }
144
145 bool FontData::containsCharacters(const UChar* characters, int length) const
146 {
147     HDC dc = GetDC(0);
148     SaveDC(dc);
149     SelectObject(dc, m_font.hfont());
150
151     WORD* glyphBuffer = new WORD[length];
152     GetGlyphIndices(dc, characters, length, glyphBuffer, GGI_MARK_NONEXISTING_GLYPHS);
153     
154     RestoreDC(dc, -1);
155     ReleaseDC(0, dc);
156
157     for (int i = 0; i < length; i++) {
158         if (glyphBuffer[i] == 0xFFFFFFFF) {
159             delete []glyphBuffer;
160             return false;
161         }
162     }
163
164     delete []glyphBuffer;
165     return true;
166 }
167
168 void FontData::determinePitch()
169 {
170     // TEXTMETRICS have this.  Set m_treatAsFixedPitch based off that.
171     HDC dc = GetDC((HWND)0);
172     SaveDC(dc);
173     SelectObject(dc, m_font.hfont());
174
175     // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
176     // is *not* fixed pitch.  Unbelievable but true.
177     TEXTMETRIC tm;
178     GetTextMetrics(dc, &tm);
179     m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
180
181     RestoreDC(dc, -1);
182     ReleaseDC(0, dc);
183 }
184
185 float FontData::platformWidthForGlyph(Glyph glyph) const
186 {
187     CGFontRef font = m_font.cgFont();
188     float pointSize = m_font.size();
189     CGSize advance;
190     CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
191     // FIXME: Need to add real support for printer fonts.
192     bool isPrinterFont = false;
193     wkGetGlyphAdvances(font, m, m_isSystemFont, isPrinterFont, glyph, advance);
194     return advance.width + m_syntheticBoldOffset;
195 }
196
197 SCRIPT_FONTPROPERTIES* FontData::scriptFontProperties() const
198 {
199     if (!m_scriptFontProperties) {
200         m_scriptFontProperties = new SCRIPT_FONTPROPERTIES;
201         memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES));
202         m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
203         HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties);
204         if (result == E_PENDING) {
205             HDC dc = GetDC(0);
206             SaveDC(dc);
207             SelectObject(dc, m_font.hfont());
208             ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties);
209             RestoreDC(dc, -1);
210             ReleaseDC(0, dc);
211         }
212     }
213     return m_scriptFontProperties;
214 }
215
216 }