Changeset 130851 in webkit


Ignore:
Timestamp:
Oct 9, 2012 10:48:51 PM (11 years ago)
Author:
enrica@apple.com
Message:

Only measure text once instead of twice when performing line layout.
https://bugs.webkit.org/show_bug.cgi?id=98317
<rdar://problem/12080821>

Reviewed by Dan Bernstein.

Since we are measuring each word to find out where the line break should occur,
we should cache that information to avoid measuring the run again when
creating the line box. The bulk of the change is in nextLineBreak, where
the measurements are collected and placed in a vector so that they can
be consumed in setLogicalWidthForTextRun where we used to measure the
text one more time.
Each entry in the vector is a WordMeasurement object that contains information
about the start and end offset in the run, the renderer, the measured width
and, possibly, a list of fallback fonts.
When we need to compute the width of the run to create the line box, we add
all the measurements for the given renderer in the run to get the total width.
This optiomization is currently disabled for platforms using HarfBuzz.

  • platform/graphics/Font.cpp:

(WebCore::Font::width): Added fallback fonts parameter.

  • platform/graphics/Font.h:

(Font): Added fallback fonts parameter to the width static member function.
This method is called when we compute the width using TextLayout.

  • platform/graphics/mac/ComplexTextController.cpp:

(WebCore::TextLayout::width): Added fallback fonts parameter.
(WebCore::Font::width):
(WebCore::ComplexTextController::advance):

  • platform/graphics/mac/ComplexTextController.h:

(ComplexTextController): Added fallback fonts parameter to advance method.

  • rendering/RenderBlock.h: Added WordMeasures parameter to few methods.
  • rendering/RenderBlockLineLayout.cpp:

