Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / fonts / Font.cpp
old mode 100755 (executable)
new mode 100644 (file)
index d6f7024..03bcf14
 #include "config.h"
 #include "platform/fonts/Font.h"
 
+#include "platform/LayoutUnit.h"
+#include "platform/fonts/Character.h"
+#include "platform/fonts/FontCache.h"
+#include "platform/fonts/FontFallbackList.h"
+#include "platform/fonts/FontPlatformFeatures.h"
+#include "platform/fonts/GlyphBuffer.h"
+#include "platform/fonts/GlyphPageTreeNode.h"
+#include "platform/fonts/SimpleFontData.h"
 #include "platform/fonts/WidthIterator.h"
 #include "platform/geometry/FloatRect.h"
 #include "platform/text/TextRun.h"
 #include "wtf/MainThread.h"
 #include "wtf/StdLibExtras.h"
-#include "wtf/text/StringBuilder.h"
+#include "wtf/unicode/CharacterNames.h"
+#include "wtf/unicode/Unicode.h"
 
 using namespace WTF;
 using namespace Unicode;
+using namespace std;
 
 namespace WebCore {
 
-const uint8_t Font::s_roundingHackCharacterTable[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
-};
-
-static const UChar32 cjkIsolatedSymbolsArray[] = {
-    // 0x2C7 Caron, Mandarin Chinese 3rd Tone
-    0x2C7,
-    // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
-    0x2CA,
-    // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
-    0x2CB,
-    // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
-    0x2D9,
-    0x2020, 0x2021, 0x2030, 0x203B, 0x203C, 0x2042, 0x2047, 0x2048, 0x2049, 0x2051,
-    0x20DD, 0x20DE, 0x2100, 0x2103, 0x2105, 0x2109, 0x210A, 0x2113, 0x2116, 0x2121,
-    0x212B, 0x213B, 0x2150, 0x2151, 0x2152, 0x217F, 0x2189, 0x2307, 0x2312, 0x23CE,
-    0x2423, 0x25A0, 0x25A1, 0x25A2, 0x25AA, 0x25AB, 0x25B1, 0x25B2, 0x25B3, 0x25B6,
-    0x25B7, 0x25BC, 0x25BD, 0x25C0, 0x25C1, 0x25C6, 0x25C7, 0x25C9, 0x25CB, 0x25CC,
-    0x25EF, 0x2605, 0x2606, 0x260E, 0x2616, 0x2617, 0x2640, 0x2642, 0x26A0, 0x26BD,
-    0x26BE, 0x2713, 0x271A, 0x273F, 0x2740, 0x2756, 0x2B1A, 0xFE10, 0xFE11, 0xFE12,
-    0xFE19, 0xFF1D,
-    // Emoji.
-    0x1F100
-};
-
 CodePath Font::s_codePath = AutoPath;
 
-TypesettingFeatures Font::s_defaultTypesettingFeatures = 0;
-
 // ============================================================================================
 // Font Implementation (Cross-Platform Portion)
 // ============================================================================================
 
 Font::Font()
-    : m_letterSpacing(0)
-    , m_wordSpacing(0)
-    , m_typesettingFeatures(0)
 {
 }
 
-Font::Font(const FontDescription& fd, float letterSpacing, float wordSpacing)
+Font::Font(const FontDescription& fd)
     : m_fontDescription(fd)
-    , m_letterSpacing(letterSpacing)
-    , m_wordSpacing(wordSpacing)
-    , m_typesettingFeatures(computeTypesettingFeatures())
 {
 }
 
 Font::Font(const Font& other)
     : m_fontDescription(other.m_fontDescription)
     , m_fontFallbackList(other.m_fontFallbackList)
-    , m_letterSpacing(other.m_letterSpacing)
-    , m_wordSpacing(other.m_wordSpacing)
-    , m_typesettingFeatures(computeTypesettingFeatures())
 {
 }
 
@@ -104,9 +71,6 @@ Font& Font::operator=(const Font& other)
 {
     m_fontDescription = other.m_fontDescription;
     m_fontFallbackList = other.m_fontFallbackList;
-    m_letterSpacing = other.m_letterSpacing;
-    m_wordSpacing = other.m_wordSpacing;
-    m_typesettingFeatures = other.m_typesettingFeatures;
     return *this;
 }
 
@@ -122,8 +86,6 @@ 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_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() : 0)
         && (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0);
 }
@@ -138,7 +100,6 @@ void Font::update(PassRefPtr<FontSelector> fontSelector) const
     if (!m_fontFallbackList)
         m_fontFallbackList = FontFallbackList::create();
     m_fontFallbackList->invalidate(fontSelector);
