Changeset 166245 in webkit


Ignore:
Timestamp:
Mar 25, 2014 1:15:14 PM (10 years ago)
Author:
mmaxfield@apple.com
Message:

InlineIterator position (unsigned int) variable can wrap around
https://bugs.webkit.org/show_bug.cgi?id=130540

Patch by Myles C. Maxfield <mmaxfield@apple.com> on 2014-03-25
Reviewed by Simon Fraser.

Source/WebCore:

We trigger an ASSERT that occurs when we are ignoring spaces (to collapse them
into a single whitespace mark) but then encounter a line break. Because we don't ignore
the first space (but do ignore subsequent spaces), when we hit a newline in an RTL context
we want to ignore that first space as well (so as not to push the text away from the right
edge). We do this by decrementing the InlineIterator pointing to this first space, so all
the spaces get ignored. However, if that space is the first character in a Text node, the
decrement will try to go past the beginning of the node, and trigger an ASSERT.

This design is not great. At some point we should rework it to more elegantly handle
collapsing whitespace in both RTL and LTR writing modes.

This patch adds an ASSERT earlier in this codepath to catch potential problems earlier.
It also pulls our sentinel value out into a separate boolean to make it more clear what is
going on.

Test: fast/text/whitespace-only-text-in-rtl.html

  • rendering/InlineIterator.h:

(WebCore::InlineIterator::moveTo): Use the set*() calls
(WebCore::InlineIterator::setOffset): ASSERT early that our math hasn't wrapped

  • rendering/RenderBlockLineLayout.cpp:

(WebCore::RenderBlockFlow::appendRunsForObject): Use new boolean value

  • rendering/line/BreakingContextInlineHeaders.h:

(WebCore::BreakingContext::handleText): Guard against wraps
(WebCore::checkMidpoints): Use new boolean value

  • rendering/line/TrailingObjects.cpp:

(WebCore::TrailingObjects::updateMidpointsForTrailingBoxes): Use new boolean value

LayoutTests:

This test triggers an ASSERT that occurs when we are ignoring spaces (to collapse them
into a single whitespace mark) but then encounter a line break. Because we don't ignore
the first space (but do ignore subsequent spaces), when we hit a newline in an RTL context
we want to ignore that first space as well (so as not to push the text away from the right
edge). We do this by decrementing the InlineIterator pointing to this first space, so all
the spaces get ignored. However, if that space is the first character in a Text node, the
decrement will try to go past the beginning of the node, and trigger an ASSERT.

This design is not great. At some point we should rework it to more elegantly handle
collapsing whitespace in both RTL and LTR writing modes.

  • fast/text/whitespace-only-text-in-rtl-expected.txt: Added.
  • fast/text/whitespace-only-text-in-rtl.html: Added.

Conflicts:

