2 * This file is part of the html renderer for KDE.
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.
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.
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.
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., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
29 #include "CharacterNames.h"
30 #include "FloatRect.h"
31 #include "FontCache.h"
32 #include "FontFallbackList.h"
34 #include "GlyphBuffer.h"
35 #include <wtf/unicode/Unicode.h>
36 #include <wtf/MathExtras.h>
39 #include <unicode/unorm.h>
43 using namespace Unicode;
47 // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values
48 const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8;
50 const uint8_t Font::gRoundingHackCharacterTable[256] = {
51 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,
52 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 /*?*/,
53 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,
54 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,
55 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,
56 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,
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
61 Font::CodePath Font::codePath = Auto;
63 struct WidthIterator {
64 WidthIterator(const Font* font, const TextRun& run);
66 void advance(int to, GlyphBuffer* glyphBuffer = 0);
67 bool advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer = 0);
74 unsigned m_currentCharacter;
75 float m_runWidthSoFar;
78 float m_finalRoundingWidth;
81 UChar32 normalizeVoicingMarks(int currentCharacter);
84 WidthIterator::WidthIterator(const Font* font, const TextRun& run)
88 , m_currentCharacter(0)
90 , m_finalRoundingWidth(0)
92 // If the padding is non-zero, count the number of spaces in the run
93 // and divide that by the padding for per space addition.
94 m_padding = m_run.padding();
99 for (int i = 0; i < run.length(); i++)
100 if (Font::treatAsSpace(m_run[i]))
106 m_padPerSpace = ceilf(m_run.padding() / numSpaces);
110 void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
115 int currentCharacter = m_currentCharacter;
116 const UChar* cp = m_run.data(currentCharacter);
118 bool rtl = m_run.rtl();
119 bool hasExtraSpacing = m_font->letterSpacing() || m_font->wordSpacing() || m_padding;
121 float runWidthSoFar = m_runWidthSoFar;
122 float lastRoundingWidth = m_finalRoundingWidth;
124 while (currentCharacter < offset) {
126 unsigned clusterLength = 1;
129 // Deal with Hiragana and Katakana voiced and semi-voiced syllables.
130 // Normalize into composed form, and then look for glyph with base + combined mark.
131 // Check above for character range to minimize performance impact.
132 UChar32 normalized = normalizeVoicingMarks(currentCharacter);
137 } else if (U16_IS_SURROGATE(c)) {
138 if (!U16_IS_SURROGATE_LEAD(c))
141 // Do we have a surrogate pair? If so, determine the full Unicode (32 bit)
142 // code point before glyph lookup.
143 // Make sure we have another character and it's a low surrogate.
144 if (currentCharacter + 1 >= m_run.length())
147 if (!U16_IS_TRAIL(low))
149 c = U16_GET_SUPPLEMENTARY(c, low);
154 const GlyphData& glyphData = m_font->glyphDataForCharacter(c, rtl);
155 Glyph glyph = glyphData.glyph;
156 const FontData* fontData = glyphData.fontData;
160 // Now that we have a glyph and font data, get its width.
162 if (c == '\t' && m_run.allowTabs()) {
163 float tabWidth = m_font->tabWidth();
164 width = tabWidth - fmodf(m_run.xPos() + runWidthSoFar, tabWidth);
166 width = fontData->widthForGlyph(glyph);
167 // We special case spaces in two ways when applying word rounding.
168 // First, we round spaces to an adjusted width in all fonts.
169 // Second, in fixed-pitch fonts we ensure that all characters that
170 // match the width of the space character have the same width as the space character.
171 if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding())
172 width = fontData->m_adjustedSpaceWidth;
175 if (hasExtraSpacing && !m_run.spacingDisabled()) {
176 // Account for letter-spacing.
177 if (width && m_font->letterSpacing())
178 width += m_font->letterSpacing();
180 if (Font::treatAsSpace(c)) {
181 // Account for padding. WebCore uses space padding to justify text.
182 // We distribute the specified padding over the available spaces in the run.
184 // Use left over padding if not evenly divisible by number of spaces.
185 if (m_padding < m_padPerSpace) {
189 width += m_padPerSpace;
190 m_padding -= m_padPerSpace;
194 // Account for word spacing.
195 // We apply additional space between "words" by adding width to the space character.
196 if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing())
197 width += m_font->wordSpacing();
201 // Advance past the character we just dealt with.
203 currentCharacter += clusterLength;
205 // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters
206 // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
207 // We adjust the width of the last character of a "word" to ensure an integer width.
208 // If we move KHTML to floats we can remove this (and related) hacks.
210 float oldWidth = width;
212 // Force characters that are used to determine word boundaries for the rounding hack
213 // to be integer width, so following words will start on an integer boundary.
214 if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c))
215 width = ceilf(width);
217 // Check to see if the next character is a "rounding hack character", if so, adjust
218 // width so that the total run width will be on an integer boundary.
219 if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && Font::isRoundingHackCharacter(*cp))
220 || (m_run.applyRunRounding() && currentCharacter >= m_end)) {
221 float totalWidth = runWidthSoFar + width;
222 width += ceilf(totalWidth) - totalWidth;
225 runWidthSoFar += width;
228 glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width));
230 lastRoundingWidth = width - oldWidth;
233 m_currentCharacter = currentCharacter;
234 m_runWidthSoFar = runWidthSoFar;
235 m_finalRoundingWidth = lastRoundingWidth;
238 bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer)
240 glyphBuffer->clear();
241 advance(m_currentCharacter + 1, glyphBuffer);
243 for (int i = 0; i < glyphBuffer->size(); ++i)
244 w += glyphBuffer->advanceAt(i);
246 return !glyphBuffer->isEmpty();
249 UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter)
251 if (currentCharacter + 1 < m_end) {
252 if (combiningClass(m_run[currentCharacter + 1]) == hiraganaKatakanaVoicingMarksCombiningClass) {
254 // Normalize into composed form using 3.2 rules.
255 UChar normalizedCharacters[2] = { 0, 0 };
256 UErrorCode uStatus = U_ZERO_ERROR;
257 int32_t resultLength = unorm_normalize(m_run.data(currentCharacter), 2,
258 UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus);
259 if (resultLength == 1 && uStatus == 0)
260 return normalizedCharacters[0];
261 #elif USE(QT4_UNICODE)
262 QString tmp(reinterpret_cast<const QChar*>(m_run.data(currentCharacter)), 2);
263 QString res = tmp.normalized(QString::NormalizationForm_C, QChar::Unicode_3_2);
264 if (res.length() == 1)
265 return res.at(0).unicode();
272 // ============================================================================================
273 // Font Implementation (Cross-Platform Portion)
274 // ============================================================================================
280 , m_isPlatformFont(false)
284 Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
285 : m_fontDescription(fd)
287 , m_letterSpacing(letterSpacing)
288 , m_wordSpacing(wordSpacing)
289 , m_isPlatformFont(false)
293 Font::Font(const FontPlatformData& fontData, bool isPrinterFont)
294 : m_fontList(new FontFallbackList)
298 , m_isPlatformFont(true)
300 m_fontDescription.setUsePrinterFont(isPrinterFont);
301 m_fontList->setPlatformFont(fontData);
304 Font::Font(const Font& other)
305 : m_fontDescription(other.m_fontDescription)
306 , m_fontList(other.m_fontList)
307 , m_pages(other.m_pages)
308 , m_pageZero(other.m_pageZero)
309 , m_letterSpacing(other.m_letterSpacing)
310 , m_wordSpacing(other.m_wordSpacing)
311 , m_isPlatformFont(other.m_isPlatformFont)
315 Font& Font::operator=(const Font& other)
317 m_fontDescription = other.m_fontDescription;
318 m_fontList = other.m_fontList;
319 m_pages = other.m_pages;
320 m_pageZero = other.m_pageZero;
321 m_letterSpacing = other.m_letterSpacing;
322 m_wordSpacing = other.m_wordSpacing;
323 m_isPlatformFont = other.m_isPlatformFont;
331 bool Font::operator==(const Font& other) const
333 // Our FontData don't have to be checked, since checking the font description will be fine.
334 // FIXME: This does not work if the font was made with the FontPlatformData constructor.
335 if ((m_fontList && m_fontList->loadingCustomFonts()) ||
336 (other.m_fontList && other.m_fontList->loadingCustomFonts()))
339 FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
340 FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
342 return first == second
343 && m_fontDescription == other.m_fontDescription
344 && m_letterSpacing == other.m_letterSpacing
345 && m_wordSpacing == other.m_wordSpacing;
348 const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const
350 bool useSmallCapsFont = forceSmallCaps;
351 if (m_fontDescription.smallCaps()) {
352 UChar32 upperC = Unicode::toUpper(c);
355 useSmallCapsFont = true;
362 unsigned pageNumber = (c / GlyphPage::size);
364 GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero;
366 node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
368 m_pages.set(pageNumber, node);
374 if (!useSmallCapsFont) {
375 // Fastest loop, for the common case (not small caps).
379 const GlyphData& data = page->glyphDataForCharacter(c);
382 if (node->isSystemFallback())
386 // Proceed with the fallback list.
387 node = node->getChild(fontDataAt(node->level()), pageNumber);
389 m_pages.set(pageNumber, node);
397 const GlyphData& data = page->glyphDataForCharacter(c);
399 // The smallCapsFontData function should not normally return 0.
400 // But if it does, we will just render the capital letter big.
401 const FontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription);
402 if (!smallCapsFontData)
405 GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber);
406 const GlyphData& data = smallCapsNode->page()->glyphDataForCharacter(c);
410 // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that
411 // a font has the lowercase character but the small caps font does not have its uppercase version.
412 return smallCapsFontData->missingGlyphData();
415 if (node->isSystemFallback())
419 // Proceed with the fallback list.
420 node = node->getChild(fontDataAt(node->level()), pageNumber);
422 m_pages.set(pageNumber, node);
429 ASSERT(node->isSystemFallback());
431 // System fallback is character-dependent. When we get here, we
432 // know that the character in question isn't in the system fallback
433 // font's glyph page. Try to lazily create it here.
438 if (Font::treatAsSpace(c16))
440 else if (Font::treatAsZeroWidthSpace(c16))
441 codeUnits[0] = zeroWidthSpace;
446 codeUnits[0] = U16_LEAD(c);
447 codeUnits[1] = U16_TRAIL(c);
450 const FontData* characterFontData = FontCache::getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
451 if (useSmallCapsFont)
452 characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
453 if (characterFontData) {
454 // Got the fallback glyph and font.
455 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
456 const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
457 // Cache it so we don't have to do system fallback again next time.
458 if (!useSmallCapsFont)
459 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
463 // Even system fallback can fail; use the missing glyph in that case.
464 // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
465 const GlyphData& data = primaryFont()->missingGlyphData();
466 if (!useSmallCapsFont)
467 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
471 const FontData* Font::primaryFont() const
474 return m_fontList->primaryFont(this);
477 const FontData* Font::fontDataAt(unsigned index) const
480 return m_fontList->fontDataAt(this, index);
483 const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const
486 return m_fontList->fontDataForCharacters(this, characters, length);
489 void Font::update(PassRefPtr<FontSelector> fontSelector) const
491 // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
492 // being reasonably safe (because inherited fonts in the render tree pick up the new
493 // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
494 // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
495 // and could eventually be rectified by using RefPtrs for Fonts themselves.
497 m_fontList = new FontFallbackList();
498 m_fontList->invalidate(fontSelector);
503 int Font::width(const TextRun& run) const
505 return lroundf(floatWidth(run));
508 int Font::ascent() const
510 return primaryFont()->ascent();
513 int Font::descent() const
515 return primaryFont()->descent();
518 int Font::lineSpacing() const
520 return primaryFont()->lineSpacing();
523 float Font::xHeight() const
525 return primaryFont()->xHeight();
528 unsigned Font::unitsPerEm() const
530 return primaryFont()->unitsPerEm();
533 int Font::spaceWidth() const
535 return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing);
538 bool Font::isFixedPitch() const
541 return m_fontList->isFixedPitch(this);
544 void Font::setCodePath(CodePath p)
549 bool Font::canUseGlyphCache(const TextRun& run) const
560 // Start from 0 since drawing and highlighting also measure the characters before run->from
561 for (int i = 0; i < run.length(); i++) {
562 const UChar c = run[i];
563 if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
568 if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
573 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
578 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)
583 if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
588 if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
593 if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
598 if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
608 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
610 // This glyph buffer holds our glyphs+advances+font data for each glyph.
611 GlyphBuffer glyphBuffer;
613 float startX = point.x();
614 WidthIterator it(this, run);
616 float beforeWidth = it.m_runWidthSoFar;
617 it.advance(to, &glyphBuffer);
619 // We couldn't generate any glyphs for the run. Give up.
620 if (glyphBuffer.isEmpty())
623 float afterWidth = it.m_runWidthSoFar;
626 float finalRoundingWidth = it.m_finalRoundingWidth;
627 it.advance(run.length());
628 startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
630 startX += beforeWidth;
632 // Swap the order of the glyphs if right-to-left.
634 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
635 glyphBuffer.swap(i, end);
637 // Calculate the starting point of the glyphs to be displayed by adding
638 // all the advances up to the first glyph.
639 FloatPoint startPoint(startX, point.y());
640 drawGlyphBuffer(context, glyphBuffer, run, startPoint);
643 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer,
644 const TextRun& run, const FloatPoint& point) const
646 // Draw each contiguous run of glyphs that use the same font data.
647 const FontData* fontData = glyphBuffer.fontDataAt(0);
648 FloatSize offset = glyphBuffer.offsetAt(0);
649 FloatPoint startPoint(point);
650 float nextX = startPoint.x();
653 while (nextGlyph < glyphBuffer.size()) {
654 const FontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
655 FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
656 if (nextFontData != fontData || nextOffset != offset) {
657 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
658 lastFrom = nextGlyph;
659 fontData = nextFontData;
661 startPoint.setX(nextX);
663 nextX += glyphBuffer.advanceAt(nextGlyph);
666 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
669 void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
671 // Don't draw anything while we are using custom fonts that are in the process of loading.
672 if (m_fontList && m_fontList->loadingCustomFonts())
675 to = (to == -1 ? run.length() : to);
676 if (canUseGlyphCache(run))
677 drawSimpleText(context, run, point, from, to);
679 drawComplexText(context, run, point, from, to);
682 float Font::floatWidth(const TextRun& run) const
684 if (canUseGlyphCache(run))
685 return floatWidthForSimpleText(run, 0);
686 return floatWidthForComplexText(run);
689 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const
691 WidthIterator it(this, run);
692 it.advance(run.length(), glyphBuffer);
693 return it.m_runWidthSoFar;
696 FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
698 to = (to == -1 ? run.length() : to);
699 if (canUseGlyphCache(run))
700 return selectionRectForSimpleText(run, point, h, from, to);
701 return selectionRectForComplexText(run, point, h, from, to);
704 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
706 WidthIterator it(this, run);
708 float beforeWidth = it.m_runWidthSoFar;
710 float afterWidth = it.m_runWidthSoFar;
712 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
714 it.advance(run.length());
715 float totalWidth = it.m_runWidthSoFar;
716 return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
718 return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
722 int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const
724 if (canUseGlyphCache(run))
725 return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
726 return offsetForPositionForComplexText(run, x, includePartialGlyphs);
729 int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
731 float delta = (float)x;
733 WidthIterator it(this, run);
734 GlyphBuffer localGlyphBuffer;
737 delta -= floatWidthForSimpleText(run, 0);
739 offset = it.m_currentCharacter;
741 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
744 if (includePartialGlyphs) {
745 if (delta - w / 2 >= 0)
754 offset = it.m_currentCharacter;
756 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
759 if (includePartialGlyphs) {
760 if (delta + w / 2 <= 0)