-    m_typesettingFeatures = computeTypesettingFeatures();
 }
 
 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const
@@ -151,7 +112,7 @@ void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, c
 
     CodePath codePathToUse = codePath(runInfo.run);
     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
-    if (codePathToUse != ComplexPath && typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
+    if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
         codePathToUse = ComplexPath;
 
     if (codePathToUse != ComplexPath)
@@ -167,7 +128,7 @@ void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r
 
     CodePath codePathToUse = codePath(runInfo.run);
     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
-    if (codePathToUse != ComplexPath && typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
+    if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
         codePathToUse = ComplexPath;
 
     if (codePathToUse != ComplexPath)
@@ -181,15 +142,15 @@ float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFo
     CodePath codePathToUse = codePath(run);
     if (codePathToUse != ComplexPath) {
         // The complex path is more restrictive about returning fallback fonts than the simple path, so we need an explicit test to make their behaviors match.
-        if (!canReturnFallbackFontsForComplexText())
+        if (!FontPlatformFeatures::canReturnFallbackFontsForComplexText())
             fallbackFonts = 0;
         // The simple path can optimize the case where glyph overflow is not observable.
         if (codePathToUse != SimpleWithGlyphOverflowPath && (glyphOverflow && !glyphOverflow->computeBounds))
             glyphOverflow = 0;
     }
 
-    bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures);
-    bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing();
+    bool hasKerningOrLigatures = fontDescription().typesettingFeatures() & (Kerning | Ligatures);
+    bool hasWordSpacingOrLetterSpacing = fontDescription().wordSpacing() || fontDescription().letterSpacing();
     float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow);
     if (cacheEntry && !std::isnan(*cacheEntry))
         return *cacheEntry;
@@ -223,7 +184,7 @@ FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point
 
     CodePath codePathToUse = codePath(run);
     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
-    if (codePathToUse != ComplexPath && typesettingFeatures() && (from || to != run.length()))
+    if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (from || to != run.length()))
         codePathToUse = ComplexPath;
 
     if (codePathToUse != ComplexPath)
@@ -235,47 +196,12 @@ FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point
 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
 {
     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
-    if (codePath(run) != ComplexPath && !typesettingFeatures())
+    if (codePath(run) != ComplexPath && !fontDescription().typesettingFeatures())
         return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
 
     return offsetForPositionForComplexText(run, x, includePartialGlyphs);
 }
 
-template <typename CharacterType>
-static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
-{
-    StringBuilder normalized;
-    normalized.reserveCapacity(length);
-
-    for (unsigned i = 0; i < length; ++i)
-        normalized.append(Font::normalizeSpaces(characters[i]));
-
-    return normalized.toString();
-}
-
-String Font::normalizeSpaces(const LChar* characters, unsigned length)
-{
-    return normalizeSpacesInternal(characters, length);
-}
-
-String Font::normalizeSpaces(const UChar* characters, unsigned length)
-{
-    return normalizeSpacesInternal(characters, length);
-}
-
-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;
@@ -286,16 +212,6 @@ CodePath Font::codePath()
     return s_codePath;
 }
 
-void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures)
-{
-    s_defaultTypesettingFeatures = typesettingFeatures;
-}
-
-TypesettingFeatures Font::defaultTypesettingFeatures()
-{
-    return s_defaultTypesettingFeatures;
-}
-
 CodePath Font::codePath(const TextRun& run) const
 {
     if (s_codePath != AutoPath)
@@ -319,301 +235,593 @@ CodePath Font::codePath(const TextRun& run) const
         return SimplePath;
 
     // Start from 0 since drawing and highlighting also measure the characters before run->from.
-    return characterRangeCodePath(run.characters16(), run.length());
+    return Character::characterRangeCodePath(run.characters16(), run.length());
 }
 