LayoutTests/ChangeLog
Source/WebCore/ChangeLog

Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r166243 r166245  
     12014-03-25  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        InlineIterator position (unsigned int) variable can wrap around
     4        https://bugs.webkit.org/show_bug.cgi?id=130540
     5
     6        Reviewed by Simon Fraser.
     7
     8        This test triggers an ASSERT that occurs when we are ignoring spaces (to collapse them
     9        into a single whitespace mark) but then encounter a line break. Because we don't ignore
     10        the first space (but do ignore subsequent spaces), when we hit a newline in an RTL context
     11        we want to ignore that first space as well (so as not to push the text away from the right
     12        edge). We do this by decrementing the InlineIterator pointing to this first space, so all
     13        the spaces get ignored. However, if that space is the first character in a Text node, the
     14        decrement will try to go past the beginning of the node, and trigger an ASSERT.
     15
     16        This design is not great. At some point we should rework it to more elegantly handle
     17        collapsing whitespace in both RTL and LTR writing modes.
     18
     19        * fast/text/whitespace-only-text-in-rtl-expected.txt: Added.
     20        * fast/text/whitespace-only-text-in-rtl.html: Added.
     21
    1222014-03-25  Oliver Hunt  <oliver@apple.com>
    223
  • trunk/Source/WebCore/ChangeLog

    r166239 r166245  
     12014-03-25  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        InlineIterator position (unsigned int) variable can wrap around
     4        https://bugs.webkit.org/show_bug.cgi?id=130540
     5
     6        Reviewed by Simon Fraser.
     7
     8        We trigger an ASSERT that occurs when we are ignoring spaces (to collapse them
     9        into a single whitespace mark) but then encounter a line break. Because we don't ignore
     10        the first space (but do ignore subsequent spaces), when we hit a newline in an RTL context
     11        we want to ignore that first space as well (so as not to push the text away from the right
     12        edge). We do this by decrementing the InlineIterator pointing to this first space, so all
     13        the spaces get ignored. However, if that space is the first character in a Text node, the
     14        decrement will try to go past the beginning of the node, and trigger an ASSERT.
     15
     16        This design is not great. At some point we should rework it to more elegantly handle
     17        collapsing whitespace in both RTL and LTR writing modes.
     18
     19        This patch adds an ASSERT earlier in this codepath to catch potential problems earlier.
     20        It also pulls our sentinel value out into a separate boolean to make it more clear what is
     21        going on.
     22
     23        Test: fast/text/whitespace-only-text-in-rtl.html
     24
     25        * rendering/InlineIterator.h:
     26        (WebCore::InlineIterator::moveTo): Use the set***() calls
     27        (WebCore::InlineIterator::setOffset): ASSERT early that our math hasn't wrapped
     28        * rendering/RenderBlockLineLayout.cpp:
     29        (WebCore::RenderBlockFlow::appendRunsForObject): Use new boolean value
     30        * rendering/line/BreakingContextInlineHeaders.h:
     31        (WebCore::BreakingContext::handleText): Guard against wraps
     32        (WebCore::checkMidpoints): Use new boolean value
     33        * rendering/line/TrailingObjects.cpp:
     34        (WebCore::TrailingObjects::updateMidpointsForTrailingBoxes): Use new boolean value
     35
    1362014-03-25  Martin Robinson  <mrobinson@igalia.com>
    237
  • trunk/Source/WebCore/rendering/InlineIterator.h

    r163465 r166245  
    4242        , m_nextBreakablePosition(-1)
    4343        , m_pos(0)
     44        , m_refersToEndOfPreviousNode(false)
    4445    {
    4546    }
     
    5051        , m_nextBreakablePosition(-1)
    5152        , m_pos(p)
     53        , m_refersToEndOfPreviousNode(false)
    5254    {
    5355    }
     
    6264    void moveTo(RenderObject* object, unsigned offset, int nextBreak = -1)
    6365    {
    64         m_renderer = object;
    65         m_pos = offset;
    66         m_nextBreakablePosition = nextBreak;
     66        setRenderer(object);
     67        setOffset(offset);
     68        setNextBreakablePosition(nextBreak);
    6769    }
    6870
     
    7072    void setRenderer(RenderObject* renderer) { m_renderer = renderer; }
    7173    unsigned offset() const { return m_pos; }
    72     void setOffset(unsigned position) { m_pos = position; }
     74    void setOffset(unsigned position);
    7375    RenderElement* root() const { return m_root; }
    7476    int nextBreakablePosition() const { return m_nextBreakablePosition; }
    7577    void setNextBreakablePosition(int position) { m_nextBreakablePosition = position; }
     78    bool refersToEndOfPreviousNode() const { return m_refersToEndOfPreviousNode; }
     79    void setRefersToEndOfPreviousNode();
    7680
    7781    void fastIncrementInTextNode();
    7882    void increment(InlineBidiResolver* = 0);
     83    void fastDecrement();
    7984    bool atEnd() const;
    8085
     
    101106    int m_nextBreakablePosition;
    102107    unsigned m_pos;
     108
     109    // There are a couple places where we want to decrement an InlineIterator.
     110    // Usually this take the form of decrementing m_pos; however, m_pos might be 0.
     111    // However, we shouldn't ever need to decrement an InlineIterator more than
     112    // once, so rather than implementing a decrement() function which traverses
     113    // nodes, we can simply keep track of this state and handle it.
     114    bool m_refersToEndOfPreviousNode;
    103115};
    104116
     
    322334}
    323335
     336inline void InlineIterator::setOffset(unsigned position)
     337{
     338    ASSERT(position <= UINT_MAX - 10); // Sanity check
     339    m_pos = position;
     340}
     341
     342inline void InlineIterator::setRefersToEndOfPreviousNode()
     343{
     344    ASSERT(!m_pos);
     345    ASSERT(!m_refersToEndOfPreviousNode);
     346    m_refersToEndOfPreviousNode = true;
     347}
     348
    324349// FIXME: This is used by RenderBlock for simplified layout, and has nothing to do with bidi
    325350// it shouldn't use functions called bidiFirst and bidiNext.
     
    364389    // bidiNext can return 0, so use moveTo instead of moveToStartOf
    365390    moveTo(bidiNextSkippingEmptyInlines(*m_root, m_renderer, resolver), 0);
     391}
     392
     393inline void InlineIterator::fastDecrement()
     394{
     395    ASSERT(!refersToEndOfPreviousNode());
     396    if (m_pos)
     397        setOffset(m_pos - 1);
     398    else
     399        setRefersToEndOfPreviousNode();
    366400}
    367401
  • trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp

    r165607 r166245  
    106106            lineMidpointState.setBetweenMidpoints(true);
    107107            lineMidpointState.incrementCurrentMidpoint();
    108             if (nextMidpoint.offset() != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
    109                 if (static_cast<int>(nextMidpoint.offset() + 1) > start)
    110                     runs.addRun(createRun(start, nextMidpoint.offset() + 1, obj, resolver));
    111                 return appendRunsForObject(runs, nextMidpoint.offset() + 1, end, obj, resolver);
    112             }
     108            // The end of the line is before the object we're inspecting. Skip everything and return
     109            if (nextMidpoint.refersToEndOfPreviousNode())
     110                return;
     111            if (static_cast<int>(nextMidpoint.offset() + 1) > start)
     112                runs.addRun(createRun(start, nextMidpoint.offset() + 1, obj, resolver));
     113            appendRunsForObject(runs, nextMidpoint.offset() + 1, end, obj, resolver);
    113114        } else
    114115           runs.addRun(createRun(start, end, obj, resolver));
  • trunk/Source/WebCore/rendering/line/BreakingContextInlineHeaders.h

    r166120 r166245  
    905905            // space doesn't seem to push the text out from the right-hand edge.
    906906            // FIXME: Do this regardless of the container's alignment - will require rebaselining a lot of test results.
    907             if (m_nextObject && m_nextObject->isBR() && (m_blockStyle.textAlign() == RIGHT || m_blockStyle.textAlign() == WEBKIT_RIGHT)) {
     907            if (m_nextObject && m_startOfIgnoredSpaces.offset() && m_nextObject->isBR() && (m_blockStyle.textAlign() == RIGHT || m_blockStyle.textAlign() == WEBKIT_RIGHT)) {
    908908                m_startOfIgnoredSpaces.setOffset(m_startOfIgnoredSpaces.offset() - 1);
    909909                // If there's just a single trailing space start ignoring it now so it collapses away.
     
    10661066            lineMidpointState.decreaseNumMidpoints();
    10671067            if (endpoint.renderer()->style().collapseWhiteSpace() && endpoint.renderer()->isText())
    1068                 endpoint.setOffset(endpoint.offset() - 1);
     1068                endpoint.fastDecrement();
    10691069        }
    10701070    }
  • trunk/Source/WebCore/rendering/line/TrailingObjects.cpp

    r162472 r166245  
    4343        ASSERT(trailingSpaceMidpoint >= 0);
    4444        if (collapseFirstSpace == CollapseFirstSpace)
    45             lineMidpointState.midpoints()[trailingSpaceMidpoint].setOffset(lineMidpointState.midpoints()[trailingSpaceMidpoint].offset() -1);
     45            lineMidpointState.midpoints()[trailingSpaceMidpoint].fastDecrement();
    4646
    4747        // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts
Note: See TracChangeset for help on using the changeset viewer.