(WordMeasurement): Added new class to hold measurement information.
(WebCore::setLogicalWidthForTextRun): This is where we compute the run width using the
cached information.
(WebCore::RenderBlock::computeInlineDirectionPositionsForLine): Added wordMeasures parameter.
(WebCore::RenderBlock::createLineBoxesFromBidiRuns): Added wordMeasures parameter.
(WebCore::RenderBlock::layoutRunsAndFloatsInRange): Added declaration of the WordMeasures
vector and its use.
(WebCore::textWidth): Added fallbackFonts parameter, since now we only measure once.
(WebCore::RenderBlock::LineBreaker::nextLineBreak): This method has been modified to collect
the measurements of the individual words and add them to the vector.

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r130850 r130851  
     12012-10-09  Enrica Casucci  <enrica@apple.com>
     2
     3        Only measure text once instead of twice when performing line layout.
     4        https://bugs.webkit.org/show_bug.cgi?id=98317
     5        <rdar://problem/12080821>
     6
     7        Reviewed by Dan Bernstein.
     8
     9        Since we are measuring each word to find out where the line break should occur,
     10        we should cache that information to avoid measuring the run again when
     11        creating the line box. The bulk of the change is in nextLineBreak, where
     12        the measurements are collected and placed in a vector so that they can
     13        be consumed in setLogicalWidthForTextRun where we used to measure the
     14        text one more time.
     15        Each entry in the vector is a WordMeasurement object that contains information
     16        about the start and end offset in the run, the renderer, the measured width
     17        and, possibly, a list of fallback fonts.
     18        When we need to compute the width of the run to create the line box, we add
     19        all the measurements for the given renderer in the run to get the total width.
     20        This optiomization is currently disabled for platforms using HarfBuzz.
     21
     22        * platform/graphics/Font.cpp:
     23        (WebCore::Font::width): Added fallback fonts parameter.
     24        * platform/graphics/Font.h:
     25        (Font): Added fallback fonts parameter to the width static member function.
     26        This method is called when we compute the width using TextLayout.
     27        * platform/graphics/mac/ComplexTextController.cpp:
     28        (WebCore::TextLayout::width): Added fallback fonts parameter.
     29        (WebCore::Font::width):
     30        (WebCore::ComplexTextController::advance):
     31        * platform/graphics/mac/ComplexTextController.h:
     32        (ComplexTextController): Added fallback fonts parameter to advance method.
     33        * rendering/RenderBlock.h: Added WordMeasures parameter to few methods.
     34        * rendering/RenderBlockLineLayout.cpp:
     35        (WordMeasurement): Added new class to hold measurement information.
     36        (WebCore::setLogicalWidthForTextRun): This is where we compute the run width using the
     37        cached information.
     38        (WebCore::RenderBlock::computeInlineDirectionPositionsForLine): Added wordMeasures parameter.
     39        (WebCore::RenderBlock::createLineBoxesFromBidiRuns): Added wordMeasures parameter.
     40        (WebCore::RenderBlock::layoutRunsAndFloatsInRange): Added declaration of the WordMeasures
     41        vector and its use.
     42        (WebCore::textWidth): Added fallbackFonts parameter, since now we only measure once.
     43        (WebCore::RenderBlock::LineBreaker::nextLineBreak): This method has been modified to collect
     44        the measurements of the individual words and add them to the vector.
     45
    1462012-10-09  Andreas Kling  <kling@webkit.org>
    247
  • trunk/Source/WebCore/platform/graphics/Font.cpp

    r130820 r130851  
    221221}
    222222
    223 float Font::width(TextLayout&, unsigned, unsigned)
     223float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*>*)
    224224{
    225225    ASSERT_NOT_REACHED();
  • trunk/Source/WebCore/platform/graphics/Font.h

    r130820 r130851  
    106106    PassOwnPtr<TextLayout> createLayout(RenderText*, float xPos, bool collapseWhiteSpace) const;
    107107    static void deleteLayout(TextLayout*);
    108     static float width(TextLayout&, unsigned from, unsigned len);
     108    static float width(TextLayout&, unsigned from, unsigned len, HashSet<const SimpleFontData*>* fallbackFonts = 0);
    109109
    110110    int offsetForPosition(const TextRun&, float position, bool includePartialGlyphs) const;
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp

    r130820 r130851  
    5555    }
    5656
    57     float width(unsigned from, unsigned len)
     57    float width(unsigned from, unsigned len, HashSet<const SimpleFontData*>* fallbackFonts)
    5858    {
    59         m_controller->advance(from, 0, ByWholeGlyphs);
     59        m_controller->advance(from, 0, ByWholeGlyphs, fallbackFonts);
    6060        float beforeWidth = m_controller->runWidthSoFar();
    6161        if (m_font.wordSpacing() && from && Font::treatAsSpace(m_run[from]))
    6262            beforeWidth += m_font.wordSpacing();
    63         m_controller->advance(from + len, 0, ByWholeGlyphs);
     63        m_controller->advance(from + len, 0, ByWholeGlyphs, fallbackFonts);
    6464        float afterWidth = m_controller->runWidthSoFar();
    6565        return afterWidth - beforeWidth;
     
    9595}
    9696
    97 float Font::width(TextLayout& layout, unsigned from, unsigned len)
    98 {
    99     return layout.width(from, len);
     97float Font::width(TextLayout& layout, unsigned from, unsigned len, HashSet<const SimpleFontData*>* fallbackFonts)
     98{
     99    return layout.width(from, len, fallbackFonts);
    100100}
    101101
     
    461461}
    462462
    463 void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle)
     463void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle, HashSet<const SimpleFontData*>* fallbackFonts)
    464464{
    465465    if (static_cast<int>(offset) > m_end)
     
    486486        unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
    487487        unsigned k = leftmostGlyph + g;
     488        if (fallbackFonts && complexTextRun.fontData() != m_font.primaryFont())
     489            fallbackFonts->add(complexTextRun.fontData());
    488490
    489491        while (m_glyphInCurrentRun < glyphCount) {
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h

    r130820 r130851  
    5555
    5656    // Advance and emit glyphs up to the specified character.
    57     void advance(unsigned to, GlyphBuffer* = 0, GlyphIterationStyle = IncludePartialGlyphs);
     57    void advance(unsigned to, GlyphBuffer* = 0, GlyphIterationStyle = IncludePartialGlyphs, HashSet<const SimpleFontData*>* fallbackFonts = 0);
    5858
    5959    // Compute the character offset for a given x coordinate.
  • trunk/Source/WebCore/rendering/RenderBlock.h

    r130820 r130851  
    5454class RenderRubyRun;
    5555class TextLayout;
     56class WordMeasurement;
    5657
    5758template <class Iterator, class Run> class BidiResolver;
     
    6364typedef WTF::HashMap<const RenderBlock*, TrackedRendererListHashSet*> TrackedDescendantsMap;
    6465typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> TrackedContainerMap;
     66typedef Vector<WordMeasurement, 64> WordMeasurements;
    6567
    6668enum CaretType { CursorCaret, DragCaret };
     
    730732        }
    731733
    732         InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines);
     734        InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);
    733735
    734736        bool lineWasHyphenated() { return m_hyphenated; }
     
    758760    void setMarginsForRubyRun(BidiRun*, RenderRubyRun*, RenderObject*, const LineInfo&);
    759761
    760     void computeInlineDirectionPositionsForLine(RootInlineBox*, const LineInfo&, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
     762    void computeInlineDirectionPositionsForLine(RootInlineBox*, const LineInfo&, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&, WordMeasurements&);
    761763    void computeBlockDirectionPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
    762764    void deleteEllipsisLineBoxes();
     
    964966
    965967    // Helper function for layoutInlineChildren()
    966     RootInlineBox* createLineBoxesFromBidiRuns(BidiRunList<BidiRun>&, const InlineIterator& end, LineInfo&, VerticalPositionCache&, BidiRun* trailingSpaceRun);
     968    RootInlineBox* createLineBoxesFromBidiRuns(BidiRunList<BidiRun>&, const InlineIterator& end, LineInfo&, VerticalPositionCache&, BidiRun* trailingSpaceRun, WordMeasurements&);
    967969    void layoutRunsAndFloats(LineLayoutState&, bool hasInlineChild);
    968970    void layoutRunsAndFloatsInRange(LineLayoutState&, InlineBidiResolver&, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines);
  • trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp

    r130820 r130851  
    693693}
    694694
     695class WordMeasurement {
     696public:
     697    WordMeasurement()
     698        : renderer(0)
     699        , width(0)
     700        , startOffset(0)
     701        , endOffset(0)
     702    {
     703    }
     704   
     705    RenderText* renderer;
     706    float width;
     707    int startOffset;
     708    int endOffset;
     709    HashSet<const SimpleFontData*> fallbackFonts;
     710};
     711
    695712static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
    696                                    GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
    697 {
     713                                             GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
     714{
     715#if USE(HARFBUZZ_NG)
     716    UNUSED_PARAM(wordMeasurements);
     717#endif
    698718    HashSet<const SimpleFontData*> fallbackFonts;
    699719    GlyphOverflow glyphOverflow;
    700720   
     721    const Font& font = renderer->style(lineInfo.isFirstLine())->font();
    701722    // Always compute glyph overflow if the block's line-box-contain value is "glyphs".
    702723    if (lineBox->fitsToGlyphs()) {
     
    705726        bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading();
    706727        int baselineShift = lineBox->verticalPositionForBox(run->m_box, verticalPositionCache);
    707         int rootDescent = includeRootLine ? lineBox->renderer()->style(lineInfo.isFirstLine())->font().fontMetrics().descent() : 0;
    708         int rootAscent = includeRootLine ? lineBox->renderer()->style(lineInfo.isFirstLine())->font().fontMetrics().ascent() : 0;
    709         int boxAscent = renderer->style(lineInfo.isFirstLine())->font().fontMetrics().ascent() - baselineShift;
    710         int boxDescent = renderer->style(lineInfo.isFirstLine())->font().fontMetrics().descent() + baselineShift;
     728        int rootDescent = includeRootLine ? font.fontMetrics().descent() : 0;
     729        int rootAscent = includeRootLine ? font.fontMetrics().ascent() : 0;
     730        int boxAscent = font.fontMetrics().ascent() - baselineShift;
     731        int boxDescent = font.fontMetrics().descent() + baselineShift;
    711732        if (boxAscent > rootDescent ||  boxDescent > rootAscent)
    712733            glyphOverflow.computeBounds = true;
     
    718739        hyphenWidth = measureHyphenWidth(renderer, font);
    719740    }
    720     run->m_box->setLogicalWidth(renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow) + hyphenWidth);
     741    float measuredWidth = 0;
     742
     743#if !USE(HARFBUZZ_NG)
     744    bool kerningIsEnabled = font.typesettingFeatures() & Kerning;
     745   
     746    // Since we don't cache glyph overflows, we need to re-measure the run if
     747    // the style is linebox-contain: glyph.
     748   
     749    if (!lineBox->fitsToGlyphs() && renderer->canUseSimpleFontCodePath()) {
     750        int lastEndOffset = run->m_start;
     751        for (size_t i = 0, size = wordMeasurements.size(); i < size && lastEndOffset < run->m_stop; ++i) {
     752            const WordMeasurement& wordMeasurement = wordMeasurements[i];
     753            if (wordMeasurement.width <=0 || wordMeasurement.startOffset == wordMeasurement.endOffset)
     754                continue;
     755            if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
     756                continue;
     757
     758            lastEndOffset = wordMeasurement.endOffset;
     759            if (kerningIsEnabled && lastEndOffset == run->m_stop) {
     760                measuredWidth += renderer->width(wordMeasurement.startOffset, lastEndOffset - wordMeasurement.startOffset, xPos, lineInfo.isFirstLine());
     761                if (i > 0)
     762                    measuredWidth += renderer->style()->wordSpacing();
     763            } else
     764                measuredWidth += wordMeasurement.width;
     765            if (!wordMeasurement.fallbackFonts.isEmpty()) {
     766                HashSet<const SimpleFontData*>::const_iterator end = wordMeasurement.fallbackFonts.end();
     767                for (HashSet<const SimpleFontData*>::const_iterator it = wordMeasurement.fallbackFonts.begin(); it != end; ++it)
     768                    fallbackFonts.add(*it);
     769            }
     770        }
     771        if (measuredWidth && lastEndOffset != run->m_stop) {
     772            // If we don't have enough cached data, we'll measure the run again.
     773            measuredWidth = 0;
     774            fallbackFonts.clear();
     775        }
     776    }
     777#endif
     778
     779    if (!measuredWidth)
     780        measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
     781
     782    run->m_box->setLogicalWidth(measuredWidth + hyphenWidth);
    721783    if (!fallbackFonts.isEmpty()) {
    722784        ASSERT(run->m_box->isText());
     
    808870
    809871void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
    810                                                          GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
     872                                                         GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
    811873{
    812874    ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
     
    855917            }
    856918
    857             setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache);
     919            setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
    858920        } else {
    859921            isAfterExpansion = false;
     
    10821144
    10831145// This function constructs line boxes for all of the text runs in the resolver and computes their position.
    1084 RootInlineBox* RenderBlock::createLineBoxesFromBidiRuns(BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun)
     1146RootInlineBox* RenderBlock::createLineBoxesFromBidiRuns(BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
    10851147{
    10861148    if (!bidiRuns.runCount())
     
    11061168    // Now we position all of our text runs horizontally.
    11071169    if (!isSVGRootInlineBox)
    1108         computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache);
     1170        computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache, wordMeasurements);
    11091171   
    11101172    // Now position our text runs vertically.
     
    13521414        }
    13531415#endif
    1354         end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines);
     1416        WordMeasurements wordMeasurements;
     1417        end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
    13551418        if (resolver.position().atEnd()) {
    13561419            // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
     
    13941457
    13951458            LayoutUnit oldLogicalHeight = logicalHeight();
    1396             RootInlineBox* lineBox = createLineBoxesFromBidiRuns(bidiRuns, end, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun);
     1459            RootInlineBox* lineBox = createLineBoxesFromBidiRuns(bidiRuns, end, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements);
    13971460
    13981461            bidiRuns.deleteRuns();
     
    20522115}
    20532116
    2054 static inline float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, TextLayout* layout = 0)
    2055 {
     2117static ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>* fallbackFonts = 0, TextLayout* layout = 0)
     2118{
     2119    GlyphOverflow glyphOverflow;
    20562120    if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine())
    2057         return text->width(from, len, font, xPos);
     2121        return text->width(from, len, font, xPos, fallbackFonts, &glyphOverflow);
    20582122
    20592123    if (layout)
    2060         return Font::width(*layout, from, len);
     2124        return Font::width(*layout, from, len, fallbackFonts);
    20612125
    20622126    TextRun run = RenderBlock::constructTextRun(text, font, text->characters() + from, len, text->style());
     
    20672131    run.setTabSize(!collapseWhiteSpace, text->style()->tabSize());
    20682132    run.setXPos(xPos);
    2069     return font.width(run);
     2133    return font.width(run, fallbackFonts, &glyphOverflow);
    20702134}
    20712135
     
    22212285}
    22222286
    2223 InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines)
     2287InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
    22242288{
    22252289    reset();
     
    24392503            float wordSpacing = currentStyle->wordSpacing();
    24402504            float lastSpaceWordSpacing = 0;
     2505            float wordSpacingForWordMeasurement = 0;
    24412506
    24422507            float wrapW = width.uncommittedWidth() + inlineLogicalWidth(current.m_obj, !appliedStartWidth, true);
     
    24942559                    wrapW += charWidth;
    24952560                    bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && current.m_pos + 1 < t->textLength() && U16_IS_TRAIL(t->characters()[current.m_pos + 1]);
    2496                     charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, textLayout);
     2561                    charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, 0, textLayout);
    24972562                    midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth();
    24982563                }
     
    25092574                            ignoringSpaces = false;
    25102575                            lastSpaceWordSpacing = 0;
     2576                            wordSpacingForWordMeasurement = 0;
    25112577                            lastSpace = current.m_pos; // e.g., "Foo    goo", don't add in any of the ignored spaces.
    25122578                            addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
     
    25182584                    }
    25192585
     2586                    wordMeasurements.grow(wordMeasurements.size() + 1);
     2587                    WordMeasurement& wordMeasurement = wordMeasurements.last();
     2588                   
     2589                    wordMeasurement.renderer = t;
     2590                    wordMeasurement.endOffset = current.m_pos;
     2591                    wordMeasurement.startOffset = lastSpace;
     2592                   
    25202593                    float additionalTmpW;
    25212594                    if (wordTrailingSpaceWidth && currentCharacterIsSpace)
    2522                         additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) - wordTrailingSpaceWidth + lastSpaceWordSpacing;
     2595                        additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;
    25232596                    else
    2524                         additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + lastSpaceWordSpacing;
     2597                        additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
     2598
     2599                    wordMeasurement.width = additionalTmpW + wordSpacingForWordMeasurement;
     2600                    additionalTmpW += lastSpaceWordSpacing;
    25252601                    width.addUncommittedWidth(additionalTmpW);
    25262602                    if (!appliedStartWidth) {
     
    25292605                    }
    25302606
    2531                     applyWordSpacing =  wordSpacing && currentCharacterIsSpace;
     2607                    applyWordSpacing = wordSpacing && currentCharacterIsSpace;
    25322608
    25332609                    if (!width.committedWidth() && autoWrap && !width.fitsOnLine())
     
    25392615                        bool lineWasTooWide = false;
    25402616                        if (width.fitsOnLine() && currentCharacterIsWS && currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {
    2541                             float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + (applyWordSpacing ? wordSpacing : 0);
     2617                            float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);
    25422618                            // Check if line is too big even without the extra space
    25432619                            // at the end of the line. If it is not, do nothing.
     
    25652641                                lBreak.increment();
    25662642                                lineInfo.setPreviousLineBrokeCleanly(true);
     2643                                wordMeasurement.endOffset = lBreak.m_pos;
    25672644                            }
    25682645                            if (lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos - 1] == softHyphen && style->hyphens() != HyphensNone)
    25692646                                m_hyphenated = true;
     2647                            if (lBreak.m_pos && lBreak.m_pos != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
     2648                                if (charWidth) {
     2649                                    wordMeasurement.endOffset = lBreak.m_pos;
     2650                                    wordMeasurement.width = charWidth;
     2651                                }
     2652                            }
    25702653                            goto end; // Didn't fit. Jump to the end.
    25712654                        } else {
     
    26102693                    if (betweenWords) {
    26112694                        lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
     2695                        wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0;
    26122696                        lastSpace = current.m_pos;
    26132697                    }
     
    26322716                    ignoringSpaces = false;
    26332717                    lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
     2718                    wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0;
    26342719                    lastSpace = current.m_pos; // e.g., "Foo    goo", don't add in any of the ignored spaces.
    26352720                    addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
     
    26642749            }
    26652750
     2751            wordMeasurements.grow(wordMeasurements.size() + 1);
     2752            WordMeasurement& wordMeasurement = wordMeasurements.last();
     2753            wordMeasurement.renderer = t;
     2754
    26662755            // IMPORTANT: current.m_pos is > length here!
    2667             float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + lastSpaceWordSpacing;
     2756            float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
     2757            wordMeasurement.startOffset = lastSpace;
     2758            wordMeasurement.endOffset = current.m_pos;
     2759            wordMeasurement.width = ignoringSpaces ? 0 : additionalTmpW + wordSpacingForWordMeasurement;
     2760            additionalTmpW += lastSpaceWordSpacing;
    26682761            width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(current.m_obj, !appliedStartWidth, includeEndWidth));
    26692762            includeEndWidth = false;
Note: See TracChangeset for help on using the changeset viewer.