Bug 102435 - REGRESSION (r126656): execCommand on contenteditable with white-space: pre-wrap hangs WebKit
Summary: REGRESSION (r126656): execCommand on contenteditable with white-space: pre-wr...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: HTML Editing (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P1 Normal
Assignee: Glenn Adams
URL:
Keywords: InRadar, Regression
Depends on:
Blocks:
 
Reported: 2012-11-15 14:36 PST by James Simonsen
Modified: 2013-04-23 22:43 PDT (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description James Simonsen 2012-11-15 14:36:04 PST
This was reported in the Chrome bugtracker:

https://code.google.com/p/chromium/issues/detail?id=161335

It's confirmed broken in Chrome 23.0.1271.64 and a Mac WebKit build from yesterday. It works fine in Safari 6.0.2.

Here's the test case:

<html>
<head>
  <style>
    .textbox {
      white-space: pre-wrap;
    }
  </style>
</head>
<body>
  <div class="textbox" contenteditable="true"><div><span style="color: rgb(66, 240, 72);">WELCOME TO THE <span style="color: rgb(66, 136, 240);">JUNGLE</span></span></div><ol><li><span style="color: rgb(240, 66, 202);">What is the air speed velocity of an </span><span style="color: rgb(74, 140, 79);"> </span><span style="color: rgb(140, 74, 88);">unladen swallow</span></li><li style="color: rgb(140, 74, 88);"><span style="color: rgb(140, 74, 88);">What do you mean, African or European swallow?</span></li><ul><li style="color: rgb(140, 74, 88);"><span style="color: rgb(140, 74, 88);">I don't know that...</span><br></li></ul></ol></div>
  <script>
    var selectElements = function(start, end) {
      var range = document.createRange(),
          selection = window.getSelection();

      range.setStart(start, 0);
      range.setEnd(end, end.textContent.length);
      selection.removeAllRanges();
      selection.addRange(range);
    }

    document.execCommand('styleWithCSS', false, true);
    selectElements(document.querySelector('.textbox ol li:nth-of-type(1) span:nth-of-type(3)').firstChild, document.querySelector('.textbox ol ul li span').firstChild);
    document.execCommand('foreColor', false, '#123123');
  </script>
</body>
</html>
Comment 1 Alexey Proskuryakov 2012-11-16 11:05:30 PST
Regressed in <http://trac.webkit.org/changeset/126656>.
Comment 2 Alexey Proskuryakov 2012-11-16 11:15:37 PST
<rdar://problem/12719948>
Comment 3 Glenn Adams 2012-11-17 09:16:21 PST
Using a mac-mountainlion build of r126656, looks like it's hitting an assert:

ASSERTION FAILED: current->contains(targetNode)
/Users/glenn/work/webkit/Source/WebCore/editing/ApplyStyleCommand.cpp(980) : void WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode(WebCore::EditingStyle *, WebCore\
::Node *)
1   0x1092ecc2b WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode(WebCore::EditingStyle*, WebCore::Node*)
2   0x1092e9006 WebCore::ApplyStyleCommand::removeInlineStyle(WebCore::EditingStyle*, WebCore::Position const&, WebCore::Position const&)
3   0x1092e66da WebCore::ApplyStyleCommand::applyInlineStyle(WebCore::EditingStyle*)
4   0x1092e496f WebCore::ApplyStyleCommand::doApply()
5   0x10941752d WebCore::CompositeEditCommand::apply()
6   0x109417361 WebCore::applyCommand(WTF::PassRefPtr<WebCore::CompositeEditCommand>)
7   0x109803849 WebCore::Editor::applyStyle(WebCore::StylePropertySet*, WebCore::EditAction)
8   0x109818ad9 WebCore::applyCommandToFrame(WebCore::Frame*, WebCore::EditorCommandSource, WebCore::EditAction, WebCore::StylePropertySet*)
9   0x109818a3d WebCore::executeApplyStyle(WebCore::Frame*, WebCore::EditorCommandSource, WebCore::EditAction, WebCore::CSSPropertyID, WTF::String const&)
10  0x10981545f WebCore::executeForeColor(WebCore::Frame*, WebCore::Event*, WebCore::EditorCommandSource, WTF::String const&)
11  0x109813ce0 WebCore::Editor::Command::execute(WTF::String const&, WebCore::Event*) const
12  0x10963416e WebCore::Document::execCommand(WTF::String const&, bool, WTF::String const&)
Comment 4 Glenn Adams 2012-11-18 21:18:03 PST
Preliminary debugging shows that prior to r126656, ApplyStyleCommand::surroundNodeRangeWithElement does not invoke mergeIdenticalElements() on previousSibling and mergedElement due to WebCore::areIdenticalElements() returning false when both elements are identical except that one has a style attribute with an extraneous SPACE after the semicolon and the other style attribute does not have this extraneous SPACE.

Now, due to r126656, the extraneous SPACE is eliminated, thus causing areIdenticalElements() to return true, and thus causing mergeElements() to be invoked. This, however, appears to be unmasking a (possibly unreported) bug in the behavior when performing pushDownInlineStyleAroundNode() on the end position passed to removeInlineStyle():

#0	0x0000000110bf9f67 in WebCore::ApplyStyleCommand::surroundNodeRangeWithElement at /Users/glenn/work/webkit/Source/WebCore/editing/ApplyStyleCommand.cpp:1299
#1	0x0000000110bfd978 in WebCore::ApplyStyleCommand::addInlineStyleIfNeeded at /Users/glenn/work/webkit/Source/WebCore/editing/ApplyStyleCommand.cpp:1401
#2	0x0000000110bfeae6 in WebCore::ApplyStyleCommand::applyInlineStyleToPushDown at /Users/glenn/work/webkit/Source/WebCore/editing/ApplyStyleCommand.cpp:964
#3	0x0000000110bfef9e in WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode at /Users/glenn/work/webkit/Source/WebCore/editing/ApplyStyleCommand.cpp:1010
#4	0x0000000110bfb006 in WebCore::ApplyStyleCommand::removeInlineStyle(WebCore::EditingStyle*, WebCore::Position const&, WebCore::Position const&) ()
#5	0x0000000110bf86da in WebCore::ApplyStyleCommand::applyInlineStyle(WebCore::EditingStyle*) ()
#6	0x0000000110bf696f in WebCore::ApplyStyleCommand::doApply() ()

This end position points at offset 20 in the Text node of "I don't know that...", namely the offset just past the last character of the Text node, where the input context of this end position is:

<li style="color: rgb(140, 74, 88);"><span style="color: rgb(140, 74, 88);">I don't know that...</span><br></li>

With this context, the ancestor conflicting node is <li>, with <span> and <br> children. On the second pass through the inner loop of pushDownInlineStyleAroundNode, i.e., when child == HTMLBRElement, the invocation of applyInlineStyleToPushDown causes targetNode to be removed as a child from the 'current' node (HTMLSpanElement), which then causes an ASSERT (see below).

This is pretty dense code of which I have no prior knowledge, so it may take me a while to track down the pre-existing bug which was being masked by the erroneous areIdenticalElements() comparison of style attributes that existed prior to r126656.

To summarize, r126656 did not introduce a new bug per se; rather, it unmasked a pre-existing bug that was not apparent due to an erroneous areIdenticalElements() mismatch. I will continue working on this, though someone who has more knowledge of this code would likely find a fix more quickly.
Comment 5 Ryosuke Niwa 2013-04-23 19:42:14 PDT
It appears that the attached reproduction no longer works after http://trac.webkit.org/log/trunk/?rev=136765&stop_rev=136607.
Comment 6 Ryosuke Niwa 2013-04-23 22:43:09 PDT
Closing the bug since http://trac.webkit.org/changeset/136619 definitely fixed this hang.