diff options
Diffstat (limited to 'WebCore/platform/graphics/Font.cpp')
-rw-r--r-- | WebCore/platform/graphics/Font.cpp | 311 |
1 files changed, 47 insertions, 264 deletions
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp index 82bf3b1..a78d27b 100644 --- a/WebCore/platform/graphics/Font.cpp +++ b/WebCore/platform/graphics/Font.cpp @@ -1,10 +1,8 @@ -/** - * This file is part of the html renderer for KDE. - * +/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2006 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,21 +30,14 @@ #include "FontFallbackList.h" #include "IntPoint.h" #include "GlyphBuffer.h" -#include <wtf/unicode/Unicode.h> +#include "WidthIterator.h" #include <wtf/MathExtras.h> -#if USE(ICU_UNICODE) -#include <unicode/unorm.h> -#endif - using namespace WTF; using namespace Unicode; namespace WebCore { -// According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values -const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8; - const uint8_t Font::gRoundingHackCharacterTable[256] = { 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, 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 /*?*/, @@ -58,250 +49,7 @@ const uint8_t Font::gRoundingHackCharacterTable[256] = { 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 }; -Font::CodePath Font::codePath = Auto; - -struct WidthIterator { - WidthIterator(const Font* font, const TextRun& run); - -#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS - bool -#else - void -#endif - advance(int to, GlyphBuffer* glyphBuffer = 0); - bool advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer = 0); - - const Font* m_font; - - const TextRun& m_run; - int m_end; - - unsigned m_currentCharacter; - float m_runWidthSoFar; - float m_padding; - float m_padPerSpace; - float m_finalRoundingWidth; - -private: - UChar32 normalizeVoicingMarks(int currentCharacter); -}; - -WidthIterator::WidthIterator(const Font* font, const TextRun& run) - : m_font(font) - , m_run(run) - , m_end(run.length()) - , m_currentCharacter(0) - , m_runWidthSoFar(0) - , m_finalRoundingWidth(0) -{ - // If the padding is non-zero, count the number of spaces in the run - // and divide that by the padding for per space addition. - m_padding = m_run.padding(); - if (!m_padding) - m_padPerSpace = 0; - else { - float numSpaces = 0; - for (int i = 0; i < run.length(); i++) - if (Font::treatAsSpace(m_run[i])) - numSpaces++; - - if (numSpaces == 0) - m_padPerSpace = 0; - else - m_padPerSpace = ceilf(m_run.padding() / numSpaces); - } -} - -#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS -#define SIGNAL_ADJUSTED_WIDTHS() adjustedWidths = true -bool WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) -#else -#define SIGNAL_ADJUSTED_WIDTHS() -void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) -#endif -{ - if (offset > m_end) - offset = m_end; - - int currentCharacter = m_currentCharacter; - const UChar* cp = m_run.data(currentCharacter); - - bool rtl = m_run.rtl(); - bool hasExtraSpacing = m_font->letterSpacing() || m_font->wordSpacing() || m_padding; - - float runWidthSoFar = m_runWidthSoFar; - float lastRoundingWidth = m_finalRoundingWidth; - -#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS - bool adjustedWidths = false; -#endif - - while (currentCharacter < offset) { - UChar32 c = *cp; - unsigned clusterLength = 1; - if (c >= 0x3041) { - if (c <= 0x30FE) { - // Deal with Hiragana and Katakana voiced and semi-voiced syllables. - // Normalize into composed form, and then look for glyph with base + combined mark. - // Check above for character range to minimize performance impact. - UChar32 normalized = normalizeVoicingMarks(currentCharacter); - if (normalized) { - c = normalized; - clusterLength = 2; - } - } else if (U16_IS_SURROGATE(c)) { - if (!U16_IS_SURROGATE_LEAD(c)) - break; - - // Do we have a surrogate pair? If so, determine the full Unicode (32 bit) - // code point before glyph lookup. - // Make sure we have another character and it's a low surrogate. - if (currentCharacter + 1 >= m_run.length()) - break; - UChar low = cp[1]; - if (!U16_IS_TRAIL(low)) - break; - c = U16_GET_SUPPLEMENTARY(c, low); - clusterLength = 2; - } - } - - const GlyphData& glyphData = m_font->glyphDataForCharacter(c, rtl); - Glyph glyph = glyphData.glyph; - const SimpleFontData* fontData = glyphData.fontData; - - ASSERT(fontData); - - // Now that we have a glyph and font data, get its width. - float width; - if (c == '\t' && m_run.allowTabs()) { - float tabWidth = m_font->tabWidth(); - width = tabWidth - fmodf(m_run.xPos() + runWidthSoFar, tabWidth); - SIGNAL_ADJUSTED_WIDTHS(); - } else { - width = fontData->widthForGlyph(glyph); -#ifndef ANDROID_NEVER_ROUND_FONT_METRICS - // We special case spaces in two ways when applying word rounding. - // First, we round spaces to an adjusted width in all fonts. - // Second, in fixed-pitch fonts we ensure that all characters that - // match the width of the space character have the same width as the space character. - if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) { - width = fontData->m_adjustedSpaceWidth; - SIGNAL_ADJUSTED_WIDTHS(); - } -#endif - } - - if (hasExtraSpacing && !m_run.spacingDisabled()) { - // Account for letter-spacing. - if (width && m_font->letterSpacing()) { - width += m_font->letterSpacing(); - SIGNAL_ADJUSTED_WIDTHS(); - } - - if (Font::treatAsSpace(c)) { - // Account for padding. WebCore uses space padding to justify text. - // We distribute the specified padding over the available spaces in the run. - if (m_padding) { - // Use left over padding if not evenly divisible by number of spaces. - if (m_padding < m_padPerSpace) { - width += m_padding; - m_padding = 0; - } else { - width += m_padPerSpace; - m_padding -= m_padPerSpace; - } - SIGNAL_ADJUSTED_WIDTHS(); - } - - // Account for word spacing. - // We apply additional space between "words" by adding width to the space character. - if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) { - width += m_font->wordSpacing(); - SIGNAL_ADJUSTED_WIDTHS(); - } - } - } - - // Advance past the character we just dealt with. - cp += clusterLength; - currentCharacter += clusterLength; - - // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters - // followed by a character defined by isRoundingHackCharacter()) are always an integer width. - // We adjust the width of the last character of a "word" to ensure an integer width. - // If we move KHTML to floats we can remove this (and related) hacks. - - float oldWidth = width; - -#ifndef ANDROID_NEVER_ROUND_FONT_METRICS - // Force characters that are used to determine word boundaries for the rounding hack - // to be integer width, so following words will start on an integer boundary. - if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) { - width = ceilf(width); - SIGNAL_ADJUSTED_WIDTHS(); - } - - // Check to see if the next character is a "rounding hack character", if so, adjust - // width so that the total run width will be on an integer boundary. - if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && Font::isRoundingHackCharacter(*cp)) - || (m_run.applyRunRounding() && currentCharacter >= m_end)) { - float totalWidth = runWidthSoFar + width; - width += ceilf(totalWidth) - totalWidth; - SIGNAL_ADJUSTED_WIDTHS(); - } -#endif - - runWidthSoFar += width; - - if (glyphBuffer) - glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width)); - - lastRoundingWidth = width - oldWidth; - } - - m_currentCharacter = currentCharacter; - m_runWidthSoFar = runWidthSoFar; - m_finalRoundingWidth = lastRoundingWidth; - -#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS - return adjustedWidths; -#endif -} - -bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer) -{ - glyphBuffer->clear(); - advance(m_currentCharacter + 1, glyphBuffer); - float w = 0; - for (int i = 0; i < glyphBuffer->size(); ++i) - w += glyphBuffer->advanceAt(i); - width = w; - return !glyphBuffer->isEmpty(); -} - -UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter) -{ - if (currentCharacter + 1 < m_end) { - if (combiningClass(m_run[currentCharacter + 1]) == hiraganaKatakanaVoicingMarksCombiningClass) { -#if USE(ICU_UNICODE) - // Normalize into composed form using 3.2 rules. - UChar normalizedCharacters[2] = { 0, 0 }; - UErrorCode uStatus = U_ZERO_ERROR; - int32_t resultLength = unorm_normalize(m_run.data(currentCharacter), 2, - UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus); - if (resultLength == 1 && uStatus == 0) - return normalizedCharacters[0]; -#elif USE(QT4_UNICODE) - QString tmp(reinterpret_cast<const QChar*>(m_run.data(currentCharacter)), 2); - QString res = tmp.normalized(QString::NormalizationForm_C, QChar::Unicode_3_2); - if (res.length() == 1) - return res.at(0).unicode(); -#endif - } - } - return 0; -} +Font::CodePath Font::s_codePath = Auto; // ============================================================================================ // Font Implementation (Cross-Platform Portion) @@ -327,7 +75,7 @@ Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing) } Font::Font(const FontPlatformData& fontData, bool isPrinterFont) - : m_fontList(new FontFallbackList) + : m_fontList(FontFallbackList::create()) , m_pageZero(0) , m_cachedPrimaryFont(0) , m_letterSpacing(0) @@ -381,7 +129,8 @@ bool Font::operator==(const Font& other) const return first == second && m_fontDescription == other.m_fontDescription && m_letterSpacing == other.m_letterSpacing - && m_wordSpacing == other.m_wordSpacing; + && m_wordSpacing == other.m_wordSpacing + && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0); } const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const @@ -442,9 +191,12 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS return data; GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); - const GlyphData& data = smallCapsNode->page()->glyphDataForCharacter(c); - if (data.fontData) - return data; + const GlyphPage* smallCapsPage = smallCapsNode->page(); + if (smallCapsPage) { + const GlyphData& data = smallCapsPage->glyphDataForCharacter(c); + if (data.fontData) + return data; + } // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that // a font has the lowercase character but the small caps font does not have its uppercase version. @@ -534,7 +286,7 @@ void Font::update(PassRefPtr<FontSelector> fontSelector) const // won't stick around long enough to get you in trouble). Still, this is pretty disgusting, // and could eventually be rectified by using RefPtrs for Fonts themselves. if (!m_fontList) - m_fontList = new FontFallbackList(); + m_fontList = FontFallbackList::create(); m_fontList->invalidate(fontSelector); m_cachedPrimaryFont = 0; m_pageZero = 0; @@ -561,6 +313,11 @@ int Font::lineSpacing() const return primaryFont()->lineSpacing(); } +int Font::lineGap() const +{ + return primaryFont()->lineGap(); +} + float Font::xHeight() const { return primaryFont()->xHeight(); @@ -584,12 +341,17 @@ bool Font::isFixedPitch() const void Font::setCodePath(CodePath p) { - codePath = p; + s_codePath = p; +} + +Font::CodePath Font::codePath() +{ + return s_codePath; } bool Font::canUseGlyphCache(const TextRun& run) const { - switch (codePath) { + switch (s_codePath) { case Auto: break; case Simple: @@ -753,6 +515,20 @@ float Font::floatWidth(const TextRun& run) const return floatWidthForComplexText(run); } +float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const +{ +#if ENABLE(SVG_FONTS) + if (primaryFont()->isSVGFont()) + return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName); +#endif + + charsConsumed = run.length(); + glyphName = ""; + if (canUseGlyphCache(run)) + return floatWidthForSimpleText(run, 0); + return floatWidthForComplexText(run); +} + float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const { WidthIterator it(this, run); @@ -846,6 +622,13 @@ int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool include return offset; } +#if ENABLE(SVG_FONTS) +bool Font::isSVGFont() const +{ + return primaryFont()->isSVGFont(); +} +#endif + FontSelector* Font::fontSelector() const { return m_fontList ? m_fontList->fontSelector() : 0; |