Changeset 136729 in webkit


Ignore:
Timestamp:
Dec 5, 2012 12:17:30 PM (11 years ago)
Author:
commit-queue@webkit.org
Message:

[CSS Exclusions] Enable shape-inside for multiple-segment polygons
https://bugs.webkit.org/show_bug.cgi?id=91878

Patch by Bear Travis <betravis@adobe.com> on 2012-12-05
Reviewed by David Hyatt.

Source/WebCore:

Patch adding support for multiple-segment polygons for shape-insides from
the CSS Exclusions specification. The layout code has been modified to first
support dividing text into multiple segments per line, and then to lay out
multiple segments per line box.

Tests: fast/exclusions/shape-inside/shape-inside-multiple-segments-001.html

fast/exclusions/shape-inside/shape-inside-multiple-segments-002.html
fast/exclusions/shape-inside/shape-inside-multiple-segments-003.html
fast/exclusions/shape-inside/shape-inside-multiple-segments-004.html

  • platform/text/BidiResolver.h:

(WebCore::BidiCharacterRun::BidiCharacterRun):
(BidiCharacterRun): Added a 'startsSegment' bitfield to track whether a
run begins a new segment. The field is here, rather than in BidiRun, in
order to save space. See Bug 100173.

  • rendering/BidiRun.h:

(WebCore::BidiRun::BidiRun):
(BidiRun): Set the initial value for 'startsSegment'.

  • rendering/ExclusionShapeInsideInfo.cpp:

(WebCore::ExclusionShapeInsideInfo::computeSegmentsForLine): Clear the
segment ranges when computing segments for a new line.

  • rendering/ExclusionShapeInsideInfo.h:

(LineSegmentRange): Added a new type to track segment offsets.
(WebCore::ExclusionShapeInsideInfo::segmentRanges): Added a getter for
the line segment ranges vector.

  • rendering/InlineFlowBox.cpp:

(WebCore::InlineFlowBox::placeBoxesInInlineDirection): Modified to call
a refactored box placement algorithm that takes a beginning and end position.
(WebCore::InlineFlowBox::placeBoxRangeInInlineDirection): Similar to the
placeBoxes method, but takes an end position that may occur before the end
of the line.

  • rendering/RenderBlock.cpp:

(WebCore::RenderBlock::exclusionShapeInsideInfo): Factored out calls
to ExclusionShapeInsideInfo to the .cpp file, as ExclusionShapeInsideInfo
requires InlineIterator.h, which would create a circular dependency in
ExclusionShapeInsideInfo.h.

  • rendering/RenderBlock.h:

(WebCore::RenderBlock::exclusionShapeInsideInfo): Modified to call
exclusionShapeInsideInfo to be non-inline.

  • rendering/RenderBlockLineLayout.cpp:

(WebCore::LineWidth::LineWidth): LineWidth now uses the number of computed
segmentRanges to determine which LineSegment to use when calculating width.
(WebCore::RenderBlock::createLineBoxes): Now takes a boolean to determine
whether or not it can share the same parentBox as its siblings (segments
must be able to position themselves separately in the RootInlineBox).
(WebCore::RenderBlock::constructLine):
(WebCore::computeExpansionForJustifiedText): Do include runs that start new
segments when calculating justification for the current segment.
(WebCore::RenderBlock::computeInlineDirectionPositionsForLine): Modified to
use the computeInlineDirectionPositionsForSegment, which can position
multiple segments of text per line.
(WebCore::RenderBlock::computeInlineDirectionPositionsForSegment): Positions
the given segment of text and calculates its layout offsets.
(WebCore::constructBidiRuns): Modified some variables from 'endOfLine' to 'endOfSegment'.
(WebCore::constructBidiRunsForLine): Construct the bidi runs for each segment in
the given line.
(WebCore::RenderBlock::layoutRunsAndFloatsInRange): Call constructBidiRunsForLine.
(WebCore::RenderBlock::LineBreaker::nextLineBreak): Moved the line breaking code
to break segments, with nextLineBreak iterating over segment breaks for the entire line.
(WebCore::RenderBlock::LineBreaker::nextSegmentBreak): Calculates how much text a
segment can hold. This code was originally in nextLineBreak.

