[Win] Reduce the use of WKSI library calls: Font Handling
[WebKit-https.git] / Source / WebCore / platform / graphics / win / SimpleFontDataCGWin.cpp
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 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 "Font.h"
31
32 #if USE(CG)
33
34 #include "FloatRect.h"
35 #include "FontCache.h"
36 #include "FontCascade.h"
37 #include "FontDescription.h"
38 #include "GlyphPage.h"
39 #include "HWndDC.h"
40 #include "OpenTypeCG.h"
41 #include <mlang.h>
42 #include <pal/spi/win/CoreTextSPIWin.h>
43 #include <unicode/uchar.h>
44 #include <unicode/unorm.h>
45 #include <winsock2.h>
46 #include <wtf/MathExtras.h>
47 #include <wtf/RetainPtr.h>
48 #include <wtf/text/WTFString.h>
49
50 namespace WebCore {
51
52 using namespace std;
53
54 void Font::platformInit()
55 {
56     m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f;
57     m_scriptCache = 0;
58     m_scriptFontProperties = 0;
59
60     if (m_platformData.useGDI())
61         return initGDIFont();
62
63     CGFontRef font = m_platformData.cgFont();
64     int iAscent = CGFontGetAscent(font);
65     int iDescent = CGFontGetDescent(font);
66     int iLineGap = CGFontGetLeading(font);
67     int iCapHeight = CGFontGetCapHeight(font);
68
69     // The Open Font Format describes the OS/2 USE_TYPO_METRICS flag as follows:
70     // "If set, it is strongly recommended to use OS/2.sTypoAscender - OS/2.sTypoDescender+ OS/2.sTypoLineGap as a value for default line spacing for this font."
71     short typoAscent, typoDescent, typoLineGap;
72     if (OpenType::tryGetTypoMetrics(adoptCF(CTFontCreateWithGraphicsFont(m_platformData.cgFont(), m_platformData.size(), nullptr, nullptr)).get(), typoAscent, typoDescent, typoLineGap)) {
73         iAscent = typoAscent;
74         iDescent = typoDescent;
75         iLineGap = typoLineGap;
76     }
77
78     unsigned unitsPerEm = CGFontGetUnitsPerEm(font);
79     float pointSize = m_platformData.size();
80     float fAscent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize;
81     float fDescent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize;
82     float fCapHeight = scaleEmToUnits(iCapHeight, unitsPerEm) * pointSize;
83     float fLineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize;
84
85     if (origin() == Origin::Local) {
86         HWndDC dc(0);
87         HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont());
88         int faceLength = GetTextFace(dc, 0, 0);
89         Vector<WCHAR> faceName(faceLength);
90         GetTextFace(dc, faceLength, faceName.data());
91         SelectObject(dc, oldFont);
92
93         fAscent = ascentConsideringMacAscentHack(faceName.data(), fAscent, fDescent);
94     }
95
96     m_fontMetrics.setAscent(fAscent);
97     m_fontMetrics.setDescent(fDescent);
98     m_fontMetrics.setCapHeight(fCapHeight);
99     m_fontMetrics.setLineGap(fLineGap);
100     m_fontMetrics.setLineSpacing(lroundf(fAscent) + lroundf(fDescent) + lroundf(fLineGap));
101
102     Glyph xGlyph = glyphDataForCharacter('x').glyph;
103     if (xGlyph) {
104         // Measure the actual character "x", since it's possible for it to extend below the baseline, and we need the
105         // reported x-height to only include the portion of the glyph that is above the baseline.
106         CGRect xBox;
107         CGFontGetGlyphBBoxes(font, &xGlyph, 1, &xBox);
108         m_fontMetrics.setXHeight(scaleEmToUnits(CGRectGetMaxY(xBox), unitsPerEm) * pointSize);
109     } else {
110         int iXHeight = CGFontGetXHeight(font);
111         m_fontMetrics.setXHeight(scaleEmToUnits(iXHeight, unitsPerEm) * pointSize);
112     }
113
114     m_fontMetrics.setUnitsPerEm(unitsPerEm);
115 }
116
117 FloatRect Font::platformBoundsForGlyph(Glyph glyph) const
118 {
119     if (!platformData().size())
120         return FloatRect();
121
122     if (m_platformData.useGDI())
123         return boundsForGDIGlyph(glyph);
124
125     CGRect box;
126     CGFontGetGlyphBBoxes(m_platformData.cgFont(), &glyph, 1, &box);
127     float pointSize = m_platformData.size();
128     CGFloat scale = pointSize / fontMetrics().unitsPerEm();
129     FloatRect boundingBox = CGRectApplyAffineTransform(box, CGAffineTransformMakeScale(scale, -scale));
130     if (m_syntheticBoldOffset)
131         boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset);
132
133     return boundingBox;
134 }
135
136 float Font::platformWidthForGlyph(Glyph glyph) const
137 {
138     if (!platformData().size())
139         return 0;
140
141     if (m_platformData.useGDI())
142         return widthForGDIGlyph(glyph);
143
144     CGFontRef font = m_platformData.cgFont();
145     float pointSize = m_platformData.size();
146     CGSize advance;
147     CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
148  
149     bool isPrinterFont = false;
150     FontCascade::getPlatformGlyphAdvances(font, m, m_platformData.isSystemFont(), isPrinterFont, glyph, advance);
151
152     return advance.width + m_syntheticBoldOffset;
153 }
154
155 Path Font::platformPathForGlyph(Glyph glyph) const
156 {
157     auto ctFont = adoptCF(CTFontCreateWithGraphicsFont(platformData().cgFont(), platformData().size(), nullptr, nullptr));
158     auto result = adoptCF(CTFontCreatePathForGlyph(ctFont.get(), glyph, nullptr));
159     auto syntheticBoldOffset = this->syntheticBoldOffset();
160     if (syntheticBoldOffset) {
161         auto newPath = adoptCF(CGPathCreateMutable());
162         CGPathAddPath(newPath.get(), nullptr, result.get());
163         auto translation = CGAffineTransformMakeTranslation(syntheticBoldOffset, 0);
164         CGPathAddPath(newPath.get(), &translation, result.get());
165         return newPath;
166     }
167     return adoptCF(CGPathCreateMutableCopy(result.get()));
168 }
169
170 }
171
172 #endif