Changeset 148781 in webkit


Ignore:
Timestamp:
Apr 19, 2013 4:28:26 PM (11 years ago)
Author:
betravis@adobe.com
Message:

[CSS Exclusions] Implement empty segments for multiple-segment shape-insides
https://bugs.webkit.org/show_bug.cgi?id=100049

Reviewed by David Hyatt.

Source/WebCore:

Content should not overflow a shape-inside segment, even if that means no content
will be placed in that segment. Overflow may be pushed to outside the shape. This
patch removes the restriction that every line must consume at least some text
input while inside a shape-inside. Content that does not fit is pushed down until
it does, either inside the shape or just below it.

Test: fast/exclusions/shape-inside/shape-inside-empty-segments.html

  • rendering/RenderBlockLineLayout.cpp:

(WebCore::constructBidiRunsForSegment): Do not include empty segments for
consideration, as the actual BidiRuns construction expects to consume at
least one character.
(WebCore::constructBidiRunsForLine): Ditto.
(WebCore::firstPositiveWidth): Find the first positive word measurement width,
as there may be some empty word break measurements inserted.
(WebCore::adjustLogicalLineTop): Move the current line down, if necessary, to
fit it within the shape inside.
(WebCore::RenderBlock::layoutRunsAndFloatsInRange): If nothing fit in the
current segment, find the first available position for the smallest item
at the beginning of the text.
(WebCore::RenderBlock::LineBreaker::nextLineBreak): Return an empty segment
for a line that is inside the shape, but has no segments.
(WebCore::RenderBlock::LineBreaker::nextSegmentBreak): Do not consume
input to meet minimum size requirements if you are inside a shape.

LayoutTests:

Testing that shape-insides do not place content where it will not fit. Also
fixing up some previous tests and expectations.

  • fast/exclusions/resources/multi-segment-polygon.js:

(simulateWithText): Enable multi-line shape expectations using arrays.

  • fast/exclusions/resources/simple-rectangle.js:

(createRectangleTest): Add overflow: break-word property to tests.
(createRectangleTestResult): Ditto.

  • fast/exclusions/shape-inside/shape-inside-empty-expected.html: Adjust results

for tests where content should be pushed down.

  • fast/exclusions/shape-inside/shape-inside-empty-segments-expected.html: Added.
  • fast/exclusions/shape-inside/shape-inside-empty-segments.html: Added.
  • fast/exclusions/shape-inside/shape-inside-empty.html: Shapes with height but

no width should still push content down below the shape.