-// Takes a flattened list of closed intervals
-template <class T, size_t size>
-bool valueInIntervalList(const T (&intervalList)[size], const T& value)
+void Font::willUseFontData() const
 {
-    const T* bound = std::upper_bound(&intervalList[0], &intervalList[size], value);
-    if ((bound - intervalList) % 2 == 1)
+    const FontFamily& family = fontDescription().family();
+    if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.familyIsEmpty())
+        m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), family.family());
+}
+
+static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 upperBound)
+{
+    return character >= lowerBound && character <= upperBound;
+}
+
+static bool shouldIgnoreRotation(UChar32 character)
+{
+    if (character == 0x000A7 || character == 0x000A9 || character == 0x000AE)
         return true;
-    return bound > intervalList && *(bound - 1) == value;
-}
-
-CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len)
-{
-    static const UChar complexCodePathRanges[] = {
-        // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
-        0x2E5, 0x2E9,
-        // U+0300 through U+036F Combining diacritical marks
-        0x300, 0x36F,
-        // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, ...
-        0x0591, 0x05BD,
-        // ... Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
-        0x05BF, 0x05CF,
-        // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
-        // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
-        // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
-        0x0600, 0x109F,
-        // 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)
-        0x1100, 0x11FF,
-        // U+135D through U+135F Ethiopic combining marks
-        0x135D, 0x135F,
-        // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
-        0x1700, 0x18AF,
-        // U+1900 through U+194F Limbu (Unicode 4.0)
-        0x1900, 0x194F,
-        // U+1980 through U+19DF New Tai Lue
-        0x1980, 0x19DF,
-        // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
-        0x1A00, 0x1CFF,
-        // U+1DC0 through U+1DFF Comining diacritical mark supplement
-        0x1DC0, 0x1DFF,
-        // U+20D0 through U+20FF Combining marks for symbols
-        0x20D0, 0x20FF,
-        // U+2CEF through U+2CF1 Combining marks for Coptic
-        0x2CEF, 0x2CF1,
-        // U+302A through U+302F Ideographic and Hangul Tone marks
-        0x302A, 0x302F,
-        // U+A67C through U+A67D Combining marks for old Cyrillic
-        0xA67C, 0xA67D,
-        // U+A6F0 through U+A6F1 Combining mark for Bamum
-        0xA6F0, 0xA6F1,
-        // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
-        // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek
-        0xA800, 0xABFF,
-        // U+D7B0 through U+D7FF Hangul Jamo Ext. B
-        0xD7B0, 0xD7FF,
-        // U+FE00 through U+FE0F Unicode variation selectors
-        0xFE00, 0xFE0F,
-        // U+FE20 through U+FE2F Combining half marks
-        0xFE20, 0xFE2F
-    };
-
-    CodePath result = SimplePath;
-    for (unsigned i = 0; i < len; i++) {
-        const UChar c = characters[i];
-
-        // Shortcut for common case
-        if (c < 0x2E5)
-            continue;
-
-        // U+1E00 through U+2000 characters with diacritics and stacked diacritics
-        if (c >= 0x1E00 && c <= 0x2000) {
-            result = SimpleWithGlyphOverflowPath;
-            continue;
-        }
 
-        // Surrogate pairs
-        if (c > 0xD7FF && c <= 0xDBFF) {
-            if (i == len - 1)
-                continue;
+    if (character == 0x000B6 || character == 0x000BC || character == 0x000BD || character == 0x000BE)
+        return true;
 
-            UChar next = characters[++i];
-            if (!U16_IS_TRAIL(next))
-                continue;
+    if (isInRange(character, 0x002E5, 0x002EB))
+        return true;
 
-            UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
+    if (isInRange(character, 0x01100, 0x011FF) || isInRange(character, 0x01401, 0x0167F) || isInRange(character, 0x01800, 0x018FF))
+        return true;
 
-            if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
-                continue;
-            if (supplementaryCharacter <= 0x1F1FF)
-                return ComplexPath;
+    if (character == 0x02016 || character == 0x02018 || character == 0x02019 || character == 0x02020 || character == 0x02021
+        || character == 0x2030 || character == 0x02031)
+        return true;
 
-            if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
-                continue;
-            if (supplementaryCharacter <= 0xE01EF)
-                return ComplexPath;
+    if (isInRange(character, 0x0203B, 0x0203D) || character == 0x02042 || character == 0x02044 || character == 0x02047
+        || character == 0x02048 || character == 0x02049 || character == 0x2051)
+        return true;
 
-            // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
-            // in plane 1 or higher.
+    if (isInRange(character, 0x02065, 0x02069) || isInRange(character, 0x020DD, 0x020E0)
+        || isInRange(character, 0x020E2, 0x020E4) || isInRange(character, 0x02100, 0x02117)
+        || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x02133, 0x0213F))
+        return true;
 
-            continue;
-        }
+    if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || character == 0x0214D
+        || isInRange(character, 0x0214F, 0x0218F))
+        return true;
 
-        // Search for other Complex cases
-        if (valueInIntervalList(complexCodePathRanges, c))
-            return ComplexPath;
-    }
+    if (isInRange(character, 0x02300, 0x02307) || isInRange(character, 0x0230C, 0x0231F)
+        || isInRange(character, 0x02322, 0x0232B) || isInRange(character, 0x0237D, 0x0239A)
+        || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023BA, 0x023CF)
+        || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E2, 0x024FF))
+        return true;
 
