2559f2feb178273d9186362e676c6227c0e61445
[WebKit-https.git] / WebCore / kwq / KWQFontMetrics.mm
1 /*
2  * Copyright (C) 2004 Apple Computer, 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "KWQFontMetrics.h"
27
28 #import <Cocoa/Cocoa.h>
29
30 #import "KWQFont.h"
31 #import "KWQLogging.h"
32 #import "KWQFoundationExtras.h"
33
34 #import "WebCoreTextRenderer.h"
35 #import "WebCoreTextRendererFactory.h"
36
37 // We know that none of the ObjC calls here will raise exceptions
38 // because they are all calls to WebCoreTextRenderer, which has a
39 // contract of not raising.
40
41 struct QFontMetricsPrivate
42 {
43     QFontMetricsPrivate(const QFont &font)
44         : refCount(0), _font(font), _renderer(nil)
45     {
46     }
47     ~QFontMetricsPrivate()
48     {
49         KWQRelease(_renderer);
50     }
51     id <WebCoreTextRenderer> getRenderer()
52     {
53         if (!_renderer) {
54             _renderer = KWQRetain([[WebCoreTextRendererFactory sharedFactory]
55                 rendererWithFont:_font.getNSFont()
56                 usingPrinterFont:_font.isPrinterFont()]);
57         }
58         return _renderer;
59     }
60     
61     const QFont &font() const { return _font; }
62     void setFont(const QFont &font)
63     {
64         if (_font == font) {
65             return;
66         }
67         _font = font;
68         KWQRelease(_renderer);
69         _renderer = nil;
70     }
71     
72     int refCount;
73     
74 private:
75     QFont _font;
76     id <WebCoreTextRenderer> _renderer;
77     
78     QFontMetricsPrivate(const QFontMetricsPrivate&);
79     QFontMetricsPrivate& operator=(const QFontMetricsPrivate&);
80 };
81
82 QFontMetrics::QFontMetrics()
83 {
84 }
85
86 QFontMetrics::QFontMetrics(const QFont &font)
87     : data(new QFontMetricsPrivate(font))
88 {
89 }
90
91 QFontMetrics::QFontMetrics(const QFontMetrics &other)
92     : data(other.data)
93 {
94 }
95
96 QFontMetrics::~QFontMetrics()
97 {
98 }
99
100 QFontMetrics &QFontMetrics::operator=(const QFontMetrics &other)
101 {
102     data = other.data;
103     return *this;
104 }
105
106 void QFontMetrics::setFont(const QFont &font)
107 {
108     if (data.isNull()) {
109         data = KWQRefPtr<QFontMetricsPrivate>(new QFontMetricsPrivate(font));
110     } else {
111         data->setFont(font);
112     }
113 }
114
115 int QFontMetrics::ascent() const
116 {
117     if (data.isNull()) {
118         ERROR("called ascent on an empty QFontMetrics");
119         return 0;
120     }
121     
122     return [data->getRenderer() ascent];
123 }
124
125 int QFontMetrics::descent() const
126 {
127     if (data.isNull()) {
128         ERROR("called descent on an empty QFontMetrics");
129         return 0;
130     }
131     
132     return [data->getRenderer() descent];
133 }
134
135 int QFontMetrics::height() const
136 {
137     // According to Qt documentation: 
138     // "This is always equal to ascent()+descent()+1 (the 1 is for the base line)."
139     // We DO NOT match the Qt behavior here.  This is intentional.
140     return ascent() + descent();
141 }
142
143 int QFontMetrics::lineSpacing() const
144 {
145     if (data.isNull()) {
146         ERROR("called lineSpacing on an empty QFontMetrics");
147         return 0;
148     }
149     return [data->getRenderer() lineSpacing];
150 }
151
152 float QFontMetrics::xHeight() const
153 {
154     if (data.isNull()) {
155         ERROR("called xHeight on an empty QFontMetrics");
156         return 0;
157     }
158     return [data->getRenderer() xHeight];
159 }
160
161 int QFontMetrics::width(QChar qc, int tabWidth, int xpos) const
162 {
163     if (data.isNull()) {
164         ERROR("called width on an empty QFontMetrics");
165         return 0;
166     }
167     
168     UniChar c = qc.unicode();
169
170     CREATE_FAMILY_ARRAY(data->font(), families);
171
172     WebCoreTextRun run;
173     WebCoreInitializeTextRun(&run, &c, 1, 0, 1);
174     
175     WebCoreTextStyle style;
176     WebCoreInitializeEmptyTextStyle(&style);
177     style.families = families;
178     style.tabWidth = tabWidth;
179     style.xpos = xpos;
180
181     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
182 }
183
184 int QFontMetrics::charWidth(const QString &s, int pos, int tabWidth, int xpos) const
185 {
186     return width(s[pos], tabWidth, xpos);
187 }
188
189 int QFontMetrics::width(char c, int tabWidth, int xpos) const
190 {
191     if (data.isNull()) {
192         ERROR("called width on an empty QFontMetrics");
193         return 0;
194     }
195     
196     UniChar ch = (uchar) c;
197
198     CREATE_FAMILY_ARRAY(data->font(), families);
199
200     WebCoreTextRun run;
201     WebCoreInitializeTextRun(&run, &ch, 1, 0, 1);
202     
203     WebCoreTextStyle style;
204     WebCoreInitializeEmptyTextStyle(&style);
205     style.families = families;
206     style.tabWidth = tabWidth;
207     style.xpos = xpos;
208
209     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
210 }
211
212 int QFontMetrics::width(const QString &qstring, int tabWidth, int xpos, int len) const
213 {
214     if (data.isNull()) {
215         ERROR("called width on an empty QFontMetrics");
216         return 0;
217     }
218     
219     CREATE_FAMILY_ARRAY(data->font(), families);
220
221     int length = len == -1 ? qstring.length() : len;
222
223     WebCoreTextRun run;
224     WebCoreInitializeTextRun(&run, (const UniChar *)qstring.unicode(), length, 0, length);
225     
226     WebCoreTextStyle style;
227     WebCoreInitializeEmptyTextStyle(&style);
228     style.families = families;
229     style.tabWidth = tabWidth;
230     style.xpos = xpos;
231
232     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
233 }
234
235 int QFontMetrics::width(const QChar *uchars, int len, int tabWidth, int xpos) const
236 {
237     if (data.isNull()) {
238         ERROR("called width on an empty QFontMetrics");
239         return 0;
240     }
241     
242     CREATE_FAMILY_ARRAY(data->font(), families);
243
244     WebCoreTextRun run;
245     WebCoreInitializeTextRun(&run, (const UniChar *)uchars, len, 0, len);
246     
247     WebCoreTextStyle style;
248     WebCoreInitializeEmptyTextStyle(&style);
249     style.families = families;
250     style.tabWidth = tabWidth;
251     style.xpos = xpos;
252
253     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
254 }
255
256 float QFontMetrics::floatWidth(const QChar *uchars, int slen, int pos, int len,
257                                int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps) const
258 {
259     if (data.isNull()) {
260         ERROR("called floatWidth on an empty QFontMetrics");
261         return 0;
262     }
263     
264     CREATE_FAMILY_ARRAY(data->font(), families);
265
266     WebCoreTextRun run;
267     WebCoreInitializeTextRun(&run, (const UniChar *)uchars, slen, pos, pos+len);
268     
269     WebCoreTextStyle style;
270     WebCoreInitializeEmptyTextStyle(&style);
271     style.tabWidth = tabWidth;
272     style.xpos = xpos;
273     style.letterSpacing = letterSpacing;
274     style.wordSpacing = wordSpacing;
275     style.smallCaps = smallCaps;
276     style.families = families;
277
278     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
279 }
280
281 float QFontMetrics::floatCharacterWidths(const QChar *uchars, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, float *buffer, int letterSpacing, int wordSpacing, bool smallCaps) const
282 {
283     if (data.isNull()) {
284         ERROR("called floatCharacterWidths on an empty QFontMetrics");
285         return 0;
286     }
287     
288     CREATE_FAMILY_ARRAY(data->font(), families);
289
290     WebCoreTextRun run;
291     WebCoreInitializeTextRun(&run, (const UniChar *)uchars, slen, pos, pos+len);
292     
293     WebCoreTextStyle style;
294     WebCoreInitializeEmptyTextStyle(&style);
295     style.letterSpacing = letterSpacing;
296     style.wordSpacing = wordSpacing;
297     style.smallCaps = smallCaps;
298     style.padding = toAdd;
299     style.tabWidth = tabWidth;
300     style.xpos = xpos;
301     style.families = families;
302
303     return [data->getRenderer() floatWidthForRun:&run style:&style widths:buffer];
304 }
305
306 int QFontMetrics::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool includePartialGlyphs) const
307 {
308     if (data.isNull()) {
309         ERROR("called floatWidth on an empty QFontMetrics");
310         return 0;
311     }
312     
313     CREATE_FAMILY_ARRAY(data->font(), families);
314     WebCoreTextRun run;
315     WebCoreInitializeTextRun(&run, (const UniChar *)s, slen, pos, pos+len);
316     
317     WebCoreTextStyle style;
318     WebCoreInitializeEmptyTextStyle(&style);
319     style.letterSpacing = letterSpacing;
320     style.wordSpacing = wordSpacing;
321     style.smallCaps = smallCaps;
322     style.families = families;
323     style.padding = toAdd;
324     style.tabWidth = tabWidth;
325     style.xpos = xpos;
326     style.rtl = reversed;
327
328     return [data->getRenderer() pointToOffset:&run style:&style position:x reversed:reversed includePartialGlyphs:includePartialGlyphs];
329 }
330
331 QRect QFontMetrics::boundingRect(QChar c) const
332 {
333     return QRect(0, 0, width(c, 0, 0), height());
334 }
335
336 QRect QFontMetrics::boundingRect(const QString &qstring, int tabWidth, int xpos, int len) const
337 {
338     return QRect(0, 0, width(qstring, tabWidth, xpos, len), height());
339 }
340
341 QRect QFontMetrics::boundingRect(int x, int y, int width, int height, int flags, const QString &str, int tabWidth, int xpos) const
342 {
343     // FIXME: need to support word wrapping?
344     return QRect(x, y, width, height).intersect(boundingRect(str, tabWidth, xpos));
345 }
346
347 QSize QFontMetrics::size(int, const QString &qstring, int tabWidth, int xpos) const
348 {
349     return QSize(width(qstring, tabWidth, xpos), height());
350 }