Fix typo from the removal of the inline keyword from some functions.
[WebKit-https.git] / WebCore / platform / Font.cpp
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 #include "config.h"
27 #include "Font.h"
28 #include "FontData.h"
29
30 #include "FontFallbackList.h"
31 #include "GraphicsContext.h"
32 #include "KWQKHTMLSettings.h"
33
34 #include "GlyphBuffer.h"
35
36 #include <unicode/umachine.h>
37
38 namespace WebCore {
39
40 #if __APPLE__
41
42 // FIXME: Cross-platform eventually, but for now we compile only on OS X.
43 #define SPACE 0x0020
44 #define NO_BREAK_SPACE 0x00A0
45
46 // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values
47 #define HIRAGANA_KATAKANA_VOICING_MARKS 8
48
49 bool isSpace(unsigned c)
50 {
51     return c == SPACE || c == '\t' || c == '\n' || c == NO_BREAK_SPACE;
52 }
53
54 static const uint8_t isRoundingHackCharacterTable[0x100] = {
55     0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56     1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/,
57     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60     1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
63 };
64
65 bool isRoundingHackCharacter(UChar32 c)
66 {
67     return (((c & ~0xFF) == 0 && isRoundingHackCharacterTable[c]));
68 }
69
70 struct WidthIterator {
71     WidthIterator(const Font* font, const UChar* str, int from, int to, int len,
72                   int tabWidth, int xpos, int toAdd, TextDirection dir, bool visuallyOrdered,
73                   bool applyWordRounding, bool applyRunRounding, const FontData* substituteFontData);
74
75     void advance(int to, GlyphBuffer* glyphBuffer = 0);
76
77     const Font* m_font;
78
79     const UChar* m_characters;
80     int m_from;
81     int m_to;
82     int m_len;
83     int m_tabWidth;
84     int m_xPos;
85     int m_toAdd;
86     TextDirection m_dir;
87     bool m_visuallyOrdered;
88     bool m_applyWordRounding;
89     bool m_applyRunRounding;
90     const FontData* m_substituteFontData;
91
92     unsigned m_currentCharacter;
93     float m_runWidthSoFar;
94     float m_widthToStart;
95     float m_padding;
96     float m_padPerSpace;
97     float m_finalRoundingWidth;
98     
99 private:
100     UChar32 normalizeVoicingMarks();
101 };
102
103 WidthIterator::WidthIterator(const Font* font, const UChar* str, int from, int to, int len,
104                              int tabWidth, int xpos, int toAdd, TextDirection dir, bool visuallyOrdered,
105                              bool applyWordRounding, bool applyRunRounding, const FontData* substituteFontData)
106 :m_font(font), m_characters((const UChar*)str), m_from(from), m_to(to), m_len(len),
107  m_tabWidth(tabWidth), m_xPos(xpos), m_toAdd(toAdd), m_dir(dir), m_visuallyOrdered(visuallyOrdered),
108  m_applyWordRounding(applyWordRounding), m_applyRunRounding(applyRunRounding), m_substituteFontData(substituteFontData),
109  m_currentCharacter(from), m_runWidthSoFar(0), m_finalRoundingWidth(0)
110 {
111     // If the padding is non-zero, count the number of spaces in the run
112     // and divide that by the padding for per space addition.
113     if (!toAdd) {
114         m_padding = 0;
115         m_padPerSpace = 0;
116     } else {
117         float numSpaces = 0;
118         for (int i = from; i < to; i++)
119             if (isSpace(m_characters[i]))
120                 numSpaces++;
121
122         m_padding = toAdd;
123         m_padPerSpace = ceilf(m_padding / numSpaces);
124     }
125     
126     // Calculate width up to starting position of the run.  This is
127     // necessary to ensure that our rounding hacks are always consistently
128     // applied.
129     if (m_from == 0)
130         m_widthToStart = 0;
131     else {
132         WidthIterator startPositionIterator(font, str, 0, len, len, tabWidth, xpos, toAdd, dir, visuallyOrdered,
133                                             applyWordRounding, applyRunRounding, substituteFontData);
134         startPositionIterator.advance(from);
135         m_widthToStart = startPositionIterator.m_runWidthSoFar;
136     }
137 }
138
139 void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
140 {
141     if (offset > m_to)
142         offset = m_to;
143
144     int currentCharacter = m_currentCharacter;
145     const UChar* cp = &m_characters[currentCharacter];
146
147     bool rtl = (m_dir == RTL);
148     bool needCharTransform = rtl || m_font->isSmallCaps();
149     bool hasExtraSpacing = m_font->letterSpacing() || m_font->wordSpacing() || m_padding;
150
151     float runWidthSoFar = m_runWidthSoFar;
152     float lastRoundingWidth = m_finalRoundingWidth;
153
154     const FontData* primaryFontData = m_font->primaryFont();
155     
156     while (currentCharacter < offset) {
157         UChar32 c = *cp;
158         unsigned clusterLength = 1;
159         if (c >= 0x3041) {
160             if (c <= 0x30FE) {
161                 // Deal with Hiragana and Katakana voiced and semi-voiced syllables.
162                 // Normalize into composed form, and then look for glyph with base + combined mark.
163                 // Check above for character range to minimize performance impact.
164                 UChar32 normalized = normalizeVoicingMarks();
165                 if (normalized) {
166                     c = normalized;
167                     clusterLength = 2;
168                 }
169             } else if (U16_IS_SURROGATE(c)) {
170                 if (!U16_IS_SURROGATE_LEAD(c))
171                     break;
172
173                 // Do we have a surrogate pair?  If so, determine the full Unicode (32 bit)
174                 // code point before glyph lookup.
175                 // Make sure we have another character and it's a low surrogate.
176                 if (currentCharacter + 1 >= m_len)
177                     break;
178                 UniChar low = cp[1];
179                 if (!U16_IS_TRAIL(low))
180                     break;
181                 c = U16_GET_SUPPLEMENTARY(c, low);
182                 clusterLength = 2;
183             }
184         }
185
186         const FontData* fontData = m_substituteFontData ? m_substituteFontData :primaryFontData;
187
188         if (needCharTransform) {
189             if (rtl)
190                 c = u_charMirror(c);
191
192             // If small-caps, convert lowercase to upper.
193             if (m_font->isSmallCaps() && !u_isUUppercase(c)) {
194                 UChar32 upperC = u_toupper(c);
195                 if (upperC != c) {
196                     c = upperC;
197                     fontData = fontData->smallCapsFontData();
198                 }
199             }
200         }
201
202         // FIXME: Should go through fallback list eventually when we rework the glyph map.
203         Glyph glyph = fontData->glyphForCharacter(&fontData, c);
204
205         // Try to find a substitute font if this font didn't have a glyph for a character in the
206         // string. If one isn't found we end up drawing and measuring the 0 glyph, usually a box.
207         if (glyph == 0 && !m_substituteFontData) {
208             // FIXME: Should go through fallback list eventually.
209             const FontData* substituteFontData = fontData->findSubstituteFontData(cp, clusterLength, m_font->fontDescription());
210             if (substituteFontData) {
211                 GlyphBuffer localGlyphBuffer;
212                 m_font->floatWidthForSimpleText((UChar*)cp, clusterLength, 0, clusterLength, 0, 0, 0, m_dir, m_visuallyOrdered, 
213                                                  m_applyWordRounding, false, substituteFontData, 0, &localGlyphBuffer);
214                 if (localGlyphBuffer.size() == 1) {
215                     assert(substituteFontData == localGlyphBuffer.fontDataAt(0));
216                     glyph = localGlyphBuffer.glyphAt(0);
217                     fontData->updateGlyphMapEntry(c, glyph, substituteFontData);
218                     fontData = substituteFontData;
219                 }
220             }
221         }
222
223         // Now that we have a glyph and font data, get its width.
224         float width;
225         if (c == '\t' && m_tabWidth)
226             width = m_tabWidth - fmodf(m_xPos + runWidthSoFar, m_tabWidth);
227         else {
228             width = fontData->widthForGlyph(glyph);
229             // We special case spaces in two ways when applying word rounding.
230             // First, we round spaces to an adjusted width in all fonts.
231             // Second, in fixed-pitch fonts we ensure that all characters that
232             // match the width of the space character have the same width as the space character.
233             if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_applyWordRounding)
234                 width = fontData->m_adjustedSpaceWidth;
235         }
236
237         if (hasExtraSpacing) {
238             // Account for letter-spacing.
239             if (width && m_font->letterSpacing())
240                 width += m_font->letterSpacing();
241
242             if (isSpace(c)) {
243                 // Account for padding. WebCore uses space padding to justify text.
244                 // We distribute the specified padding over the available spaces in the run.
245                 if (m_padding) {
246                     // Use left over padding if not evenly divisible by number of spaces.
247                     if (m_padding < m_padPerSpace) {
248                         width += m_padding;
249                         m_padding = 0;
250                     } else {
251                         width += m_padPerSpace;
252                         m_padding -= m_padPerSpace;
253                     }
254                 }
255
256                 // Account for word spacing.
257                 // We apply additional space between "words" by adding width to the space character.
258                 if (currentCharacter != 0 && !isSpace(cp[-1]) && m_font->wordSpacing())
259                     width += m_font->wordSpacing();
260             }
261         }
262
263         // Advance past the character we just dealt with.
264         cp += clusterLength;
265         currentCharacter += clusterLength;
266
267         // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters 
268         // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
269         // We adjust the width of the last character of a "word" to ensure an integer width.
270         // If we move KHTML to floats we can remove this (and related) hacks.
271
272         float oldWidth = width;
273
274         // Force characters that are used to determine word boundaries for the rounding hack
275         // to be integer width, so following words will start on an integer boundary.
276         if (m_applyWordRounding && isRoundingHackCharacter(c))
277             width = ceilf(width);
278
279         // Check to see if the next character is a "rounding hack character", if so, adjust
280         // width so that the total run width will be on an integer boundary.
281         if ((m_applyWordRounding && currentCharacter < m_len && isRoundingHackCharacter(*cp))
282                 || (m_applyRunRounding && currentCharacter >= m_to)) {
283             float totalWidth = m_widthToStart + runWidthSoFar + width;
284             width += ceilf(totalWidth) - totalWidth;
285         }
286
287         runWidthSoFar += width;
288
289         if (glyphBuffer)
290             glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width));
291
292         lastRoundingWidth = width - oldWidth;
293     }
294
295     m_currentCharacter = currentCharacter;
296     m_runWidthSoFar = runWidthSoFar;
297     m_finalRoundingWidth = lastRoundingWidth;
298 }
299
300 UChar32 WidthIterator::normalizeVoicingMarks()
301 {
302     int currentCharacter = m_currentCharacter;
303     if (currentCharacter + 1 < m_to) {
304         if (u_getCombiningClass(m_characters[currentCharacter + 1]) == HIRAGANA_KATAKANA_VOICING_MARKS) {
305             // Normalize into composed form using 3.2 rules.
306             UChar normalizedCharacters[2] = { 0, 0 };
307             UErrorCode uStatus = (UErrorCode)0;  
308             int32_t resultLength = unorm_normalize(&m_characters[currentCharacter], 2,
309                 UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus);
310             if (resultLength == 1 && uStatus == 0)
311                 return normalizedCharacters[0];
312         }
313     }
314     return 0;
315 }
316 #endif
317
318 // ============================================================================================
319 // Font Implementation (Cross-Platform Portion)
320 // ============================================================================================
321
322 Font::Font() :m_fontList(0), m_letterSpacing(0), m_wordSpacing(0) {}
323 Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing) 
324 : m_fontDescription(fd),
325   m_fontList(0),
326   m_letterSpacing(letterSpacing),
327   m_wordSpacing(wordSpacing)
328 {}
329
330 Font::Font(const Font& other)
331 {
332     m_fontDescription = other.m_fontDescription;
333     m_fontList = other.m_fontList;
334     m_letterSpacing = other.m_letterSpacing;
335     m_wordSpacing = other.m_wordSpacing;
336 }
337
338 Font& Font::operator=(const Font& other)
339 {
340     if (&other != this) {
341         m_fontDescription = other.m_fontDescription;
342         m_fontList = other.m_fontList;
343         m_letterSpacing = other.m_letterSpacing;
344         m_wordSpacing = other.m_wordSpacing;
345     }
346     return *this;
347 }
348
349 Font::~Font()
350 {
351 }
352
353 const FontData* Font::primaryFont() const
354 {
355     assert(m_fontList);
356     return m_fontList->primaryFont(m_fontDescription);
357 }
358
359 void Font::update() const
360 {
361     // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up 
362     // being reasonably safe (because inherited fonts in the render tree pick up the new
363     // style anyway.  Other copies are transient, e.g., the state in the GraphicsContext, and
364     // won't stick around long enough to get you in trouble).  Still, this is pretty disgusting,
365     // and could eventually be rectified by using RefPtrs for Fonts themselves.
366     if (!m_fontList)
367         m_fontList = new FontFallbackList();
368     m_fontList->invalidate();
369 }
370
371 int Font::width(const UChar* chs, int slen, int pos, int len, int tabWidth, int xpos) const
372 {
373     // FIXME: Want to define an lroundf for win32.
374 #if __APPLE__
375     return lroundf(floatWidth(chs + pos, slen - pos, 0, len, tabWidth, xpos));
376 #else
377     return floatWidth(chs + pos, slen - pos, 0, len, tabWidth, xpos) + 0.5f;
378 #endif
379 }
380
381 int Font::ascent() const
382 {
383     assert(m_fontList);
384     return m_fontList->primaryFont(fontDescription())->ascent();
385 }
386
387 int Font::descent() const
388 {
389     assert(m_fontList);
390     return m_fontList->primaryFont(fontDescription())->descent();
391 }
392
393 int Font::lineSpacing() const
394 {
395     assert(m_fontList);
396     return m_fontList->primaryFont(fontDescription())->lineSpacing();
397 }
398
399 float Font::xHeight() const
400 {
401     assert(m_fontList);
402     return m_fontList->primaryFont(fontDescription())->xHeight();
403 }
404
405 bool Font::isFixedPitch() const
406 {
407     assert(m_fontList);
408     return m_fontList->isFixedPitch(fontDescription());
409 }
410
411 #if __APPLE__
412 // FIXME: These methods will eventually be cross-platform, but to keep Windows compiling we'll make this Apple-only for now.
413 bool Font::gAlwaysUseComplexPath = false;
414 void Font::setAlwaysUseComplexPath(bool alwaysUse)
415 {
416     gAlwaysUseComplexPath = alwaysUse;
417 }
418
419 bool Font::canUseGlyphCache(const UChar* str, int to) const
420 {
421     if (gAlwaysUseComplexPath)
422         return false;
423     
424     // Start from 0 since drawing and highlighting also measure the characters before run->from
425     for (int i = 0; i < to; i++) {
426         UChar c = str[i];
427         if (c < 0x300)      // U+0300 through U+036F Combining diacritical marks
428             continue;
429         if (c <= 0x36F)
430             return false;
431
432         if (c < 0x0591 || c == 0x05BE)     // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
433             continue;
434         if (c <= 0x05CF)
435             return false;
436
437         if (c < 0x0600)     // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
438             continue;
439         if (c <= 0x1059)
440             return false;
441
442         if (c < 0x1100)     // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
443             continue;
444         if (c <= 0x11FF)
445             return false;
446
447         if (c < 0x1780)     // U+1780 through U+18AF Khmer, Mongolian
448             continue;
449         if (c <= 0x18AF)
450             return false;
451
452         if (c < 0x1900)     // U+1900 through U+194F Limbu (Unicode 4.0)
453             continue;
454         if (c <= 0x194F)
455             return false;
456
457         if (c < 0x20D0)     // U+20D0 through U+20FF Combining marks for symbols
458             continue;
459         if (c <= 0x20FF)
460             return false;
461
462         if (c < 0xFE20)     // U+FE20 through U+FE2F Combining half marks
463             continue;
464         if (c <= 0xFE2F)
465             return false;
466     }
467
468     return true;
469
470 }
471
472 void Font::drawSimpleText(GraphicsContext* context, const IntPoint& point, int tabWidth, int xpos, const UChar* str, int len, int from, int to,
473                           int toAdd, TextDirection dir, bool visuallyOrdered) const
474 {
475     // This glyph buffer holds our glyphs+advances+font data for each glyph.
476     GlyphBuffer glyphBuffer;
477
478     // Our measuring code will generate glyphs and advances for us.
479     float startX;
480     floatWidthForSimpleText(str, len, from, to, tabWidth, xpos, toAdd, dir, visuallyOrdered, 
481                             true, true, 0,
482                             &startX, &glyphBuffer);
483     
484     // We couldn't generate any glyphs for the run.  Give up.
485     if (glyphBuffer.isEmpty())
486         return;
487     
488     // Calculate the starting point of the glyphs to be displayed by adding
489     // all the advances up to the first glyph.
490     startX += point.x();
491     FloatPoint startPoint(startX, point.y());
492
493     // Swap the order of the glyphs if right-to-left.
494     if (dir == RTL)
495         for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
496             glyphBuffer.swap(i, end);
497
498     // Draw each contiguous run of glyphs that use the same font data.
499     const FontData* fontData = glyphBuffer.fontDataAt(0);
500     float nextX = startX;
501     int lastFrom = 0;
502     int nextGlyph = 0;
503     while (nextGlyph < glyphBuffer.size()) {
504         const FontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
505         if (nextFontData != fontData) {
506             drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
507             lastFrom = nextGlyph;
508             fontData = nextFontData;
509             startPoint.setX(nextX);
510         }
511         nextX += glyphBuffer.advanceAt(nextGlyph);
512         nextGlyph++;
513     }
514     drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
515 }
516
517 void Font::drawText(GraphicsContext* context, const IntPoint& point, int tabWidth, int xpos, const UChar* str, int len, int from, int to,
518                     int toAdd, TextDirection d, bool visuallyOrdered) const
519 {
520     if (len == 0)
521         return;
522
523     if (from < 0)
524         from = 0;
525     if (to < 0)
526         to = len;
527
528     if (canUseGlyphCache(str, to))
529         drawSimpleText(context, point, tabWidth, xpos, str, len, from, to, toAdd, d, visuallyOrdered);
530     else
531         drawComplexText(context, point, tabWidth, xpos, str, len, from, to, toAdd, d, visuallyOrdered);
532 }
533
534 float Font::floatWidth(const UChar* str, int slen, int from, int len, int tabWidth, int xpos, bool runRounding) const
535 {
536     int to = from + len;
537     if (canUseGlyphCache(str, to))
538         return floatWidthForSimpleText(str, slen, from, to, tabWidth, xpos, 0, LTR, false, true, runRounding, 0, 0, 0);
539     else
540         return floatWidthForComplexText(str, slen, from, to, tabWidth, xpos, runRounding);
541 }
542
543 float Font::floatWidthForSimpleText(const UChar* str, int len, int from, int to, int tabWidth, int xpos, int toAdd, 
544                                     TextDirection dir, bool visuallyOrdered, 
545                                     bool applyWordRounding, bool applyRunRounding,
546                                     const FontData* substituteFont,
547                                     float* startPosition, GlyphBuffer* glyphBuffer) const
548 {
549     WidthIterator it(this, str, from, dir == LTR ? to : len, len, tabWidth, xpos, toAdd, dir, visuallyOrdered, 
550                      applyWordRounding, applyRunRounding, substituteFont);
551     it.advance(to, glyphBuffer);
552     float runWidth = it.m_runWidthSoFar;
553     if (startPosition) {
554         if (dir == LTR)
555             *startPosition = it.m_widthToStart;
556         else {
557             float finalRoundingWidth = it.m_finalRoundingWidth;
558             it.advance(len);
559             *startPosition = it.m_runWidthSoFar - runWidth + finalRoundingWidth;
560         }
561     }
562     return runWidth;
563 }
564 #endif
565
566 }