summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/Font.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/Font.cpp')
-rw-r--r--Source/WebCore/platform/graphics/Font.cpp474
1 files changed, 474 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/Font.cpp b/Source/WebCore/platform/graphics/Font.cpp
new file mode 100644
index 0000000..887e21d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Font.cpp
@@ -0,0 +1,474 @@
+/*
+ * 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, 2010 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
+ * 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 "FloatRect.h"
+#include "FontCache.h"
+#include "FontTranscoder.h"
+#include "IntPoint.h"
+#include "GlyphBuffer.h"
+#include "WidthIterator.h"
+#include <wtf/MathExtras.h>
+#include <wtf/UnusedParam.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+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::s_codePath = Auto;
+
+// ============================================================================================
+// Font Implementation (Cross-Platform Portion)
+// ============================================================================================
+
+Font::Font()
+ : m_letterSpacing(0)
+ , m_wordSpacing(0)
+ , m_isPlatformFont(false)
+ , m_needsTranscoding(false)
+{
+}
+
+Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
+ : m_fontDescription(fd)
+ , m_letterSpacing(letterSpacing)
+ , m_wordSpacing(wordSpacing)
+ , m_isPlatformFont(false)
+ , m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
+{
+}
+
+Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
+ : m_fontList(FontFallbackList::create())
+ , m_letterSpacing(0)
+ , m_wordSpacing(0)
+ , m_isPlatformFont(true)
+{
+ m_fontDescription.setUsePrinterFont(isPrinterFont);
+ m_fontDescription.setFontSmoothing(fontSmoothingMode);
+ m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
+ m_fontList->setPlatformFont(fontData);
+}
+
+Font::Font(const Font& other)
+ : m_fontDescription(other.m_fontDescription)
+ , m_fontList(other.m_fontList)
+ , m_letterSpacing(other.m_letterSpacing)
+ , m_wordSpacing(other.m_wordSpacing)
+ , m_isPlatformFont(other.m_isPlatformFont)
+ , m_needsTranscoding(fontTranscoder().needsTranscoding(other.m_fontDescription))
+{
+}
+
+Font& Font::operator=(const Font& other)
+{
+ m_fontDescription = other.m_fontDescription;
+ m_fontList = other.m_fontList;
+ m_letterSpacing = other.m_letterSpacing;
+ m_wordSpacing = other.m_wordSpacing;
+ m_isPlatformFont = other.m_isPlatformFont;
+ m_needsTranscoding = other.m_needsTranscoding;
+ return *this;
+}
+
+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 (loadingCustomFonts() || other.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);
+}
+
+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);
+}
+
+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 (loadingCustomFonts())
+ return;
+
+ to = (to == -1 ? run.length() : to);
+
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont()) {
+ drawTextUsingSVGFont(context, run, point, from, to);
+ return;
+ }
+#endif
+
+ if (codePath(run) != Complex)
+ return drawSimpleText(context, run, point, from, to);
+
+ return drawComplexText(context, run, point, from, to);
+}
+
+void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
+{
+ if (loadingCustomFonts())
+ return;
+
+ if (to < 0)
+ to = run.length();
+
+#if ENABLE(SVG_FONTS)
+ // FIXME: Implement for SVG fonts.
+ if (primaryFont()->isSVGFont())
+ return;
+#endif
+
+ if (codePath(run) != Complex)
+ drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
+ else
+ drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
+}
+
+float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return floatWidthUsingSVGFont(run);
+#endif
+
+ CodePath codePathToUse = codePath(run);
+ if (codePathToUse != Complex) {
+ // If the complex text implementation cannot return fallback fonts, avoid
+ // returning them for simple text as well.
+ static bool returnFallbackFonts = canReturnFallbackFontsForComplexText();
+ return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow ? glyphOverflow : 0);
+ }
+
+ return floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
+}
+
+float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
+{
+#if !ENABLE(SVG_FONTS)
+ UNUSED_PARAM(extraCharsAvailable);
+#else
+ if (primaryFont()->isSVGFont())
+ return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName);
+#endif
+
+ charsConsumed = run.length();
+ glyphName = "";
+
+ if (codePath(run) != Complex)
+ return floatWidthForSimpleText(run, 0);
+
+ return floatWidthForComplexText(run);
+}
+
+FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& 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 (codePath(run) != Complex)
+ return selectionRectForSimpleText(run, point, h, from, to);
+
+ return selectionRectForComplexText(run, point, h, from, to);
+}
+
+int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
+#endif
+
+ if (codePath(run) != Complex)
+ return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
+
+ return offsetForPositionForComplexText(run, x, includePartialGlyphs);
+}
+
+#if ENABLE(SVG_FONTS)
+bool Font::isSVGFont() const
+{
+ return primaryFont()->isSVGFont();
+}
+#endif
+
+String Font::normalizeSpaces(const String& string)
+{
+ const UChar* characters = string.characters();
+ unsigned length = string.length();
+ Vector<UChar, 256> buffer(length);
+ bool didReplacement = false;
+
+ for (unsigned i = 0; i < length; ++i) {
+ UChar originalCharacter = characters[i];
+ buffer[i] = normalizeSpaces(originalCharacter);
+ if (buffer[i] != originalCharacter)
+ didReplacement = true;
+ }
+
+ return didReplacement ? String(buffer.data(), length) : string;
+}
+
+static bool shouldUseFontSmoothing = true;
+
+void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
+{
+ ASSERT(isMainThread());
+ shouldUseFontSmoothing = shouldUseSmoothing;
+}
+
+bool Font::shouldUseSmoothing()
+{
+ return shouldUseFontSmoothing;
+}
+
+void Font::setCodePath(CodePath p)
+{
+ s_codePath = p;
+}
+
+Font::CodePath Font::codePath()
+{
+ return s_codePath;
+}
+
+Font::CodePath Font::codePath(const TextRun& run) const
+{
+ if (s_codePath != Auto)
+ return s_codePath;
+
+#if PLATFORM(QT)
+ if (run.padding() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
+ return Complex;
+#endif
+
+ CodePath result = Simple;
+
+ // 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 Complex;
+
+ 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 Complex;
+
+ 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 Complex;
+
+ 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 Complex;
+
+ if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
+ continue;
+ if (c <= 0x18AF)
+ return Complex;
+
+ if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
+ continue;
+ if (c <= 0x194F)
+ return Complex;
+
+ if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics
+ continue;
+ if (c <= 0x2000) {
+ result = SimpleWithGlyphOverflow;
+ continue;
+ }
+
+ if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
+ continue;
+ if (c <= 0x20FF)
+ return Complex;
+
+ if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
+ continue;
+ if (c <= 0xFE2F)
+ return Complex;
+ }
+
+ if (typesettingFeatures())
+ return Complex;
+
+ return result;
+}
+
+bool Font::isCJKIdeograph(UChar32 c)
+{
+ // The basic CJK Unified Ideographs block.
+ if (c >= 0x4E00 && c <= 0x9FFF)
+ return true;
+
+ // CJK Unified Ideographs Extension A.
+ if (c >= 0x3400 && c <= 0x4DBF)
+ return true;
+
+ // CJK Radicals Supplement.
+ if (c >= 0x2E80 && c <= 0x2EFF)
+ return true;
+
+ // Kangxi Radicals.
+ if (c >= 0x2F00 && c <= 0x2FDF)
+ return true;
+
+ // CJK Strokes.
+ if (c >= 0x31C0 && c <= 0x31EF)
+ return true;
+
+ // CJK Compatibility Ideographs.
+ if (c >= 0xF900 && c <= 0xFAFF)
+ return true;
+
+ // CJK Unified Ideographs Extension B.
+ if (c >= 0x20000 && c <= 0x2A6DF)
+ return true;
+
+ // CJK Unified Ideographs Extension C.
+ if (c >= 0x2A700 && c <= 0x2B73F)
+ return true;
+
+ // CJK Unified Ideographs Extension D.
+ if (c >= 0x2B740 && c <= 0x2B81F)
+ return true;
+
+ // CJK Compatibility Ideographs Supplement.
+ if (c >= 0x2F800 && c <= 0x2FA1F)
+ return true;
+
+ return false;
+}
+
+bool Font::isCJKIdeographOrSymbol(UChar32 c)
+{
+ // 0x2C7 Caron, Mandarin Chinese 3rd Tone
+ // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
+ // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
+ // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
+ if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
+ return true;
+
+ // Ideographic Description Characters.
+ if (c >= 0x2FF0 && c <= 0x2FFF)
+ return true;
+
+ // CJK Symbols and Punctuation.
+ if (c >= 0x3000 && c <= 0x303F)
+ return true;
+
+ // Hiragana
+ if (c >= 0x3040 && c <= 0x309F)
+ return true;
+
+ // Katakana
+ if (c >= 0x30A0 && c <= 0x30FF)
+ return true;
+
+ // Bopomofo
+ if (c >= 0x3100 && c <= 0x312F)
+ return true;
+
+ // Bopomofo Extended
+ if (c >= 0x31A0 && c <= 0x31BF)
+ return true;
+
+ // Enclosed CJK Letters and Months.
+ if (c >= 0x3200 && c <= 0x32FF)
+ return true;
+
+ // CJK Compatibility.
+ if (c >= 0x3300 && c <= 0x33FF)
+ return true;
+
+ // CJK Compatibility Forms.
+ if (c >= 0xFE30 && c <= 0xFE4F)
+ return true;
+
+ // Halfwidth and Fullwidth Forms
+ // Usually only used in CJK
+ if (c >= 0xFF00 && c <= 0xFFEF)
+ return true;
+
+ // Emoji.
+ if (c >= 0x1F200 && c <= 0x1F6F)
+ return true;
+
+ return isCJKIdeograph(c);
+}
+
+bool Font::canReceiveTextEmphasis(UChar32 c)
+{
+ CharCategory category = Unicode::category(c);
+ if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
+ return false;
+
+ // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
+ if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
+ || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
+ return false;
+
+ return true;
+}
+
+}