-    return result;
-}
+    if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620, 0x02767)
+        || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B12, 0x02B2F)
+        || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E80, 0x03007))
+        return true;
 
-bool Font::isCJKIdeograph(UChar32 c)
-{
-    static const UChar32 cjkIdeographRanges[] = {
-        // CJK Radicals Supplement and Kangxi Radicals.
-        0x2E80, 0x2FDF,
-        // CJK Strokes.
-        0x31C0, 0x31EF,
-        // CJK Unified Ideographs Extension A.
-        0x3400, 0x4DBF,
-        // The basic CJK Unified Ideographs block.
-        0x4E00, 0x9FFF,
-        // CJK Compatibility Ideographs.
-        0xF900, 0xFAFF,
-        // CJK Unified Ideographs Extension B.
-        0x20000, 0x2A6DF,
-        // CJK Unified Ideographs Extension C.
-        // CJK Unified Ideographs Extension D.
-        0x2A700, 0x2B81F,
-        // CJK Compatibility Ideographs Supplement.
-        0x2F800, 0x2FA1F
-    };
-    static size_t cjkIdeographRangesCount = WTF_ARRAY_LENGTH(cjkIdeographRanges);
-
-    // Early out
-    if (c < cjkIdeographRanges[0] || c > cjkIdeographRanges[cjkIdeographRangesCount - 1])
-        return false;
+    if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x03020, 0x0302F)
+        || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A1, 0x030FB)
+        || isInRange(character, 0x030FD, 0x0A4CF))
+        return true;
 
-    return valueInIntervalList(cjkIdeographRanges, c);
-}
+    if (isInRange(character, 0x0A840, 0x0A87F) || isInRange(character, 0x0A960, 0x0A97F)
+        || isInRange(character, 0x0AC00, 0x0D7FF) || isInRange(character, 0x0E000, 0x0FAFF))
+        return true;
 
-bool Font::isCJKIdeographOrSymbol(UChar32 c)
-{
-    // Likely common case
-    if (c < 0x2C7)
-        return false;
+    if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30, 0x0FE48)
+        || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5F, 0x0FE62)
+        || isInRange(character, 0x0FE67, 0x0FE6F))
+        return true;
 
-    // Hash lookup for isolated symbols (those not part of a contiguous range)
-    static HashSet<UChar32>* cjkIsolatedSymbols = 0;
-    if (!cjkIsolatedSymbols) {
-        cjkIsolatedSymbols = new HashSet<UChar32>();
-        for (size_t i = 0; i < WTF_ARRAY_LENGTH(cjkIsolatedSymbolsArray); ++i)
-            cjkIsolatedSymbols->add(cjkIsolatedSymbolsArray[i]);
-    }
-    if (cjkIsolatedSymbols->contains(c))
+    if (isInRange(character, 0x0FF01, 0x0FF07) || isInRange(character, 0x0FF0A, 0x0FF0C)
+        || isInRange(character, 0x0FF0E, 0x0FF19) || isInRange(character, 0x0FF1F, 0x0FF3A))
+        return true;
+
+    if (character == 0x0FF3C || character == 0x0FF3E)
+        return true;
+
+    if (isInRange(character, 0x0FF40, 0x0FF5A) || isInRange(character, 0x0FFE0, 0x0FFE2)
+        || isInRange(character, 0x0FFE4, 0x0FFE7) || isInRange(character, 0x0FFF0, 0x0FFF8)
+        || character == 0x0FFFD)
         return true;
 
-    if (isCJKIdeograph(c))
+    if (isInRange(character, 0x13000, 0x1342F) || isInRange(character, 0x1B000, 0x1B0FF)
+        || isInRange(character, 0x1D000, 0x1D1FF) || isInRange(character, 0x1D300, 0x1D37F)
+        || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F680, 0x1F77F))
         return true;
 
