Reviewed by Hyatt.
[WebKit-https.git] / WebCore / platform / mac / FontMac.mm
1 /**
2  * This file is part of the html renderer for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2000 Dirk Mueller (mueller@kde.org)
7  * Copyright (C) 2003, 2006 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25
26 #import "config.h"
27 #import "Font.h"
28
29 #import "Logging.h"
30 #import "BlockExceptions.h"
31 #import "FoundationExtras.h"
32
33 #import "FontDataSet.h"
34 #import "GraphicsContext.h"
35 #import "KWQKHTMLSettings.h"
36
37 #import "WebCoreTextRenderer.h"
38 #import "IntRect.h"
39
40 namespace WebCore {
41
42 FontDataSet::FontDataSet()
43 :m_pitch(UnknownPitch), m_renderer(nil)
44 {
45     m_webCoreFont.font = nil;
46 }
47
48 FontDataSet::~FontDataSet()
49 {
50     KWQRelease(m_renderer);
51     KWQRelease(m_webCoreFont.font);
52 }
53
54 const WebCoreFont& FontDataSet::getWebCoreFont(const FontDescription& fontDescription) const
55 {
56     if (!m_webCoreFont.font) {
57         CREATE_FAMILY_ARRAY(fontDescription, families);
58         BEGIN_BLOCK_OBJC_EXCEPTIONS;
59         int traits = 0;
60         if (fontDescription.italic())
61             traits |= NSItalicFontMask;
62         if (fontDescription.weight() >= WebCore::cBoldWeight)
63             traits |= NSBoldFontMask;
64         m_webCoreFont = [[WebCoreTextRendererFactory sharedFactory] 
65                                      fontWithFamilies:families traits:traits size:fontDescription.computedPixelSize()];
66         KWQRetain(m_webCoreFont.font);
67         m_webCoreFont.forPrinter = fontDescription.usePrinterFont();
68         END_BLOCK_OBJC_EXCEPTIONS;
69     }
70     return m_webCoreFont;
71 }
72
73 id <WebCoreTextRenderer> FontDataSet::getRenderer(const FontDescription& fontDescription)
74 {
75     if (!m_renderer)
76         m_renderer = KWQRetain([[WebCoreTextRendererFactory sharedFactory] rendererWithFont:getWebCoreFont(fontDescription)]);
77     return m_renderer;
78 }
79
80 void FontDataSet::determinePitch(const FontDescription& fontDescription) const {
81     BEGIN_BLOCK_OBJC_EXCEPTIONS;
82     if ([[WebCoreTextRendererFactory sharedFactory] isFontFixedPitch:getWebCoreFont(fontDescription)])
83         m_pitch = FixedPitch;
84     else
85         m_pitch = VariablePitch;
86     END_BLOCK_OBJC_EXCEPTIONS;
87 }
88
89 void FontDataSet::invalidate()
90 {
91     KWQRelease(m_renderer);
92     m_renderer = nil;
93     KWQRelease(m_webCoreFont.font);
94     m_webCoreFont.font = nil;
95     m_pitch = UnknownPitch;
96 }
97
98 const WebCoreFont& Font::getWebCoreFont() const
99 {
100     return m_dataSet->getWebCoreFont(fontDescription());
101 }
102
103 int Font::ascent() const
104 {
105     return [m_dataSet->getRenderer(fontDescription()) ascent];
106 }
107
108 int Font::descent() const
109 {
110     assert(m_dataSet);
111     return [m_dataSet->getRenderer(fontDescription()) descent];
112 }
113
114 int Font::lineSpacing() const
115 {
116     assert(m_dataSet);
117     return [m_dataSet->getRenderer(fontDescription()) lineSpacing];
118 }
119
120 float Font::xHeight() const
121 {
122     assert(m_dataSet);
123     return [m_dataSet->getRenderer(fontDescription()) xHeight];
124 }
125
126 bool Font::isFixedPitch() const
127 {
128     assert(m_dataSet);
129     return m_dataSet->isFixedPitch(fontDescription());
130 }
131
132 IntRect Font::selectionRectForText(const IntPoint& point, int h, int tabWidth, int xpos, 
133     const QChar* str, int slen, int pos, int l, int toAdd,
134     bool rtl, bool visuallyOrdered, int from, int to) const
135 {
136     assert(m_dataSet);
137     int len = std::min(slen - pos, l);
138
139     CREATE_FAMILY_ARRAY(fontDescription(), families);
140
141     if (from < 0)
142         from = 0;
143     if (to < 0)
144         to = len;
145
146     WebCoreTextRun run;
147     WebCoreInitializeTextRun(&run, (const UniChar *)(str+pos), len, from, to);    
148     WebCoreTextStyle style;
149     WebCoreInitializeEmptyTextStyle(&style);
150     style.rtl = rtl;
151     style.directionalOverride = visuallyOrdered;
152     style.letterSpacing = letterSpacing();
153     style.wordSpacing = wordSpacing();
154     style.smallCaps = fontDescription().smallCaps();
155     style.families = families;    
156     style.padding = toAdd;
157     style.tabWidth = tabWidth;
158     style.xpos = xpos;
159     WebCoreTextGeometry geometry;
160     WebCoreInitializeEmptyTextGeometry(&geometry);
161     geometry.point = point;
162     geometry.selectionY = point.y();
163     geometry.selectionHeight = h;
164     geometry.useFontMetricsForSelectionYAndHeight = false;
165     return enclosingIntRect([m_dataSet->getRenderer(fontDescription()) selectionRectForRun:&run style:&style geometry:&geometry]);
166 }
167                      
168 void Font::drawText(GraphicsContext* context, const IntPoint& point, int tabWidth, int xpos, const QChar* str, int len, int from, int to,
169                     int toAdd, TextDirection d, bool visuallyOrdered) const
170 {
171     // Avoid allocations, use stack array to pass font families.  Normally these
172     // css fallback lists are small <= 3.
173     CREATE_FAMILY_ARRAY(*this, families);
174
175     if (from < 0)
176         from = 0;
177     if (to < 0)
178         to = len;
179         
180     WebCoreTextRun run;
181     WebCoreInitializeTextRun(&run, (const UniChar *)str, len, from, to);    
182     WebCoreTextStyle style;
183     WebCoreInitializeEmptyTextStyle(&style);
184     style.textColor = nsColor(context->pen().color());
185     style.backgroundColor = nil;
186     style.rtl = d == RTL;
187     style.directionalOverride = visuallyOrdered;
188     style.letterSpacing = letterSpacing();
189     style.wordSpacing = wordSpacing();
190     style.smallCaps = isSmallCaps();
191     style.families = families;
192     style.padding = toAdd;
193     style.tabWidth = tabWidth;
194     style.xpos = xpos;
195     WebCoreTextGeometry geometry;
196     WebCoreInitializeEmptyTextGeometry(&geometry);
197     geometry.point = point;
198     [m_dataSet->getRenderer(fontDescription()) drawRun:&run style:&style geometry:&geometry];
199 }
200
201 void Font::drawHighlightForText(GraphicsContext* context, const IntPoint& point, int h, int tabWidth, int xpos, const QChar* str,
202                                 int len, int from, int to, int toAdd,
203                                 TextDirection d, bool visuallyOrdered, const Color& backgroundColor) const
204 {
205     // Avoid allocations, use stack array to pass font families.  Normally these
206     // css fallback lists are small <= 3.
207     CREATE_FAMILY_ARRAY(*this, families);
208
209     if (from < 0)
210         from = 0;
211     if (to < 0)
212         to = len;
213         
214     WebCoreTextRun run;
215     WebCoreInitializeTextRun(&run, (const UniChar *)str, len, from, to);    
216     WebCoreTextStyle style;
217     WebCoreInitializeEmptyTextStyle(&style);
218     style.textColor = nsColor(context->pen().color());
219     style.backgroundColor = backgroundColor.isValid() ? nsColor(backgroundColor) : nil;
220     style.rtl = d == RTL;
221     style.directionalOverride = visuallyOrdered;
222     style.letterSpacing = letterSpacing();
223     style.wordSpacing = wordSpacing();
224     style.smallCaps = isSmallCaps();
225     style.families = families;    
226     style.padding = toAdd;
227     style.tabWidth = tabWidth;
228     style.xpos = xpos;
229     WebCoreTextGeometry geometry;
230     WebCoreInitializeEmptyTextGeometry(&geometry);
231     geometry.point = point;
232     geometry.selectionY = point.y();
233     geometry.selectionHeight = h;
234     geometry.useFontMetricsForSelectionYAndHeight = false;
235     [m_dataSet->getRenderer(fontDescription()) drawHighlightForRun:&run style:&style geometry:&geometry];
236 }
237
238 void Font::drawLineForText(GraphicsContext* context, const IntPoint& point, int yOffset, int width) const
239 {
240     [m_dataSet->getRenderer(fontDescription())
241         drawLineForCharacters:point
242                       yOffset:(float)yOffset
243                         width:width
244                         color:nsColor(context->pen().color())
245                     thickness:context->pen().width()];
246 }
247
248 void Font::drawLineForMisspelling(GraphicsContext* context, const IntPoint& point, int width) const
249 {
250     [m_dataSet->getRenderer(fontDescription()) drawLineForMisspelling:point withWidth:width];
251 }
252
253 int Font::misspellingLineThickness(GraphicsContext* context) const
254 {
255     return [m_dataSet->getRenderer(fontDescription()) misspellingLineThickness];
256 }
257
258 float Font::floatWidth(const QChar* uchars, int slen, int pos, int len, int tabWidth, int xpos, bool runRounding) const
259 {
260     assert(m_dataSet);
261     CREATE_FAMILY_ARRAY(fontDescription(), families);
262
263     WebCoreTextRun run;
264     WebCoreInitializeTextRun(&run, (const UniChar *)uchars, slen, pos, pos+len);
265     
266     WebCoreTextStyle style;
267     WebCoreInitializeEmptyTextStyle(&style);
268     style.tabWidth = tabWidth;
269     style.xpos = xpos;
270     style.letterSpacing = letterSpacing();
271     style.wordSpacing = wordSpacing();
272     style.smallCaps = fontDescription().smallCaps();
273     style.families = families;
274     style.applyRunRounding = runRounding;
275
276     return [m_dataSet->getRenderer(fontDescription()) floatWidthForRun:&run style:&style];
277
278 }
279
280 int Font::checkSelectionPoint(const QChar* s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int x, TextDirection d, bool visuallyOrdered, bool includePartialGlyphs) const
281 {
282     assert(m_dataSet);
283     CREATE_FAMILY_ARRAY(fontDescription(), families);
284     
285     WebCoreTextRun run;
286     WebCoreInitializeTextRun(&run, (const UniChar *)(s+pos), std::min(slen - pos, len), 0, len);
287     
288     WebCoreTextStyle style;
289     WebCoreInitializeEmptyTextStyle(&style);
290     style.letterSpacing = letterSpacing();
291     style.wordSpacing = wordSpacing();
292     style.smallCaps = fontDescription().smallCaps();
293     style.families = families;
294     style.padding = toAdd;
295     style.tabWidth = tabWidth;
296     style.xpos = xpos;
297     style.rtl =  d == RTL;
298     style.directionalOverride = visuallyOrdered;
299
300     return [m_dataSet->getRenderer(fontDescription()) pointToOffset:&run style:&style position:x includePartialGlyphs:includePartialGlyphs];
301 }
302
303 }