Location:
trunk
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r148774 r148781  
     12013-04-19  Bear Travis  <betravis@adobe.com>
     2
     3        [CSS Exclusions] Implement empty segments for multiple-segment shape-insides
     4        https://bugs.webkit.org/show_bug.cgi?id=100049
     5
     6        Reviewed by David Hyatt.
     7
     8        Testing that shape-insides do not place content where it will not fit. Also
     9        fixing up some previous tests and expectations.
     10
     11        * fast/exclusions/resources/multi-segment-polygon.js:
     12        (simulateWithText): Enable multi-line shape expectations using arrays.
     13        * fast/exclusions/resources/simple-rectangle.js:
     14        (createRectangleTest): Add overflow: break-word property to tests.
     15        (createRectangleTestResult): Ditto.
     16        * fast/exclusions/shape-inside/shape-inside-empty-expected.html: Adjust results
     17        for tests where content should be pushed down.
     18        * fast/exclusions/shape-inside/shape-inside-empty-segments-expected.html: Added.
     19        * fast/exclusions/shape-inside/shape-inside-empty-segments.html: Added.
     20        * fast/exclusions/shape-inside/shape-inside-empty.html: Shapes with height but
     21        no width should still push content down below the shape.
     22
    1232013-04-19  Jessie Berlin  <jberlin@apple.com>
    224
  • trunk/LayoutTests/fast/exclusions/resources/multi-segment-polygon.js

    r136729 r148781  
    2222    div.style.setProperty('font', fontSize + 'px/1 Ahem, sans-serif');
    2323    div.style.setProperty('color', 'green');
     24    if (content instanceof Array) {
     25        div.style.setProperty('white-space', 'pre');
     26        content = content.join('\n');
     27    }
    2428    div.innerHTML = content;
    2529}
  • trunk/LayoutTests/fast/exclusions/resources/simple-rectangle.js

    r138040 r148781  
    1919    rules.push('-webkit-shape-inside: rectangle(' + rectangleBounds.join(',') + ')');
    2020    rules.push('position: relative');
     21    rules.push('overflow-wrap: break-word');
    2122    stylesheet.insertRule('#' + elementId + '{' + rules.join(';') + '}');
    2223
     
    4647    rules.push('padding-top: ' + shapeBounds.y + units, 'padding-bottom: ' + (bounds.height - shapeBounds.height - shapeBounds.y) + units);
    4748    rules.push('position: relative');
     49    rules.push('overflow-wrap: break-word');
    4850    stylesheet.insertRule('#' + elementId + '{' + rules.join(';') + '}');
    4951
  • trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-empty-expected.html

    r131766 r148781  
    1111        height: 2em;
    1212        border: solid green;
     13        box-sizing: border-box;
     14    }
     15    .padded {
     16        padding-top: 1em;
    1317    }
    1418</style>
    1519</head>
    1620<body>
    17     <p class="shape-inside">
    18         This text should be unconstrained by the rectangle(0px, 0px, 0px, 100px) shape-inside CSS property.
     21    <p class="shape-inside padded">
     22        This text should be shifted down 1em by the rectangle(0px, 0px, 0px, 1em) shape-inside CSS property.
    1923    </p>
    2024    <p class="shape-inside">
    21         This text should be unconstrained by the rectangle(0px, 0px, 100px, 0px) shape-inside CSS property.
     25        This text should be unconstrained by the rectangle(0px, 0px, 1em, 0px) shape-inside CSS property.
    2226    </p>
    2327    <p class="shape-inside">
    2428        This text should be unconstrained by the circle(0px, 0px, 0px) shape-inside CSS property.
    2529    </p>
    26     <p class="shape-inside">
    27         This text should be unconstrained by the ellipseX0(0px, 0px, 0px, 100px) shape-inside CSS property.
     30    <p class="shape-inside padded">
     31        This text should be shifted down 1em by the ellipseX0(0px, 0px, 0px, 1em) shape-inside CSS property.
    2832    </p>
    2933    <p class="shape-inside">
    30         This text should be unconstrained by the ellipse(0px, 0px, 100px, 0px) shape-inside CSS property.
    31     </p>
    32     <p class="shape-inside">
    33         This text should be unconstrained by the polygon() shape-inside CSS property.
     34        This text should be unconstrained by the ellipse(0px, 0px, 1em, 0px) shape-inside CSS property.
    3435    </p>
    3536    <p class="shape-inside">
     
    3738    </p>
    3839    <p class="shape-inside">
    39         This text should be unconstrained by the polygon(0px 0px, 10px 0px) shape-inside CSS property.
     40        This text should be unconstrained by the polygon(0px 0px, 1em 0px) shape-inside CSS property.
    4041    </p>
    4142</body>
  • trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-empty.html

    r131766 r148781  
    1111        height: 2em;
    1212        border: solid green;
     13        box-sizing: border-box;
    1314    }
    1415
    1516    #shape-inside-rectangle-width0 {
    16         -webkit-shape-inside: rectangle(0px, 0px, 0px, 100px);
     17        -webkit-shape-inside: rectangle(0px, 0px, 0px, 1em);
     18        padding-top: 1em;
    1719    }
    1820
    1921    #shape-inside-rectangle-height0 {
    20         -webkit-shape-inside: rectangle(0px, 0px, 100px, 0px);
     22        -webkit-shape-inside: rectangle(0px, 0px, 1em, 0px);
    2123    }
    2224
     
    2628
    2729    #shape-inside-ellipse-radiusX0 {
    28         -webkit-shape-inside: ellipse(0px, 0px, 0px, 100px);
     30        -webkit-shape-inside: ellipse(0px, 0px, 0px, 1em);
     31        padding-top: 1em;
    2932    }
    3033
    3134    #shape-inside-ellipse-radiusY0 {
    32         -webkit-shape-inside: ellipse(0px, 0px, 100px, 0px);
    33     }
    34 
    35     #shape-inside-polygon-0vertices {
    36         -webkit-shape-inside: polygon();
     35        -webkit-shape-inside: ellipse(0px, 0px, 1em, 0px);
    3736    }
    3837
     
    4241
    4342    #shape-inside-polygon-2vertices {
    44         -webkit-shape-inside: polygon(0px 0px, 10px 0px);
     43        -webkit-shape-inside: polygon(0px 0px, 1em 0px);
    4544    }
    4645</style>
     
    4847<body>
    4948    <p class="shape-inside" id="shape-inside-rectangle-width0">
    50         This text should be unconstrained by the rectangle(0px, 0px, 0px, 100px) shape-inside CSS property.
     49        This text should be shifted down 1em by the rectangle(0px, 0px, 0px, 1em) shape-inside CSS property.
    5150    </p>
    5251    <p class="shape-inside" id="shape-inside-rectangle-height0">
    53         This text should be unconstrained by the rectangle(0px, 0px, 100px, 0px) shape-inside CSS property.
     52        This text should be unconstrained by the rectangle(0px, 0px, 1em, 0px) shape-inside CSS property.
    5453    </p>
    5554    <p class="shape-inside" id="shape-inside-circle-radius0">
     
    5756    </p>
    5857    <p class="shape-inside" id="shape-inside-ellipse-radiusX0">
    59         This text should be unconstrained by the ellipseX0(0px, 0px, 0px, 100px) shape-inside CSS property.
     58        This text should be shifted down 1em by the ellipseX0(0px, 0px, 0px, 1em) shape-inside CSS property.
    6059    </p>
    6160    <p class="shape-inside" id="shape-inside-ellipse-radiusY0">
    62         This text should be unconstrained by the ellipse(0px, 0px, 100px, 0px) shape-inside CSS property.
    63     </p>
    64     <p class="shape-inside" id="shape-inside-polygon-0vertices">
    65         This text should be unconstrained by the polygon() shape-inside CSS property.
     61        This text should be unconstrained by the ellipse(0px, 0px, 1em, 0px) shape-inside CSS property.
    6662    </p>
    6763    <p class="shape-inside" id="shape-inside-polygon-1vertex">
     
    6965    </p>
    7066    <p class="shape-inside" id="shape-inside-polygon-2vertices">
    71         This text should be unconstrained by the polygon(0px 0px, 10px 0px) shape-inside CSS property.
     67        This text should be unconstrained by the polygon(0px 0px, 1em 0px) shape-inside CSS property.
    7268    </p>
    7369</body>
  • trunk/Source/WebCore/ChangeLog

    r148777 r148781  
     12013-04-19  Bear Travis  <betravis@adobe.com>
     2
     3        [CSS Exclusions] Implement empty segments for multiple-segment shape-insides
     4        https://bugs.webkit.org/show_bug.cgi?id=100049
     5
     6        Reviewed by David Hyatt.
     7
     8        Content should not overflow a shape-inside segment, even if that means no content
     9        will be placed in that segment. Overflow may be pushed to outside the shape. This
     10        patch removes the restriction that every line must consume at least some text
     11        input while inside a shape-inside. Content that does not fit is pushed down until
     12        it does, either inside the shape or just below it.
     13
     14        Test: fast/exclusions/shape-inside/shape-inside-empty-segments.html
     15
     16        * rendering/RenderBlockLineLayout.cpp:
     17        (WebCore::constructBidiRunsForSegment): Do not include empty segments for
     18        consideration, as the actual BidiRuns construction expects to consume at
     19        least one character.
     20        (WebCore::constructBidiRunsForLine): Ditto.
     21        (WebCore::firstPositiveWidth): Find the first positive word measurement width,
     22        as there may be some empty word break measurements inserted.
     23        (WebCore::adjustLogicalLineTop): Move the current line down, if necessary, to
     24        fit it within the shape inside.
     25        (WebCore::RenderBlock::layoutRunsAndFloatsInRange): If nothing fit in the
     26        current segment, find the first available position for the smallest item
     27        at the beginning of the text.
     28        (WebCore::RenderBlock::LineBreaker::nextLineBreak): Return an empty segment
     29        for a line that is inside the shape, but has no segments.
     30        (WebCore::RenderBlock::LineBreaker::nextSegmentBreak): Do not consume
     31        input to meet minimum size requirements if you are inside a shape.
     32
    1332013-04-19  Ryosuke Niwa  <rniwa@webkit.org>
    234
  • trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp

    r148658 r148781  
    12971297    // of the resolver owning the runs.
    12981298    ASSERT(&topResolver.runs() == &bidiRuns);
     1299    ASSERT(topResolver.position() != endOfRuns);
    12991300    RenderObject* currentRoot = topResolver.position().root();
    13001301    topResolver.createBidiRunsForLine(endOfRuns, override, previousLineBrokeCleanly);
     
    13831384            topResolver.midpointState().betweenMidpoints = false;
    13841385        }
     1386        if (segmentStart == segmentEnd)
     1387            continue;
    13851388        topResolver.setPosition(segmentStart, numberOfIsolateAncestors(segmentStart));
    13861389        constructBidiRunsForSegment(topResolver, bidiRuns, segmentEnd, override, previousLineBrokeCleanly);
     
    16211624}
    16221625
     1626#if ENABLE(CSS_EXCLUSIONS)
     1627static inline float firstPositiveWidth(const WordMeasurements& wordMeasurements)
     1628{
     1629    for (size_t i = 0; i < wordMeasurements.size(); ++i) {
     1630        if (wordMeasurements[i].width > 0)
     1631            return wordMeasurements[i].width;
     1632    }
     1633    return 0;
     1634}
     1635
     1636static inline LayoutUnit adjustLogicalLineTop(ExclusionShapeInsideInfo* exclusionShapeInsideInfo, InlineIterator start, InlineIterator end, const WordMeasurements& wordMeasurements)
     1637{
     1638    if (!exclusionShapeInsideInfo || end != start)
     1639        return 0;
     1640
     1641    float minWidth = firstPositiveWidth(wordMeasurements);
     1642    ASSERT(minWidth || wordMeasurements.isEmpty());
     1643    if (minWidth > 0 && exclusionShapeInsideInfo->adjustLogicalLineTop(minWidth))
     1644        return exclusionShapeInsideInfo->logicalLineTop();
     1645
     1646    return exclusionShapeInsideInfo->shapeLogicalBottom();
     1647}
     1648#endif
     1649
    16231650void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines)
    16241651{
     
    16951722            break;
    16961723        }
     1724
     1725#if ENABLE(CSS_EXCLUSIONS)
     1726        if (LayoutUnit adjustedLogicalLineTop = adjustLogicalLineTop(exclusionShapeInsideInfo, resolver.position(), end, wordMeasurements)) {
     1727            end = restartLayoutRunsAndFloatsInRange(logicalHeight(), adjustedLogicalLineTop - absoluteLogicalTop, lastFloatFromPreviousLine, resolver, oldEnd);
     1728            continue;
     1729        }
     1730#endif
     1731
    16971732        ASSERT(end != resolver.position());
    1698 
    1699 #if ENABLE(CSS_EXCLUSIONS)
    1700         if (exclusionShapeInsideInfo && wordMeasurements.size() && exclusionShapeInsideInfo->adjustLogicalLineTop(wordMeasurements[0].width)) {
    1701             end = restartLayoutRunsAndFloatsInRange(logicalHeight(), exclusionShapeInsideInfo->logicalLineTop() - absoluteLogicalTop, lastFloatFromPreviousLine, resolver, oldEnd);
    1702             continue;
    1703         }
    1704 #endif
    17051733
    17061734        // This is a short-cut for empty lines.
     
    26532681#else
    26542682    ExclusionShapeInsideInfo* exclusionShapeInsideInfo = m_block->layoutExclusionShapeInsideInfo();
    2655     if (!exclusionShapeInsideInfo || !exclusionShapeInsideInfo->hasSegments())
     2683    if (!exclusionShapeInsideInfo || !exclusionShapeInsideInfo->lineOverlapsShapeBounds())
    26562684        return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
    26572685
    26582686    InlineIterator end = resolver.position();
    26592687    InlineIterator oldEnd = end;
     2688
     2689    if (!exclusionShapeInsideInfo->hasSegments()) {
     2690        end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
     2691        resolver.setPositionIgnoringNestedIsolates(oldEnd);
     2692        return oldEnd;
     2693    }
    26602694
    26612695    const SegmentList& segments = exclusionShapeInsideInfo->segments();
     
    26732707        if (resolver.position() == end) {
    26742708            // Nothing fit this segment
     2709            end = segmentStart;
    26752710            segmentRanges.append(LineSegmentRange(segmentStart, segmentStart));
    26762711            resolver.setPositionIgnoringNestedIsolates(segmentStart);
     
    32963331
    32973332 end:
    3298     if (lBreak == resolver.position() && (!lBreak.m_obj || !lBreak.m_obj->isBR())) {
     3333#if ENABLE(CSS_EXCLUSIONS)
     3334    ExclusionShapeInsideInfo* shapeInfo = m_block->layoutExclusionShapeInsideInfo();
     3335    bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments();
     3336#else
     3337    bool segmentAllowsOverflow = true;
     3338#endif
     3339
     3340    if (lBreak == resolver.position() && (!lBreak.m_obj || !lBreak.m_obj->isBR()) && segmentAllowsOverflow) {
    32993341        // we just add as much as possible
    33003342        if (blockStyle->whiteSpace() == PRE && !current.m_pos) {
     
    33083350    }
    33093351
    3310     // FIXME Bug 100049: We do not need to consume input in a multi-segment line
    3311     // unless no segment will.
    33123352    // make sure we consume at least one char/object.
    3313     if (lBreak == resolver.position())
     3353    if (lBreak == resolver.position() && segmentAllowsOverflow)
    33143354        lBreak.increment();
    33153355
Note: See TracChangeset for help on using the changeset viewer.