LayoutTests:

Adding tests for multiple segment polygons. These tests make sure that text can be
properly broken up into multiple segments per line to fit into a shape-inside.

  • fast/exclusions/shape-inside/shape-inside-multiple-segments-001-expected.html: Added.
  • fast/exclusions/shape-inside/shape-inside-multiple-segments-001.html: Added.
  • fast/exclusions/shape-inside/shape-inside-multiple-segments-002-expected.html: Added.
  • fast/exclusions/shape-inside/shape-inside-multiple-segments-002.html: Added.
  • fast/exclusions/shape-inside/shape-inside-multiple-segments-003-expected.html: Added.
  • fast/exclusions/shape-inside/shape-inside-multiple-segments-003.html: Added.
  • fast/exclusions/shape-inside/shape-inside-multiple-segments-004-expected.html: Added.
  • fast/exclusions/shape-inside/shape-inside-multiple-segments-004.html: Added.
Location:
trunk
Files:
9 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r136726 r136729  
     12012-12-05  Bear Travis  <betravis@adobe.com>
     2
     3        [CSS Exclusions] Enable shape-inside for multiple-segment polygons
     4        https://bugs.webkit.org/show_bug.cgi?id=91878
     5
     6        Reviewed by David Hyatt.
     7
     8        Adding tests for multiple segment polygons. These tests make sure that text can be
     9        properly broken up into multiple segments per line to fit into a shape-inside.
     10
     11        * fast/exclusions/shape-inside/shape-inside-multiple-segments-001-expected.html: Added.
     12        * fast/exclusions/shape-inside/shape-inside-multiple-segments-001.html: Added.
     13        * fast/exclusions/shape-inside/shape-inside-multiple-segments-002-expected.html: Added.
     14        * fast/exclusions/shape-inside/shape-inside-multiple-segments-002.html: Added.
     15        * fast/exclusions/shape-inside/shape-inside-multiple-segments-003-expected.html: Added.
     16        * fast/exclusions/shape-inside/shape-inside-multiple-segments-003.html: Added.
     17        * fast/exclusions/shape-inside/shape-inside-multiple-segments-004-expected.html: Added.
     18        * fast/exclusions/shape-inside/shape-inside-multiple-segments-004.html: Added.
     19
    1202012-12-05  Roger Fong  <roger_fong@apple.com>
    221
  • trunk/Source/WebCore/ChangeLog

    r136728 r136729  
     12012-12-05  Bear Travis  <betravis@adobe.com>
     2
     3        [CSS Exclusions] Enable shape-inside for multiple-segment polygons
     4        https://bugs.webkit.org/show_bug.cgi?id=91878
     5
     6        Reviewed by David Hyatt.
     7
     8        Patch adding support for multiple-segment polygons for shape-insides from
     9        the CSS Exclusions specification. The layout code has been modified to first
     10        support dividing text into multiple segments per line, and then to lay out
     11        multiple segments per line box.
     12
     13        Tests:  fast/exclusions/shape-inside/shape-inside-multiple-segments-001.html
     14                fast/exclusions/shape-inside/shape-inside-multiple-segments-002.html
     15                fast/exclusions/shape-inside/shape-inside-multiple-segments-003.html
     16                fast/exclusions/shape-inside/shape-inside-multiple-segments-004.html
     17
     18        * platform/text/BidiResolver.h:
     19        (WebCore::BidiCharacterRun::BidiCharacterRun):
     20        (BidiCharacterRun): Added a 'startsSegment' bitfield to track whether a
     21        run begins a new segment. The field is here, rather than in BidiRun, in
     22        order to save space. See Bug 100173.
     23        * rendering/BidiRun.h:
     24        (WebCore::BidiRun::BidiRun):
     25        (BidiRun): Set the initial value for 'startsSegment'.
     26        * rendering/ExclusionShapeInsideInfo.cpp:
     27        (WebCore::ExclusionShapeInsideInfo::computeSegmentsForLine): Clear the
     28        segment ranges when computing segments for a new line.
     29        * rendering/ExclusionShapeInsideInfo.h:
     30        (LineSegmentRange): Added a new type to track segment offsets.
     31        (WebCore::ExclusionShapeInsideInfo::segmentRanges): Added a getter for
     32        the line segment ranges vector.
     33        * rendering/InlineFlowBox.cpp:
     34        (WebCore::InlineFlowBox::placeBoxesInInlineDirection): Modified to call
     35        a refactored box placement algorithm that takes a beginning and end position.
     36        (WebCore::InlineFlowBox::placeBoxRangeInInlineDirection): Similar to the
     37        placeBoxes method, but takes an end position that may occur before the end
     38        of the line.
     39        * rendering/RenderBlock.cpp:
     40        (WebCore::RenderBlock::exclusionShapeInsideInfo): Factored out calls
     41        to ExclusionShapeInsideInfo to the .cpp file, as ExclusionShapeInsideInfo
     42        requires InlineIterator.h, which would create a circular dependency in
     43        ExclusionShapeInsideInfo.h.
     44        * rendering/RenderBlock.h:
     45        (WebCore::RenderBlock::exclusionShapeInsideInfo): Modified to call
     46        exclusionShapeInsideInfo to be non-inline.
     47        * rendering/RenderBlockLineLayout.cpp:
     48        (WebCore::LineWidth::LineWidth): LineWidth now uses the number of computed
     49        segmentRanges to determine which LineSegment to use when calculating width.
     50        (WebCore::RenderBlock::createLineBoxes): Now takes a boolean to determine
     51        whether or not it can share the same parentBox as its siblings (segments
     52        must be able to position themselves separately in the RootInlineBox).
     53        (WebCore::RenderBlock::constructLine):
     54        (WebCore::computeExpansionForJustifiedText): Do include runs that start new
     55        segments when calculating justification for the current segment.
     56        (WebCore::RenderBlock::computeInlineDirectionPositionsForLine): Modified to
     57        use the computeInlineDirectionPositionsForSegment, which can position
     58        multiple segments of text per line.
     59        (WebCore::RenderBlock::computeInlineDirectionPositionsForSegment): Positions
     60        the given segment of text and calculates its layout offsets.
     61        (WebCore::constructBidiRuns): Modified some variables from 'endOfLine' to 'endOfSegment'.
     62        (WebCore::constructBidiRunsForLine): Construct the bidi runs for each segment in
     63        the given line.
     64        (WebCore::RenderBlock::layoutRunsAndFloatsInRange): Call constructBidiRunsForLine.
     65        (WebCore::RenderBlock::LineBreaker::nextLineBreak): Moved the line breaking code
     66        to break segments, with nextLineBreak iterating over segment breaks for the entire line.
     67        (WebCore::RenderBlock::LineBreaker::nextSegmentBreak): Calculates how much text a
     68        segment can hold. This code was originally in nextLineBreak.
     69
    1702012-12-05  Stephen White  <senorblanco@chromium.org>
    271
  • trunk/Source/WebCore/platform/text/BidiResolver.h

    r133713 r136729  
    148148
    149149    // Do not add anything apart from bitfields until after m_next. See https://bugs.webkit.org/show_bug.cgi?id=100173
    150     bool m_override:1;
    151     bool m_hasHyphen:1; // Used by BidiRun subclass which is a layering violation but enables us to save 8 bytes per object on 64-bit.
     150    bool m_override : 1;
     151    bool m_hasHyphen : 1; // Used by BidiRun subclass which is a layering violation but enables us to save 8 bytes per object on 64-bit.
     152#if ENABLE(CSS_EXCLUSIONS)
     153    bool m_startsSegment : 1; // Same comment as m_hasHyphen.
     154#endif
    152155    unsigned char m_level;
    153156    BidiCharacterRun* m_next;
  • trunk/Source/WebCore/rendering/BidiRun.h

    r133713 r136729  
    4040        , m_box(0)
    4141    {
    42         m_hasHyphen = false; // Stored in base class to save space.
     42        // Stored in base class to save space.
     43        m_hasHyphen = false;
     44#if ENABLE(CSS_EXCLUSIONS)
     45        m_startsSegment = false;
     46#endif
    4347    }
    4448
  • trunk/Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp

    r135314 r136729  
    110110    m_lineHeight = lineHeight;
    111111    m_segments.clear();
     112    m_segmentRanges.clear();
    112113
    113114    if (lineOverlapsShapeBounds()) {
  • trunk/Source/WebCore/rendering/ExclusionShapeInsideInfo.h

    r133779 r136729  
    3535#include "ExclusionShape.h"
    3636#include "FloatRect.h"
     37#include "InlineIterator.h"
    3738#include "LayoutUnit.h"
    3839#include <wtf/OwnPtr.h>
     
    4344
    4445class RenderBlock;
     46
     47struct LineSegmentRange {
     48    InlineIterator start;
     49    InlineIterator end;
     50    LineSegmentRange(InlineIterator start, InlineIterator end)
     51        : start(start)
     52        , end(end)
     53    {
     54    }
     55};
     56typedef Vector<LineSegmentRange> SegmentRangeList;
    4557
    4658class ExclusionShapeInsideInfo {
     
    6779        ASSERT(hasSegments());
    6880        return m_segments;
     81    }
     82    SegmentRangeList& segmentRanges() { return m_segmentRanges; }
     83    const SegmentRangeList& segmentRanges() const { return m_segmentRanges; }
     84    const LineSegment* currentSegment() const
     85    {
     86        if (!hasSegments())
     87            return 0;
     88        ASSERT(m_segmentRanges.size() < m_segments.size());
     89        return &m_segments[m_segmentRanges.size()];
    6990    }
    7091    bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight);
     
    98119
    99120    SegmentList m_segments;
     121    SegmentRangeList m_segmentRanges;
    100122    bool m_shapeSizeDirty;
    101123};
  • trunk/Source/WebCore/rendering/InlineFlowBox.cpp

    r136640 r136729  
    370370{
    371371    // Set our x position.
    372     setLogicalLeft(logicalLeft);
    373  
     372    beginPlacingBoxRangesInInlineDirection(logicalLeft);
     373
    374374    float startLogicalLeft = logicalLeft;
    375375    logicalLeft += borderLogicalLeft() + paddingLogicalLeft();
     
    378378    float maxLogicalRight = logicalLeft;
    379379
    380     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
     380    placeBoxRangeInInlineDirection(firstChild(), 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap);
     381
     382    logicalLeft += borderLogicalRight() + paddingLogicalRight();
     383    endPlacingBoxRangesInInlineDirection(startLogicalLeft, logicalLeft, minLogicalLeft, maxLogicalRight);
     384    return logicalLeft;
     385}
     386
     387float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
     388{
     389    for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) {
    381390        if (curr->renderer()->isText()) {
    382391            InlineTextBox* text = toInlineTextBox(curr);
     
    430439        }
    431440    }
    432 
    433     logicalLeft += borderLogicalRight() + paddingLogicalRight();
    434     setLogicalWidth(logicalLeft - startLogicalLeft);
    435     if (knownToHaveNoOverflow() && (minLogicalLeft < startLogicalLeft || maxLogicalRight > logicalLeft))
    436         clearKnownToHaveNoOverflow();
    437441    return logicalLeft;
    438442}
  • trunk/Source/WebCore/rendering/InlineFlowBox.h

    r135750 r136729  
    174174    LayoutUnit getFlowSpacingLogicalWidth();
    175175    float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
     176    float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
     177    void beginPlacingBoxRangesInInlineDirection(float logicalLeft) { setLogicalLeft(logicalLeft); }
     178    void endPlacingBoxRangesInInlineDirection(float logicalLeft, float logicalRight, float minLogicalLeft, float maxLogicalRight)
     179    {
     180        setLogicalWidth(logicalRight - logicalLeft);
     181        if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight))
     182            clearKnownToHaveNoOverflow();
     183    }
     184
    176185    void computeLogicalBoxHeights(RootInlineBox*, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom,
    177186                                  int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
  • trunk/Source/WebCore/rendering/RenderBlock.cpp

    r136288 r136729  
    13981398
    13991399#if ENABLE(CSS_EXCLUSIONS)
     1400ExclusionShapeInsideInfo* RenderBlock::exclusionShapeInsideInfo() const
     1401{
     1402    return style()->shapeInside() && ExclusionShapeInsideInfo::isExclusionShapeInsideInfoEnabledForRenderBlock(this) ? ExclusionShapeInsideInfo::exclusionShapeInsideInfoForRenderBlock(this) : 0;
     1403}
     1404
    14001405void RenderBlock::updateExclusionShapeInsideInfoAfterStyleChange(const ExclusionShapeValue* shapeInside, const ExclusionShapeValue* oldShapeInside)
    14011406{
  • trunk/Source/WebCore/rendering/RenderBlock.h

    r136288 r136729  
    3636
    3737#if ENABLE(CSS_EXCLUSIONS)
    38 #include "ExclusionShapeInsideInfo.h"
    3938#include "ExclusionShapeValue.h"
    4039#endif
     
    5453class LineInfo;
    5554class RenderRubyRun;
     55#if ENABLE(CSS_EXCLUSIONS)
     56class BasicShape;
     57class ExclusionShapeInsideInfo;
     58#endif
    5659class TextLayout;
    5760class WordMeasurement;
     
    426429
    427430#if ENABLE(CSS_EXCLUSIONS)
    428     ExclusionShapeInsideInfo* exclusionShapeInsideInfo() const
    429     {
    430         return style()->shapeInside() && ExclusionShapeInsideInfo::isExclusionShapeInsideInfoEnabledForRenderBlock(this) ? ExclusionShapeInsideInfo::exclusionShapeInsideInfoForRenderBlock(this) : 0;
    431     }
     431    ExclusionShapeInsideInfo* exclusionShapeInsideInfo() const;
    432432#endif
    433433
     
    764764        void reset();
    765765       
     766        InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);
    766767        void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
    767768        void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&);
     
    780781   
    781782    RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&);
    782     InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox);
     783    InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox, bool startsNewSegment);
    783784
    784785    void setMarginsForRubyRun(BidiRun*, RenderRubyRun*, RenderObject*, const LineInfo&);
    785786
     787    BidiRun* computeInlineDirectionPositionsForSegment(RootInlineBox*, const LineInfo&, ETextAlign, float& logicalLeft,
     788        float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache&, WordMeasurements&);
    786789    void computeInlineDirectionPositionsForLine(RootInlineBox*, const LineInfo&, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&, WordMeasurements&);
    787790    void computeBlockDirectionPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
  • trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp

    r136034 r136729  
    8989#if ENABLE(CSS_EXCLUSIONS)
    9090        ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo(m_block);
    91         // FIXME: Bug 91878: Add support for multiple segments, currently we only support one
    92         if (exclusionShapeInsideInfo && exclusionShapeInsideInfo->hasSegments())
    93             m_segment = &exclusionShapeInsideInfo->segments()[0];
     91        if (exclusionShapeInsideInfo)
     92            m_segment = exclusionShapeInsideInfo->currentSegment();
    9493#endif
    9594        updateAvailableWidth();
     
    451450}
    452451
    453 InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox)
     452InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox, bool startNewSegment)
    454453{
    455454    // See if we have an unconstructed line box for this object that is also
     
    474473        bool constructedNewBox = false;
    475474        bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
    476         bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox);
     475        bool mustCreateBoxesToRoot = startNewSegment && !(parentBox && parentBox->isRootInlineBox());
     476        bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox) && !mustCreateBoxesToRoot;
    477477        if (allowedToConstructNewBox && !canUseExistingParentBox) {
    478478            // We need to make a new box for this render object.  Once
     
    571571        // If we have no parent box yet, or if the run is not simply a sibling,
    572572        // then we need to construct inline boxes as necessary to properly enclose the
    573         // run's inline box.
    574         if (!parentBox || parentBox->renderer() != r->m_object->parent())
     573        // run's inline box. Segments can only be siblings at the root level, as
     574        // they are positioned separately.
     575#if ENABLE(CSS_EXCLUSIONS)
     576        bool runStartsSegment = r->m_startsSegment;
     577#else
     578        bool runStartsSegment = false;
     579#endif
     580        if (!parentBox || parentBox->renderer() != r->m_object->parent() || runStartsSegment)
    575581            // Create new inline boxes all the way back to the appropriate insertion point.
    576             parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box);
     582            parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box, runStartsSegment);
    577583        else {
    578584            // Append the inline box to this line.
     
    809815    size_t i = 0;
    810816    for (BidiRun* r = firstRun; r; r = r->next()) {
     817#if ENABLE(CSS_EXCLUSIONS)
     818        // This method is called once per segment, do not move past the current segment.
     819        if (r->m_startsSegment)
     820            break;
     821#endif
    811822        if (!r->m_box || r == trailingSpaceRun)
    812823            continue;
     
    884895    // box is only affected if it is the first child of its parent element."
    885896    bool firstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->firstChild() != this);
    886     float logicalLeft = pixelSnappedLogicalLeftOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight);
    887     float logicalRight = pixelSnappedLogicalRightOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight);
     897    float lineLogicalLeft = pixelSnappedLogicalLeftOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight);
     898    float lineLogicalRight = pixelSnappedLogicalRightOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight);
     899    float availableLogicalWidth;
     900    bool needsWordSpacing;
    888901#if ENABLE(CSS_EXCLUSIONS)
    889902    ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo(this);
    890903    if (exclusionShapeInsideInfo && exclusionShapeInsideInfo->hasSegments()) {
    891         logicalLeft = max<float>(roundToInt(exclusionShapeInsideInfo->segments()[0].logicalLeft), logicalLeft);
    892         logicalRight = min<float>(floorToInt(exclusionShapeInsideInfo->segments()[0].logicalRight), logicalRight);
     904        BidiRun* segmentStart = firstRun;
     905        const SegmentList& segments = exclusionShapeInsideInfo->segments();
     906        float logicalLeft = max<float>(roundToInt(segments[0].logicalLeft), lineLogicalLeft);
     907        float logicalRight = min<float>(floorToInt(segments[0].logicalRight), lineLogicalRight);
     908        float startLogicalLeft = logicalLeft;
     909        float endLogicalRight = logicalLeft;
     910        float minLogicalLeft = logicalLeft;
     911        float maxLogicalRight = logicalLeft;
     912        lineBox->beginPlacingBoxRangesInInlineDirection(logicalLeft);
     913        for (size_t i = 0; i < segments.size(); i++) {
     914            if (i) {
     915                logicalLeft = max<float>(roundToInt(segments[i].logicalLeft), lineLogicalLeft);
     916                logicalRight = min<float>(floorToInt(segments[i].logicalRight), lineLogicalRight);
     917            }
     918            availableLogicalWidth = logicalRight - logicalLeft;
     919            BidiRun* newSegmentStart = computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, logicalLeft, availableLogicalWidth, segmentStart, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
     920            needsWordSpacing = false;
     921            endLogicalRight = lineBox->placeBoxRangeInInlineDirection(segmentStart->m_box, newSegmentStart ? newSegmentStart->m_box : 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap);
     922            if (!newSegmentStart || !newSegmentStart->next())
     923                break;
     924            ASSERT(newSegmentStart->m_startsSegment);
     925            // Discard the empty segment start marker bidi runs
     926            segmentStart = newSegmentStart->next();
     927        }
     928        lineBox->endPlacingBoxRangesInInlineDirection(startLogicalLeft, endLogicalRight, minLogicalLeft, maxLogicalRight);
     929        return;
    893930    }
    894931#endif
    895     float availableLogicalWidth = logicalRight - logicalLeft;
    896 
     932    availableLogicalWidth = lineLogicalRight - lineLogicalLeft;
     933    computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, lineLogicalLeft, availableLogicalWidth, firstRun,  trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
     934    // The widths of all runs are now known. We can now place every inline box (and
     935    // compute accurate widths for the inline flow boxes).
     936    needsWordSpacing = false;
     937    lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing, textBoxDataMap);
     938}
     939
     940BidiRun* RenderBlock::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo& lineInfo, ETextAlign textAlign, float& logicalLeft,
     941    float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache,
     942    WordMeasurements& wordMeasurements)
     943{
    897944    bool needsWordSpacing = false;
    898945    float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
     
    902949    RenderObject* previousObject = 0;
    903950
    904     for (BidiRun* r = firstRun; r; r = r->next()) {
     951    BidiRun* r = firstRun;
     952    for (; r; r = r->next()) {
     953#if ENABLE(CSS_EXCLUSIONS)
     954        // Once we have reached the start of the next segment, we have finished
     955        // computing the positions for this segment's contents.
     956        if (r->m_startsSegment)
     957            break;
     958#endif
    905959        if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak())
    906960            continue; // Positioned objects are only participating to figure out their
     
    9521006    computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
    9531007
    954     // The widths of all runs are now known.  We can now place every inline box (and
    955     // compute accurate widths for the inline flow boxes).
    956     needsWordSpacing = false;
    957     lineBox->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
     1008    return r;
    9581009}
    9591010
     
    11021153
    11031154// FIXME: BidiResolver should have this logic.
    1104 static inline void constructBidiRuns(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly)
     1155static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfRuns, VisualDirectionOverride override, bool previousLineBrokeCleanly)
    11051156{
    11061157    // FIXME: We should pass a BidiRunList into createBidiRunsForLine instead
     
    11081159    ASSERT(&topResolver.runs() == &bidiRuns);
    11091160    RenderObject* currentRoot = topResolver.position().root();
    1110     topResolver.createBidiRunsForLine(endOfLine, override, previousLineBrokeCleanly);
     1161    topResolver.createBidiRunsForLine(endOfRuns, override, previousLineBrokeCleanly);
    11111162
    11121163    while (!topResolver.isolatedRuns().isEmpty()) {
     
    11481199        // FIXME: What should end and previousLineBrokeCleanly be?
    11491200        // rniwa says previousLineBrokeCleanly is just a WinIE hack and could always be false here?
    1150         isolatedResolver.createBidiRunsForLine(endOfLine, NoVisualOverride, previousLineBrokeCleanly);
     1201        isolatedResolver.createBidiRunsForLine(endOfRuns, NoVisualOverride, previousLineBrokeCleanly);
    11511202        // Note that we do not delete the runs from the resolver.
    11521203        // We're not guaranteed to get any BidiRuns in the previous step. If we don't, we allow the placeholder
     
    11631214        }
    11641215    }
     1216}
     1217
     1218static inline void constructBidiRunsForLine(const RenderBlock* block, InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly)
     1219{
     1220#if !ENABLE(CSS_EXCLUSIONS)
     1221    UNUSED_PARAM(block);
     1222    constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
     1223#else
     1224    ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo(block);
     1225    if (!exclusionShapeInsideInfo || !exclusionShapeInsideInfo->hasSegments()) {
     1226        constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
     1227        return;
     1228    }
     1229
     1230    const SegmentRangeList& segmentRanges = exclusionShapeInsideInfo->segmentRanges();
     1231    ASSERT(segmentRanges.size());
     1232
     1233    for (size_t i = 0; i < segmentRanges.size(); i++) {
     1234        InlineIterator segmentStart = segmentRanges[i].start;
     1235        InlineIterator segmentEnd = segmentRanges[i].end;
     1236        if (i) {
     1237            ASSERT(segmentStart.m_obj);
     1238            BidiRun* segmentMarker = createRun(segmentStart.m_pos, segmentStart.m_pos, segmentStart.m_obj, topResolver);
     1239            segmentMarker->m_startsSegment = true;
     1240            bidiRuns.addRun(segmentMarker);
     1241            // Do not collapse midpoints between segments
     1242            topResolver.midpointState().betweenMidpoints = false;
     1243        }
     1244        topResolver.setPosition(segmentStart, numberOfIsolateAncestors(segmentStart));
     1245        constructBidiRunsForSegment(topResolver, bidiRuns, segmentEnd, override, previousLineBrokeCleanly);
     1246    }
     1247#endif
    11651248}
    11661249
     
    14621545            // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
    14631546            BidiRunList<BidiRun>& bidiRuns = resolver.runs();
    1464             constructBidiRuns(resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
     1547            constructBidiRunsForLine(this, resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
    14651548            ASSERT(resolver.position() == end);
    14661549
     
    23232406
    23242407InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
     2408{
     2409#if !ENABLE(CSS_EXCLUSIONS)
     2410    return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
     2411#else
     2412    ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo(m_block);
     2413    if (!exclusionShapeInsideInfo || !exclusionShapeInsideInfo->hasSegments())
     2414        return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
     2415
     2416    InlineIterator end = resolver.position();
     2417    InlineIterator oldEnd = end;
     2418
     2419    const SegmentList& segments = exclusionShapeInsideInfo->segments();
     2420    SegmentRangeList& segmentRanges = exclusionShapeInsideInfo->segmentRanges();
     2421
     2422    for (unsigned i = 0; i < segments.size(); i++) {
     2423        InlineIterator segmentStart = resolver.position();
     2424        end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
     2425
     2426        ASSERT(segmentRanges.size() == i);
     2427        if (resolver.position() == end) {
     2428            // Nothing fit this segment
     2429            segmentRanges.append(LineSegmentRange(segmentStart, segmentStart));
     2430            resolver.setPositionIgnoringNestedIsolates(segmentStart);
     2431        } else {
     2432            // Note that resolver.position is already skipping some of the white space at the beginning of the line,
     2433            // so that's why segmentStart might be different than resolver.position().
     2434            LineSegmentRange range(resolver.position(), end);
     2435            segmentRanges.append(range);
     2436            resolver.setPosition(end, numberOfIsolateAncestors(end));
     2437
     2438            if (lineInfo.previousLineBrokeCleanly()) {
     2439                // If we hit a new line break, just stop adding anything to this line.
     2440                break;
     2441            }
     2442        }
     2443    }
     2444    resolver.setPositionIgnoringNestedIsolates(oldEnd);
     2445    return end;
     2446#endif
     2447}
     2448
     2449InlineIterator RenderBlock::LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
    23252450{
    23262451    reset();
     
    29053030    }
    29063031
     3032    // FIXME Bug 100049: We do not need to consume input in a multi-segment line
     3033    // unless no segment will.
    29073034    // make sure we consume at least one char/object.
    29083035    if (lBreak == resolver.position())
Note: See TracChangeset for help on using the changeset viewer.