-    static const UChar32 cjkSymbolRanges[] = {
-        0x2156, 0x215A,
-        0x2160, 0x216B,
-        0x2170, 0x217B,
-        0x23BE, 0x23CC,
-        0x2460, 0x2492,
-        0x249C, 0x24FF,
-        0x25CE, 0x25D3,
-        0x25E2, 0x25E6,
-        0x2600, 0x2603,
-        0x2660, 0x266F,
-        0x2672, 0x267D,
-        0x2776, 0x277F,
-        // Ideographic Description Characters, with CJK Symbols and Punctuation, excluding 0x3030.
-        // Then Hiragana 0x3040 .. 0x309F, Katakana 0x30A0 .. 0x30FF, Bopomofo 0x3100 .. 0x312F
-        0x2FF0, 0x302F,
-        0x3031, 0x312F,
-        // More Bopomofo and Bopomofo Extended 0x31A0 .. 0x31BF
-        0x3190, 0x31BF,
-        // Enclosed CJK Letters and Months (0x3200 .. 0x32FF).
-        // CJK Compatibility (0x3300 .. 0x33FF).
-        0x3200, 0x33FF,
-        0xF860, 0xF862,
-        // CJK Compatibility Forms.
-        0xFE30, 0xFE4F,
-        // Halfwidth and Fullwidth Forms
-        // Usually only used in CJK
-        0xFF00, 0xFF0C,
-        0xFF0E, 0xFF1A,
-        0xFF1F, 0xFFEF,
-        // Emoji.
-        0x1F110, 0x1F129,
-        0x1F130, 0x1F149,
-        0x1F150, 0x1F169,
-        0x1F170, 0x1F189,
-        0x1F200, 0x1F6FF
-    };
-
-    return valueInIntervalList(cjkSymbolRanges, c);
-}
-
-unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
-{
-    unsigned count = 0;
-    if (direction == LTR) {
-        for (size_t i = 0; i < length; ++i) {
-            if (treatAsSpace(characters[i])) {
-                count++;
-                isAfterExpansion = true;
-            } else
-                isAfterExpansion = false;
+    if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000, 0x3FFFD))
+        return true;
+
+    return false;
+}
+
+static inline std::pair<GlyphData, GlyphPage*> glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, GlyphData& data, GlyphPage* page, unsigned pageNumber)
+{
+    if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(character)) {
+        RefPtr<SimpleFontData> uprightFontData = data.fontData->uprightOrientationFontData();
+        GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData.get(), pageNumber);
+        GlyphPage* uprightPage = uprightNode->page();
+        if (uprightPage) {
+            GlyphData uprightData = uprightPage->glyphDataForCharacter(character);
+            // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
+            if (data.glyph == uprightData.glyph)
+                return make_pair(data, page);
+            // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
+            // glyph, so we fall back to the upright data and use the horizontal glyph.
+            if (uprightData.fontData)
+                return make_pair(uprightData, uprightPage);
         }
-    } else {
-        for (size_t i = length; i > 0; --i) {
-            if (treatAsSpace(characters[i - 1])) {
-                count++;
-                isAfterExpansion = true;
-            } else
-                isAfterExpansion = false;
+    } else if (orientation == NonCJKGlyphOrientationVerticalRight) {
+        RefPtr<SimpleFontData> verticalRightFontData = data.fontData->verticalRightOrientationFontData();
+        GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData.get(), pageNumber);
+        GlyphPage* verticalRightPage = verticalRightNode->page();
+        if (verticalRightPage) {
+            GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(character);
+            // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
+            // into it.
+            if (data.glyph != verticalRightData.glyph)
+                return make_pair(data, page);
+            // The glyphs are identical, meaning that we should just use the horizontal glyph.
+            if (verticalRightData.fontData)
+                return make_pair(verticalRightData, verticalRightPage);
         }
     }
-    return count;
+    return make_pair(data, page);
 }
 
-unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
+std::pair<GlyphData, GlyphPage*> Font::glyphDataAndPageForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
 {
-    static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
-    unsigned count = 0;
-    if (direction == LTR) {
-        for (size_t i = 0; i < length; ++i) {
-            UChar32 character = characters[i];
-            if (treatAsSpace(character)) {
-                count++;
-                isAfterExpansion = true;
-                continue;
-            }
-            if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
-                character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
-                i++;
-            }
-            if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
-                if (!isAfterExpansion)
-                    count++;
-                count++;
-                isAfterExpansion = true;
-                continue;
+    ASSERT(isMainThread());
+
+    if (variant == AutoVariant) {
+        if (m_fontDescription.smallCaps() && !primaryFont()->isSVGFont()) {
+            UChar32 upperC = toUpper(c);
+            if (upperC != c) {
+                c = upperC;
+                variant = SmallCapsVariant;
+            } else {
+                variant = NormalVariant;
             }
-            isAfterExpansion = false;
+        } else {
+            variant = NormalVariant;
         }
-    } else {
-        for (size_t i = length; i > 0; --i) {
-            UChar32 character = characters[i - 1];
-            if (treatAsSpace(character)) {
-                count++;
-                isAfterExpansion = true;
-                continue;
-            }
-            if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
-                character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
-                i--;
+    }
+
+    if (mirror)
+        c = mirroredChar(c);
+
+    unsigned pageNumber = (c / GlyphPage::size);
+
+    GlyphPageTreeNode* node = pageNumber ? m_fontFallbackList->m_pages.get(pageNumber) : m_fontFallbackList->m_pageZero;
+    if (!node) {
+        node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
+        if (pageNumber)
+            m_fontFallbackList->m_pages.set(pageNumber, node);
+        else
+            m_fontFallbackList->m_pageZero = node;
+    }
+
+    GlyphPage* page = 0;
+    if (variant == NormalVariant) {
+        // Fastest loop, for the common case (normal variant).
+        while (true) {
+            page = node->page();
+            if (page) {
+                GlyphData data = page->glyphDataForCharacter(c);
+                if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback()))
+                    return make_pair(data, page);
+
+                if (data.fontData) {
+                    if (Character::isCJKIdeographOrSymbol(c)) {
+                        if (!data.fontData->hasVerticalGlyphs()) {
+                            // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
+                            // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
+                            variant = BrokenIdeographVariant;
+                            break;
+                        }
+                    } else {
+                        return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, page, pageNumber);
+                    }
+
+                    return make_pair(data, page);
+                }
+
+                if (node->isSystemFallback())
+                    break;
             }
-            if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
-                if (!isAfterExpansion)
-                    count++;
-                count++;
-                isAfterExpansion = true;
-                continue;
+
+            // Proceed with the fallback list.
+            node = node->getChild(fontDataAt(node->level()), pageNumber);
+            if (pageNumber)
+                m_fontFallbackList->m_pages.set(pageNumber, node);
+            else
+                m_fontFallbackList->m_pageZero = node;
+        }
+    }
+    if (variant != NormalVariant) {
+        while (true) {
+            page = node->page();
+            if (page) {
+                GlyphData data = page->glyphDataForCharacter(c);
+                if (data.fontData) {
+                    // The variantFontData function should not normally return 0.
+                    // But if it does, we will just render the capital letter big.
+                    RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
+                    if (!variantFontData)
+                        return make_pair(data, page);
+
+                    GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData.get(), pageNumber);
+                    GlyphPage* variantPage = variantNode->page();
+                    if (variantPage) {
+                        GlyphData data = variantPage->glyphDataForCharacter(c);
+                        if (data.fontData)
+                            return make_pair(data, variantPage);
+                    }
+
+                    // Do not attempt system fallback off the variantFontData. 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 make_pair(variantFontData->missingGlyphData(), page);
+                }
+
+                if (node->isSystemFallback())
+                    break;
             }
-            isAfterExpansion = false;
+
+            // Proceed with the fallback list.
+            node = node->getChild(fontDataAt(node->level()), pageNumber);
+            if (pageNumber)
+                m_fontFallbackList->m_pages.set(pageNumber, node);
+            else
+                m_fontFallbackList->m_pageZero = node;
         }
     }
-    return count;
+
+    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.
+
+    // FIXME: Unclear if this should normalizeSpaces above 0xFFFF.
+    // Doing so changes fast/text/international/plane2-diffs.html
+    UChar32 characterToRender = c;
+    if (characterToRender <=  0xFFFF)
+        characterToRender = Character::normalizeSpaces(characterToRender);
+    const SimpleFontData* fontDataToSubstitute = fontDataAt(0)->fontDataForCharacter(characterToRender);
+    RefPtr<SimpleFontData> characterFontData = FontCache::fontCache()->platformFallbackForCharacter(m_fontDescription, characterToRender, fontDataToSubstitute);
+    if (characterFontData) {
+        if (characterFontData->platformData().orientation() == Vertical && !characterFontData->hasVerticalGlyphs() && Character::isCJKIdeographOrSymbol(c))
+            variant = BrokenIdeographVariant;
+        if (variant != NormalVariant)
+            characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
+    }
+    if (characterFontData) {
+        // Got the fallback glyph and font.
+        GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData.get(), pageNumber)->page();
+        GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
+        // Cache it so we don't have to do system fallback again next time.
+        if (variant == NormalVariant) {
+            page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
+            data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
+            if (!Character::isCJKIdeographOrSymbol(c) && data.fontData->platformData().orientation() != Horizontal && !data.fontData->isTextOrientationFallback())
+                return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, fallbackPage, pageNumber);
+        }
+        return make_pair(data, page);
+    }
+
+    // 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.
+    GlyphData data = primaryFont()->missingGlyphData();
+    if (variant == NormalVariant) {
+        page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
+        data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
+    }
+    return make_pair(data, page);
 }
 
