Index: webkit/pending/Font.cpp |
=================================================================== |
--- webkit/pending/Font.cpp (revision 2884) |
+++ webkit/pending/Font.cpp (working copy) |
@@ -1,839 +0,0 @@ |
-/** |
- * 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. |
- * |
- * This library is free software; you can redistribute it and/or |
- * modify it under the terms of the GNU Library General Public |
- * License as published by the Free Software Foundation; either |
- * version 2 of the License, or (at your option) any later version. |
- * |
- * This library is distributed in the hope that it will be useful, |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
- * Library General Public License for more details. |
- * |
- * You should have received a copy of the GNU Library General Public License |
- * along with this library; see the file COPYING.LIB. If not, write to |
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
- * Boston, MA 02110-1301, USA. |
- * |
- */ |
- |
-#include "config.h" |
-#include "Font.h" |
- |
-#include "CharacterNames.h" |
-#include "FloatRect.h" |
-#include "FontCache.h" |
-#include "FontFallbackList.h" |
-#include "IntPoint.h" |
-#include "GlyphBuffer.h" |
-#include <wtf/unicode/Unicode.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 /*?*/, |
- 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, |
- 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, |
- 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, |
- 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, |
- 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, |
- 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); |
- |
- void 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); |
- } |
-} |
- |
-void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) |
-{ |
- 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; |
- |
- 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); |
- } else { |
- width = fontData->widthForGlyph(glyph); |
- // 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; |
- } |
- |
- if (hasExtraSpacing && !m_run.spacingDisabled()) { |
- // Account for letter-spacing. |
- if (width && m_font->letterSpacing()) |
- width += m_font->letterSpacing(); |
- |
- 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; |
- } |
- } |
- |
- // 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(); |
- } |
- } |
- |
- // 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; |
- |
- // 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); |
- |
- // 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; |
- } |
- |
- runWidthSoFar += width; |
- |
- if (glyphBuffer) |
- glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width)); |
- |
- lastRoundingWidth = width - oldWidth; |
- } |
- |
- m_currentCharacter = currentCharacter; |
- m_runWidthSoFar = runWidthSoFar; |
- m_finalRoundingWidth = lastRoundingWidth; |
-} |
- |
-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 Implementation (Cross-Platform Portion) |
-// ============================================================================================ |
- |
-Font::Font() |
- : m_pageZero(0) |
- , m_cachedPrimaryFont(0) |
- , m_letterSpacing(0) |
- , m_wordSpacing(0) |
- , m_isPlatformFont(false) |
-{ |
-} |
- |
-Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing) |
- : m_fontDescription(fd) |
- , m_pageZero(0) |
- , m_cachedPrimaryFont(0) |
- , m_letterSpacing(letterSpacing) |
- , m_wordSpacing(wordSpacing) |
- , m_isPlatformFont(false) |
-{ |
-} |
- |
-Font::Font(const FontPlatformData& fontData, bool isPrinterFont) |
- : m_fontList(FontFallbackList::create()) |
- , m_pageZero(0) |
- , m_cachedPrimaryFont(0) |
- , m_letterSpacing(0) |
- , m_wordSpacing(0) |
- , m_isPlatformFont(true) |
-{ |
- m_fontDescription.setUsePrinterFont(isPrinterFont); |
- m_fontList->setPlatformFont(fontData); |
-} |
- |
-Font::Font(const Font& other) |
- : m_fontDescription(other.m_fontDescription) |
- , m_fontList(other.m_fontList) |
- , m_pages(other.m_pages) |
- , m_pageZero(other.m_pageZero) |
- , m_cachedPrimaryFont(other.m_cachedPrimaryFont) |
- , m_letterSpacing(other.m_letterSpacing) |
- , m_wordSpacing(other.m_wordSpacing) |
- , m_isPlatformFont(other.m_isPlatformFont) |
-{ |
-} |
- |
-Font& Font::operator=(const Font& other) |
-{ |
- m_fontDescription = other.m_fontDescription; |
- m_fontList = other.m_fontList; |
- m_pages = other.m_pages; |
- m_pageZero = other.m_pageZero; |
- m_cachedPrimaryFont = other.m_cachedPrimaryFont; |
- m_letterSpacing = other.m_letterSpacing; |
- m_wordSpacing = other.m_wordSpacing; |
- m_isPlatformFont = other.m_isPlatformFont; |
- return *this; |
-} |
- |
-Font::~Font() |
-{ |
-} |
- |
-bool Font::operator==(const Font& other) const |
-{ |
- // Our FontData don't have to be checked, since checking the font description will be fine. |
- // FIXME: This does not work if the font was made with the FontPlatformData constructor. |
- if ((m_fontList && m_fontList->loadingCustomFonts()) || |
- (other.m_fontList && other.m_fontList->loadingCustomFonts())) |
- return false; |
- |
- FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0; |
- FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0; |
- |
- return first == second |
- && m_fontDescription == other.m_fontDescription |
- && m_letterSpacing == other.m_letterSpacing |
- && 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 |
-{ |
- bool useSmallCapsFont = forceSmallCaps; |
- if (m_fontDescription.smallCaps()) { |
- UChar32 upperC = Unicode::toUpper(c); |
- if (upperC != c) { |
- c = upperC; |
- useSmallCapsFont = true; |
- } |
- } |
- |
- if (mirror) |
- c = mirroredChar(c); |
- |
- unsigned pageNumber = (c / GlyphPage::size); |
- |
- GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero; |
- if (!node) { |
- node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); |
- if (pageNumber) |
- m_pages.set(pageNumber, node); |
- else |
- m_pageZero = node; |
- } |
- |
- GlyphPage* page; |
- if (!useSmallCapsFont) { |
- // Fastest loop, for the common case (not small caps). |
- while (true) { |
- page = node->page(); |
- if (page) { |
- const GlyphData& data = page->glyphDataForCharacter(c); |
- if (data.fontData) |
- return data; |
- if (node->isSystemFallback()) |
- break; |
- } |
- |
- // Proceed with the fallback list. |
- node = node->getChild(fontDataAt(node->level()), pageNumber); |
- if (pageNumber) |
- m_pages.set(pageNumber, node); |
- else |
- m_pageZero = node; |
- } |
- } else { |
- while (true) { |
- page = node->page(); |
- if (page) { |
- const GlyphData& data = page->glyphDataForCharacter(c); |
- if (data.fontData) { |
- // The smallCapsFontData function should not normally return 0. |
- // But if it does, we will just render the capital letter big. |
- const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription); |
- if (!smallCapsFontData) |
- return data; |
- |
- GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); |
- 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. |
- return smallCapsFontData->missingGlyphData(); |
- } |
- |
- if (node->isSystemFallback()) |
- break; |
- } |
- |
- // Proceed with the fallback list. |
- node = node->getChild(fontDataAt(node->level()), pageNumber); |
- if (pageNumber) |
- m_pages.set(pageNumber, node); |
- else |
- m_pageZero = node; |
- } |
- } |
- |
- ASSERT(page); |
- ASSERT(node->isSystemFallback()); |
- |
- // System fallback is character-dependent. When we get here, we |
- // know that the character in question isn't in the system fallback |
- // font's glyph page. Try to lazily create it here. |
- UChar codeUnits[2]; |
- int codeUnitsLength; |
- if (c <= 0xFFFF) { |
- UChar c16 = c; |
- if (Font::treatAsSpace(c16)) |
- codeUnits[0] = ' '; |
- else if (Font::treatAsZeroWidthSpace(c16)) |
- codeUnits[0] = zeroWidthSpace; |
- else |
- codeUnits[0] = c16; |
- codeUnitsLength = 1; |
- } else { |
- codeUnits[0] = U16_LEAD(c); |
- codeUnits[1] = U16_TRAIL(c); |
- codeUnitsLength = 2; |
- } |
- const SimpleFontData* characterFontData = FontCache::getFontDataForCharacters(*this, codeUnits, codeUnitsLength); |
- if (useSmallCapsFont) |
- characterFontData = characterFontData->smallCapsFontData(m_fontDescription); |
- if (characterFontData) { |
- // Got the fallback glyph and font. |
- GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); |
- const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); |
- // Cache it so we don't have to do system fallback again next time. |
- if (!useSmallCapsFont) |
- page->setGlyphDataForCharacter(c, data.glyph, data.fontData); |
- return data; |
- } |
- |
- // Even system fallback can fail; use the missing glyph in that case. |
- // FIXME: It would be nicer to use the missing glyph from the last resort font instead. |
- const GlyphData& data = primaryFont()->missingGlyphData(); |
- if (!useSmallCapsFont) |
- page->setGlyphDataForCharacter(c, data.glyph, data.fontData); |
- return data; |
-} |
- |
-void Font::cachePrimaryFont() const |
-{ |
- ASSERT(m_fontList); |
- ASSERT(!m_cachedPrimaryFont); |
- m_cachedPrimaryFont = m_fontList->primaryFont(this)->fontDataForCharacter(' '); |
-} |
- |
-const FontData* Font::fontDataAt(unsigned index) const |
-{ |
- ASSERT(m_fontList); |
- return m_fontList->fontDataAt(this, index); |
-} |
- |
-const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const |
-{ |
- ASSERT(m_fontList); |
- return m_fontList->fontDataForCharacters(this, characters, length); |
-} |
- |
-void Font::update(PassRefPtr<FontSelector> fontSelector) const |
-{ |
- // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up |
- // being reasonably safe (because inherited fonts in the render tree pick up the new |
- // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and |
- // 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 = FontFallbackList::create(); |
- m_fontList->invalidate(fontSelector); |
- m_cachedPrimaryFont = 0; |
- m_pageZero = 0; |
- m_pages.clear(); |
-} |
- |
-int Font::width(const TextRun& run) const |
-{ |
- return lroundf(floatWidth(run)); |
-} |
- |
-int Font::ascent() const |
-{ |
- return primaryFont()->ascent(); |
-} |
- |
-int Font::descent() const |
-{ |
- return primaryFont()->descent(); |
-} |
- |
-int Font::lineSpacing() const |
-{ |
- return primaryFont()->lineSpacing(); |
-} |
- |
-int Font::lineGap() const |
-{ |
- return primaryFont()->lineGap(); |
-} |
- |
-float Font::xHeight() const |
-{ |
- return primaryFont()->xHeight(); |
-} |
- |
-unsigned Font::unitsPerEm() const |
-{ |
- return primaryFont()->unitsPerEm(); |
-} |
- |
-int Font::spaceWidth() const |
-{ |
- return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing); |
-} |
- |
-bool Font::isFixedPitch() const |
-{ |
- ASSERT(m_fontList); |
- return m_fontList->isFixedPitch(this); |
-} |
- |
-void Font::setCodePath(CodePath p) |
-{ |
- codePath = p; |
-} |
- |
-bool Font::canUseGlyphCache(const TextRun& run) const |
-{ |
- switch (codePath) { |
- case Auto: |
- break; |
- case Simple: |
- return true; |
- case Complex: |
- return false; |
- } |
- |
- // Start from 0 since drawing and highlighting also measure the characters before run->from |
- for (int i = 0; i < run.length(); i++) { |
- const UChar c = run[i]; |
- if (c < 0x300) // U+0300 through U+036F Combining diacritical marks |
- continue; |
- if (c <= 0x36F) |
- return false; |
- |
- if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha |
- continue; |
- if (c <= 0x05CF) |
- return false; |
- |
- 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 |
- continue; |
- if (c <= 0x1059) |
- return false; |
- |
- 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) |
- continue; |
- if (c <= 0x11FF) |
- return false; |
- |
- if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian |
- continue; |
- if (c <= 0x18AF) |
- return false; |
- |
- if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0) |
- continue; |
- if (c <= 0x194F) |
- return false; |
- |
- if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols |
- continue; |
- if (c <= 0x20FF) |
- return false; |
- |
- if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks |
- continue; |
- if (c <= 0xFE2F) |
- return false; |
- } |
- |
- return true; |
- |
-} |
- |
-void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const |
-{ |
- // This glyph buffer holds our glyphs+advances+font data for each glyph. |
- GlyphBuffer glyphBuffer; |
- |
- float startX = point.x(); |
- WidthIterator it(this, run); |
- it.advance(from); |
- float beforeWidth = it.m_runWidthSoFar; |
- it.advance(to, &glyphBuffer); |
- |
- // We couldn't generate any glyphs for the run. Give up. |
- if (glyphBuffer.isEmpty()) |
- return; |
- |
- float afterWidth = it.m_runWidthSoFar; |
- |
- if (run.rtl()) { |
- float finalRoundingWidth = it.m_finalRoundingWidth; |
- it.advance(run.length()); |
- startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth; |
- } else |
- startX += beforeWidth; |
- |
- // Swap the order of the glyphs if right-to-left. |
- if (run.rtl()) |
- for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) |
- glyphBuffer.swap(i, end); |
- |
- // Calculate the starting point of the glyphs to be displayed by adding |
- // all the advances up to the first glyph. |
- FloatPoint startPoint(startX, point.y()); |
- drawGlyphBuffer(context, glyphBuffer, run, startPoint); |
-} |
- |
-void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, |
- const TextRun& run, const FloatPoint& point) const |
-{ |
- // Draw each contiguous run of glyphs that use the same font data. |
- const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); |
- FloatSize offset = glyphBuffer.offsetAt(0); |
- FloatPoint startPoint(point); |
- float nextX = startPoint.x(); |
- int lastFrom = 0; |
- int nextGlyph = 0; |
- while (nextGlyph < glyphBuffer.size()) { |
- const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); |
- FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); |
- if (nextFontData != fontData || nextOffset != offset) { |
- drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); |
- |
- lastFrom = nextGlyph; |
- fontData = nextFontData; |
- offset = nextOffset; |
- startPoint.setX(nextX); |
- } |
- nextX += glyphBuffer.advanceAt(nextGlyph); |
- nextGlyph++; |
- } |
- |
- drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); |
-} |
- |
-void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const |
-{ |
- // Don't draw anything while we are using custom fonts that are in the process of loading. |
- if (m_fontList && m_fontList->loadingCustomFonts()) |
- return; |
- |
- to = (to == -1 ? run.length() : to); |
- |
-#if ENABLE(SVG_FONTS) |
- if (primaryFont()->isSVGFont()) { |
- drawTextUsingSVGFont(context, run, point, from, to); |
- return; |
- } |
-#endif |
- |
- if (canUseGlyphCache(run)) |
- drawSimpleText(context, run, point, from, to); |
- else |
- drawComplexText(context, run, point, from, to); |
-} |
- |
-float Font::floatWidth(const TextRun& run) const |
-{ |
-#if ENABLE(SVG_FONTS) |
- if (primaryFont()->isSVGFont()) |
- return floatWidthUsingSVGFont(run); |
-#endif |
- |
- if (canUseGlyphCache(run)) |
- return floatWidthForSimpleText(run, 0); |
- 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); |
- it.advance(run.length(), glyphBuffer); |
- return it.m_runWidthSoFar; |
-} |
- |
-FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const |
-{ |
-#if ENABLE(SVG_FONTS) |
- if (primaryFont()->isSVGFont()) |
- return selectionRectForTextUsingSVGFont(run, point, h, from, to); |
-#endif |
- |
- to = (to == -1 ? run.length() : to); |
- if (canUseGlyphCache(run)) |
- return selectionRectForSimpleText(run, point, h, from, to); |
- return selectionRectForComplexText(run, point, h, from, to); |
-} |
- |
-FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const |
-{ |
- WidthIterator it(this, run); |
- it.advance(from); |
- float beforeWidth = it.m_runWidthSoFar; |
- it.advance(to); |
- float afterWidth = it.m_runWidthSoFar; |
- |
- // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning |
- if (run.rtl()) { |
- it.advance(run.length()); |
- float totalWidth = it.m_runWidthSoFar; |
- return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h); |
- } else { |
- return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); |
- } |
-} |
- |
-int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const |
-{ |
-#if ENABLE(SVG_FONTS) |
- if (primaryFont()->isSVGFont()) |
- return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs); |
-#endif |
- |
- if (canUseGlyphCache(run)) |
- return offsetForPositionForSimpleText(run, x, includePartialGlyphs); |
- return offsetForPositionForComplexText(run, x, includePartialGlyphs); |
-} |
- |
-int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const |
-{ |
- float delta = (float)x; |
- |
- WidthIterator it(this, run); |
- GlyphBuffer localGlyphBuffer; |
- unsigned offset; |
- if (run.rtl()) { |
- delta -= floatWidthForSimpleText(run, 0); |
- while (1) { |
- offset = it.m_currentCharacter; |
- float w; |
- if (!it.advanceOneCharacter(w, &localGlyphBuffer)) |
- break; |
- delta += w; |
- if (includePartialGlyphs) { |
- if (delta - w / 2 >= 0) |
- break; |
- } else { |
- if (delta >= 0) |
- break; |
- } |
- } |
- } else { |
- while (1) { |
- offset = it.m_currentCharacter; |
- float w; |
- if (!it.advanceOneCharacter(w, &localGlyphBuffer)) |
- break; |
- delta -= w; |
- if (includePartialGlyphs) { |
- if (delta + w / 2 <= 0) |
- break; |
- } else { |
- if (delta <= 0) |
- break; |
- } |
- } |
- } |
- |
- 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; |
-} |
- |
-} |