-bool Font::canReceiveTextEmphasis(UChar32 c)
+bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
 {
-    CharCategory category = Unicode::category(c);
-    if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
-        return false;
+    unsigned pageNumber = (character / GlyphPage::size);
+
+    GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
+    GlyphPage* page = node->page();
+
+    return page && page->fontDataForCharacter(character);
+}
 
-    // 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)
+// FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
+// standard emphasis marks do so.
+bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
+{
+    if (mark.isEmpty())
         return false;
 
+    UChar32 character = mark[0];
+
+    if (U16_IS_SURROGATE(character)) {
+        if (!U16_IS_SURROGATE_LEAD(character))
+            return false;
+
+        if (mark.length() < 2)
+            return false;
+
+        UChar low = mark[1];
+        if (!U16_IS_TRAIL(low))
+            return false;
+
+        character = U16_GET_SUPPLEMENTARY(character, low);
+    }
+
+    glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
     return true;
 }
 
-void Font::willUseFontData() const
+int Font::emphasisMarkAscent(const AtomicString& mark) const
 {
-    const FontFamily& family = fontDescription().family();
-    if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.familyIsEmpty())
-        m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), family.family());
+    FontCachePurgePreventer purgePreventer;
+
+    GlyphData markGlyphData;
+    if (!getEmphasisMarkGlyphData(mark, markGlyphData))
+        return 0;
+
+    const SimpleFontData* markFontData = markGlyphData.fontData;
+    ASSERT(markFontData);
+    if (!markFontData)
+        return 0;
+
+    return markFontData->fontMetrics().ascent();
+}
+
+int Font::emphasisMarkDescent(const AtomicString& mark) const
+{
+    FontCachePurgePreventer purgePreventer;
+
+    GlyphData markGlyphData;
+    if (!getEmphasisMarkGlyphData(mark, markGlyphData))
+        return 0;
+
+    const SimpleFontData* markFontData = markGlyphData.fontData;
+    ASSERT(markFontData);
+    if (!markFontData)
+        return 0;
+
+    return markFontData->fontMetrics().descent();
+}
+
+int Font::emphasisMarkHeight(const AtomicString& mark) const
+{
+    FontCachePurgePreventer purgePreventer;
+
+    GlyphData markGlyphData;
+    if (!getEmphasisMarkGlyphData(mark, markGlyphData))
+        return 0;
+
+    const SimpleFontData* markFontData = markGlyphData.fontData;
+    ASSERT(markFontData);
+    if (!markFontData)
+        return 0;
+
+    return markFontData->fontMetrics().height();
+}
+
+float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
+{
+    float initialAdvance;
+
+    WidthIterator it(this, run, 0, false, forTextEmphasis);
+    // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or
+    // ligatures are enabled.
+    GlyphBuffer localGlyphBuffer;
+    it.advance(from, &localGlyphBuffer);
+    float beforeWidth = it.m_runWidthSoFar;
+    it.advance(to, &glyphBuffer);
+
+    if (glyphBuffer.isEmpty())
+        return 0;
+
+    float afterWidth = it.m_runWidthSoFar;
+
+    if (run.rtl()) {
+        float finalRoundingWidth = it.m_finalRoundingWidth;
+        it.advance(run.length(), &localGlyphBuffer);
+        initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
+    } else {
+        initialAdvance = beforeWidth;
+    }
+
+    if (run.rtl())
+        glyphBuffer.reverse(0, glyphBuffer.size());
+
+    return initialAdvance;
+}
+
+void Font::drawSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point) const
+{
+    // This glyph buffer holds our glyphs+advances+font data for each glyph.
+    GlyphBuffer glyphBuffer;
+
+    float startX = point.x() + getGlyphsAndAdvancesForSimpleText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer);
+
+    if (glyphBuffer.isEmpty())
+        return;
+
+    FloatPoint startPoint(startX, point.y());
+    drawGlyphBuffer(context, runInfo, glyphBuffer, startPoint);
+}
+
+void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
+{
+    GlyphBuffer glyphBuffer;
+    float initialAdvance = getGlyphsAndAdvancesForSimpleText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer, ForTextEmphasis);
+
+    if (glyphBuffer.isEmpty())
+        return;
+
+    drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
+}
+
+void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
+{
+    // Draw each contiguous run of glyphs that use the same font data.
+    const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
+    FloatPoint startPoint(point);
+    float nextX = startPoint.x() + glyphBuffer.advanceAt(0);
+    unsigned lastFrom = 0;
+    unsigned nextGlyph = 1;
+#if ENABLE(SVG_FONTS)
+    TextRun::RenderingContext* renderingContext = runInfo.run.renderingContext();
+#endif
+    while (nextGlyph < glyphBuffer.size()) {
+        const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
+
+        if (nextFontData != fontData) {
+#if ENABLE(SVG_FONTS)
+            if (renderingContext && fontData->isSVGFont())
+                renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
+            else
+#endif
+                drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds);
+
+            lastFrom = nextGlyph;
+            fontData = nextFontData;
+            startPoint.setX(nextX);
+        }
+        nextX += glyphBuffer.advanceAt(nextGlyph);
+        nextGlyph++;
+    }
+
+#if ENABLE(SVG_FONTS)
+    if (renderingContext && fontData->isSVGFont())
+        renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
+    else
+#endif
+        drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds);
+}
+
+inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
+{
+    if (fontData->platformData().orientation() == Horizontal) {
+        FloatRect bounds = fontData->boundsForGlyph(glyph);
+        return bounds.x() + bounds.width() / 2;
+    }
+    // FIXME: Use glyph bounds once they make sense for vertical fonts.
+    return fontData->widthForGlyph(glyph) / 2;
+}
+
+inline static float offsetToMiddleOfAdvanceAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
+{
+    return glyphBuffer.advanceAt(i) / 2;
+}
+
+void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
+{
+    FontCachePurgePreventer purgePreventer;
+
+    GlyphData markGlyphData;
+    if (!getEmphasisMarkGlyphData(mark, markGlyphData))
+        return;
+
+    const SimpleFontData* markFontData = markGlyphData.fontData;
+    ASSERT(markFontData);
+    if (!markFontData)
+        return;
+
+    Glyph markGlyph = markGlyphData.glyph;
+    Glyph spaceGlyph = markFontData->spaceGlyph();
+
+    float middleOfLastGlyph = offsetToMiddleOfAdvanceAtIndex(glyphBuffer, 0);
+    FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
+
+    GlyphBuffer markBuffer;
+    for (unsigned i = 0; i + 1 < glyphBuffer.size(); ++i) {
+        float middleOfNextGlyph = offsetToMiddleOfAdvanceAtIndex(glyphBuffer, i + 1);
+        float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
+        markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
+        middleOfLastGlyph = middleOfNextGlyph;
+    }
+    markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
+
+    drawGlyphBuffer(context, runInfo, markBuffer, startPoint);
+}
+
+float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+    WidthIterator it(this, run, fallbackFonts, glyphOverflow);
+    GlyphBuffer glyphBuffer;
+    it.advance(run.length(), (fontDescription().typesettingFeatures() & (Kerning | Ligatures)) ? &glyphBuffer : 0);
+
+    if (glyphOverflow) {
+        glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
+        glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
+        glyphOverflow->left = ceilf(it.firstGlyphOverflow());
+        glyphOverflow->right = ceilf(it.lastGlyphOverflow());
+    }
+
+    return it.m_runWidthSoFar;
+}
+
+FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
+{
+    GlyphBuffer glyphBuffer;
+    WidthIterator it(this, run);
+    it.advance(from, &glyphBuffer);
+    float beforeWidth = it.m_runWidthSoFar;
+    it.advance(to, &glyphBuffer);
+    float afterWidth = it.m_runWidthSoFar;
+
+    // Using roundf() rather than ceilf() for the right edge as a compromise to
+    // ensure correct caret positioning.
+    // Use LayoutUnit::epsilon() to ensure that values that cannot be stored as
+    // an integer are floored to n and not n-1 due to floating point imprecision.
+    if (run.rtl()) {
+        it.advance(run.length(), &glyphBuffer);
+        float totalWidth = it.m_runWidthSoFar;
+        float pixelAlignedX = floorf(point.x() + totalWidth - afterWidth + LayoutUnit::epsilon());
+        return FloatRect(pixelAlignedX, point.y(),
+            roundf(point.x() + totalWidth - beforeWidth) - pixelAlignedX, h);
+    }
+
+    float pixelAlignedX = floorf(point.x() + beforeWidth + LayoutUnit::epsilon());
+    return FloatRect(pixelAlignedX, point.y(),
+        roundf(point.x() + afterWidth) - pixelAlignedX, h);
+}
+
+int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
+{
+    float delta = x;
+
+    WidthIterator it(this, run);
+    GlyphBuffer localGlyphBuffer;
+    unsigned offset;
+    if (run.rtl()) {
+        delta -= floatWidthForSimpleText(run);
+        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;
 }
 
 }