Title: [133224] trunk
Revision
133224
Author
enr...@apple.com
Date
2012-11-01 13:54:20 -0700 (Thu, 01 Nov 2012)

Log Message

Part2 of: Extend -webkit-user-select with new value "all"
<rdar://problem/10161404>
https://bugs.webkit.org/show_bug.cgi?id=91912

Reviewed by Ryosuke Niwa.

Source/WebCore: 

The new value "all" for -webkit-user-select property gives content none-or-all selection option.
The patch was originally prepared by Alice Cheng but the approach has been changed.
The idea is to treat these elements like non editable, meaning that we should skip over them entirely
when moving the cursor and a deletion should delete the element and all its descentants at once.
The key change is in Node::rendererIsEditable where we now return false if the element style is
userSelect: all. The other change is in the way we create the selection on mouse click and dragging
over the element. In both cases we force the selection to extend over the entire element with
the user-select: all attribute.
This is currently enabled only for the Mac port.

Test: editing/selection/user-select-all-selection.html

* dom/Node.cpp: Added a parameter to isContentEditable to behave differently
when called from _javascript_. Internally isContentEditable returns false on
nodes with user-select: all style.
(WebCore::Node::isContentEditable):
(WebCore::Node::isContentRichlyEditable):
(WebCore::Node::rendererIsEditable):
(WebCore::Node::shouldUseInputMethod):
(WebCore::Node::willRespondToMouseClickEvents):
* dom/Node.h:
(WebCore::Node::rendererIsEditable):
(WebCore::Node::rendererIsRichlyEditable):
* dom/Position.cpp:
(WebCore::Position::nodeIsUserSelectAll): Added.
(WebCore::Position::rootUserSelectAllForNode): Added.
* dom/Position.h: Added static functions described above.
* editing/ApplyStyleCommand.cpp:
(WebCore::ApplyStyleCommand::removeInlineStyleFromElement): Added parameter to
isContentEditable() call.
(WebCore::ApplyStyleCommand::surroundNodeRangeWithElement): Added parameter to
isContentEditable() call.
* editing/DeleteFromTextNodeCommand.cpp:
(WebCore::DeleteFromTextNodeCommand::doApply): Added parameter to
isContentEditable() call.
* editing/FrameSelection.cpp:
(WebCore::adjustForwardPositionForUserSelectAll): New helper function.
(WebCore::adjustBackwardPositionForUserSelectAll): New helper function.
(WebCore::FrameSelection::modifyExtendingRight):
(WebCore::FrameSelection::modifyExtendingForward):
(WebCore::FrameSelection::modifyExtendingLeft):
(WebCore::FrameSelection::modifyExtendingBackward):
(WebCore::FrameSelection::modify):
(WebCore::CaretBase::invalidateCaretRect): Added parameter to
isContentEditable() call.
* editing/InsertNodeBeforeCommand.cpp:
(WebCore::InsertNodeBeforeCommand::doApply): Ditto.
(WebCore::InsertNodeBeforeCommand::doUnapply): Ditto.
* editing/RemoveNodeCommand.cpp:
(WebCore::RemoveNodeCommand::doApply): Ditto.
* editing/visible_units.cpp:
(WebCore::startOfParagraph): We should not consider a paragraph break and element
with user-select: all style, like we do at the border of editability.
(WebCore::endOfParagraph): Ditto.
* page/EventHandler.cpp:
(WebCore::EventHandler::updateSelectionForMouseDownDispatchingSelectStart): Create a selection
around the element whose style is user-select: all.
(WebCore::EventHandler::updateSelectionForMouseDrag): Ditto.
* rendering/RootInlineBox.cpp:
(WebCore::RootInlineBox::selectionState): Fixed a bug uncovered during this work.
If the selection starts in one of the leaf boxes and after we encounter one with SelectionNone,
we should return the selection state as SelectionBoth, assuming we went past the end selection.
This avoids doing an incorrect gap filling for the selection highlighting.

LayoutTests: 

Testing moving and extending selections with the new CSS propertyvalue, with mouse movements
and with the keyboard.
Updated test expectations for all the platforms, since this is only enabled for the Mac port.

* editing/selection/user-select-all-selection-expected.txt: Added.
* editing/selection/user-select-all-selection.html: Added.
* platform/chromium/TestExpectations:
* platform/qt/TestExpectations:
* platform/gtk/TestExpectations:
* platform/win/TestExpectations:
* platform/efl/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (133223 => 133224)


--- trunk/LayoutTests/ChangeLog	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/LayoutTests/ChangeLog	2012-11-01 20:54:20 UTC (rev 133224)
@@ -1,3 +1,24 @@
+2012-11-01  Enrica Casucci  <enr...@apple.com>
+
+        Part2 of: Extend -webkit-user-select with new value "all"
+        <rdar://problem/10161404>
+        https://bugs.webkit.org/show_bug.cgi?id=91912
+
+        Reviewed by Ryosuke Niwa.
+
+        Testing moving and extending selections with the new CSS propertyvalue, with mouse movements
+        and with the keyboard.
+        Updated test expectations for all the platforms, since this is only enabled for the Mac port.
+
+        * editing/selection/user-select-all-selection-expected.txt: Added.
+        * editing/selection/user-select-all-selection.html: Added.
+        * platform/chromium/TestExpectations:
+        * platform/qt/TestExpectations:
+        * platform/gtk/TestExpectations:
+        * platform/win/TestExpectations:
+        * platform/efl/TestExpectations:
+
+
 2012-11-01  David Barton  <dbar...@mathscribe.com>
 
         REGRESSION (r128837): mathml/presentation/subsup.xhtml became flaky

Added: trunk/LayoutTests/editing/selection/user-select-all-selection-expected.txt (0 => 133224)


--- trunk/LayoutTests/editing/selection/user-select-all-selection-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/user-select-all-selection-expected.txt	2012-11-01 20:54:20 UTC (rev 133224)
@@ -0,0 +1,34 @@
+Test -webkit-user-select all user select all area Test -webkit-user-select all
+Test -webkit-user-select all selection movements and extensions (left right forward backward)
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+placeCaretBeforeUserSelectAllElement()
+window.getSelection().modify('extend', 'forward', 'character')
+PASS Selection is the entire user-select-all element
+window.getSelection().modify('extend', 'backward', 'character')
+PASS Selection is right before user-select-all element
+window.getSelection().modify('extend', 'right', 'character')
+PASS Selection is the entire user-select-all element
+window.getSelection().modify('extend', 'left', 'character')
+PASS Selection is right before user-select-all element
+window.getSelection().modify('move', 'forward', 'character')
+PASS Selection is right after user-select-all element
+window.getSelection().modify('move', 'backward', 'character')
+PASS Selection is right before user-select-all element
+window.getSelection().modify('move', 'right', 'character')
+PASS Selection is right after user-select-all element
+window.getSelection().modify('move', 'left', 'character')
+PASS Selection is right before user-select-all element
+clickAt(descendant.offsetLeft + 10 , descendant.offsetTop + 10)
+PASS Selection is the entire user-select-all element
+mouseMoveFromTo(leftTarget.offsetLeft, descendant.offsetLeft + 20)
+PASS Selection is the entire user-select-all element plus everything on its left
+mouseMoveFromTo(userSelectAllElement.offsetLeft + userSelectAllElement.offsetWidth + rightTarget.offsetWidth, descendant.offsetLeft + 10)
+PASS Selection is the entire user-select-all element plus everything on its right
+PASS Selection is only the text in bold
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/selection/user-select-all-selection.html (0 => 133224)


--- trunk/LayoutTests/editing/selection/user-select-all-selection.html	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/user-select-all-selection.html	2012-11-01 20:54:20 UTC (rev 133224)
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<head>
+<style>
+.userSelectAll {-webkit-user-select: all; }
+</style>
+<script src=""
+<script src=""
+<script src=""
+<script>
+function log(str) {
+    var div = document.createElement("div");
+    div.appendChild(document.createTextNode(str));
+    document.getElementById("console").appendChild(div);
+}
+
+function testSelectionAt(anchorNode, anchorOffset, optFocusNode, optFocusOffset, str) {
+    var focusNode = optFocusNode || anchorNode;
+    var focusOffset = (optFocusOffset === undefined) ? anchorOffset : optFocusOffset;
+                
+    var sel = window.getSelection();
+    if (sel.anchorNode == anchorNode
+        && sel.focusNode == focusNode
+        && sel.anchorOffset == anchorOffset
+        && sel.focusOffset == focusOffset) {
+        testPassed("Selection is " + str);
+    } else {
+        testFailed("Selection should be " + str +
+            " at anchorNode: " + sel.anchorNode + " anchorOffset: " + sel.anchorOffset +
+            " focusNode: " + sel.focusNode + " focusOffset: " + sel.focusOffset);
+    }
+}
+
+function selectionShouldBeRelativeToUserSelectAllElement(str) {
+    var userSelectAllElement = document.getElementById("allArea");
+    var userSelectAllNodeIndex = 1;
+    if (str == "around")
+        testSelectionAt(userSelectAllElement.previousSibling.firstChild, userSelectAllElement.previousSibling.textContent.length,
+            userSelectAllElement.nextSibling, 0,
+            "the entire user-select-all element");
+    else if ( str == "before")
+        testSelectionAt(userSelectAllElement.previousSibling.firstChild, userSelectAllElement.previousSibling.textContent.length,
+            userSelectAllElement.previousSibling.firstChild, userSelectAllElement.previousSibling.textContent.length,
+            "right before user-select-all element");
+    else if (str == "after")
+        testSelectionAt(userSelectAllElement.nextSibling.firstChild, 0,
+            userSelectAllElement.nextSibling.firstChild, 0,
+            "right after user-select-all element");
+}
+
+function placeCaretBeforeUserSelectAllElement(){
+    var userSelectAllElement = document.getElementById("allArea");
+    execSetSelectionCommand(userSelectAllElement.previousSibling.firstChild, userSelectAllElement.previousSibling.textContent.length, userSelectAllElement.previousSibling, userSelectAllElement.previousSibling.textContent.length);
+}
+
+function mouseMoveFromTo(fromX, toX){
+    var userSelectAllElement = document.getElementById("allArea");
+    var y = userSelectAllElement.offsetTop + 10;
+    eventSender.dragMode = false;
+    // Clear click count
+    eventSender.mouseMoveTo(0, 0);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+                
+    eventSender.mouseMoveTo(fromX, y);
+    eventSender.mouseDown();
+    eventSender.mouseMoveTo(toX, y);
+    eventSender.mouseUp();
+}
+
+function testKeyboard(){
+    var userSelectAllElement = document.getElementById("allArea");
+                
+    evalAndLog("placeCaretBeforeUserSelectAllElement()");
+    evalAndLog("window.getSelection().modify('extend', 'forward', 'character')");
+    selectionShouldBeRelativeToUserSelectAllElement("around");
+     
+    evalAndLog("window.getSelection().modify('extend', 'backward', 'character')");
+    selectionShouldBeRelativeToUserSelectAllElement("before");
+     
+    evalAndLog("window.getSelection().modify('extend', 'right', 'character')");
+    selectionShouldBeRelativeToUserSelectAllElement("around");
+                
+    evalAndLog("window.getSelection().modify('extend', 'left', 'character')");
+    selectionShouldBeRelativeToUserSelectAllElement("before");
+                
+    evalAndLog("window.getSelection().modify('move', 'forward', 'character')");
+    selectionShouldBeRelativeToUserSelectAllElement("after");
+                
+    evalAndLog("window.getSelection().modify('move', 'backward', 'character')");
+    selectionShouldBeRelativeToUserSelectAllElement("before");
+                
+    evalAndLog("window.getSelection().modify('move', 'right', 'character')");
+    selectionShouldBeRelativeToUserSelectAllElement("after");
+     
+    evalAndLog("window.getSelection().modify('move', 'left', 'character')");
+    selectionShouldBeRelativeToUserSelectAllElement("before");
+}
+
+function testMouse(){
+    var userSelectAllElement = document.getElementById("allArea");
+    var descendant = document.getElementById("descendant");
+    evalAndLog("clickAt(descendant.offsetLeft + 10 , descendant.offsetTop + 10)");
+    selectionShouldBeRelativeToUserSelectAllElement("around");
+                
+    // mouse extending from left
+    var leftTarget = userSelectAllElement.previousSibling;
+    log("mouseMoveFromTo(leftTarget.offsetLeft, descendant.offsetLeft + 20)");
+    mouseMoveFromTo(leftTarget.offsetLeft, descendant.offsetLeft + 20);
+    testSelectionAt(leftTarget.firstChild, 0, userSelectAllElement.nextSibling, 0, "the entire user-select-all element plus everything on its left");
+    
+    // mouse extending from right
+    var rightTarget = userSelectAllElement.nextSibling;
+    var textLength = rightTarget.textContent.length;
+    log("mouseMoveFromTo(userSelectAllElement.offsetLeft + userSelectAllElement.offsetWidth + rightTarget.offsetWidth, descendant.offsetLeft + 10)");
+    mouseMoveFromTo(userSelectAllElement.offsetLeft + userSelectAllElement.offsetWidth + rightTarget.offsetWidth, descendant.offsetLeft + 10);
+    testSelectionAt(rightTarget.firstChild, textLength, leftTarget.firstChild, leftTarget.textContent.textLength, "the entire user-select-all element plus everything on its right");
+}
+    
+function testProgrammaticSelection(){
+    var boldElement = document.querySelector('b');
+    getSelection().selectAllChildren(boldElement);
+    testSelectionAt(boldElement.firstChild, 0, boldElement.firstChild, 10, "only the text in bold");
+}
+</script>
+</head>
+<body><div contenteditable><span>Test -webkit-user-select all </span><span class="userSelectAll" id="allArea"><span style="border: solid red 1px" id="descendant">user <b>select all</b> area</span></span><span> Test -webkit-user-select all</span></div>
+<div id="console"></div>
+<script>
+description(" Test -webkit-user-select all selection movements and extensions (left right forward backward) ");
+testKeyboard();
+testMouse();
+testProgrammaticSelection();
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/LayoutTests/platform/chromium/TestExpectations (133223 => 133224)


--- trunk/LayoutTests/platform/chromium/TestExpectations	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/LayoutTests/platform/chromium/TestExpectations	2012-11-01 20:54:20 UTC (rev 133224)
@@ -4141,6 +4141,7 @@
 
 webkit.org/b/100478  [ Mac ] css3/filters/custom/effect-custom.html [ Pass ImageOnlyFailure ]
 
+webkit.org/b/100424 editing/selection/user-select-all-selection.html [ Failure ]
 webkit.org/b/100475 compositing/tiling/tile-cache-zoomed.html [ Failure ]
 webkit.org/b/100475 platform/chromium/virtual/softwarecompositing/tiling/tile-cache-zoomed.html [ Failure ]
 webkit.org/b/100477 [ Win ] platform/chromium/fast/forms/suggestion-picker/date-suggestion-picker-key-operations.html [ Failure ]

Modified: trunk/LayoutTests/platform/efl/TestExpectations (133223 => 133224)


--- trunk/LayoutTests/platform/efl/TestExpectations	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/LayoutTests/platform/efl/TestExpectations	2012-11-01 20:54:20 UTC (rev 133224)
@@ -1670,6 +1670,8 @@
 # Resource Timing is not enable yet, skip it.
 webkit.org/b/61138 http/tests/w3c/webperf/submission/Intel/resource-timing [ Skip ]
 
+webkit.org/b/100424 editing/selection/user-select-all-selection.html [ Failure ]
+
 # Entering into full screen playback mode fails when triggered by context menu
 Bug(EFL) media/context-menu-actions.html [ Failure ]
 

Modified: trunk/LayoutTests/platform/gtk/TestExpectations (133223 => 133224)


--- trunk/LayoutTests/platform/gtk/TestExpectations	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/LayoutTests/platform/gtk/TestExpectations	2012-11-01 20:54:20 UTC (rev 133224)
@@ -1429,6 +1429,8 @@
 
 webkit.org/b/98718 svg/animations/animate-css-xml-attributeType.html [ Failure ]
 
+webkit.org/b/100424 editing/selection/user-select-all-selection.html [ Failure ]
+
 webkit.org/b/100846 inspector-protocol/debugger-pause-dedicated-worker.html [ Skip ]
 
 webkit.org/b/95299 fast/images/exif-orientation.html [ Failure ]

Modified: trunk/LayoutTests/platform/qt/TestExpectations (133223 => 133224)


--- trunk/LayoutTests/platform/qt/TestExpectations	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/LayoutTests/platform/qt/TestExpectations	2012-11-01 20:54:20 UTC (rev 133224)
@@ -2508,6 +2508,8 @@
 # [Qt] New http/tests/inspector/network/image-as-text-loading-data-url.html fails
 webkit.org/b/100196 http/tests/inspector/network/image-as-text-loading-data-url.html
 
+webkit.org/b/100424 editing/selection/user-select-all-selection.html [ Failure ]
+
 # REGRESSION(r132757): It made 2 jquery tests assert
 webkit.org/b/100636 jquery/manipulation.html
 webkit.org/b/100636 jquery/traversing.html

Modified: trunk/LayoutTests/platform/win/TestExpectations (133223 => 133224)


--- trunk/LayoutTests/platform/win/TestExpectations	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/LayoutTests/platform/win/TestExpectations	2012-11-01 20:54:20 UTC (rev 133224)
@@ -2378,6 +2378,8 @@
 # Resource Timing is not enable yet, skip it.
 webkit.org/b/61138 http/tests/w3c/webperf/submission/Intel/resource-timing
 
+webkit.org/b/100424 editing/selection/user-select-all-selection.html [ Failure ]
+
 # https://bugs.webkit.org/show_bug.cgi?id=99567
 # Not supported on Mac or Windows ports
 inspector/elements/update-shadowdom.html

Modified: trunk/Source/WebCore/ChangeLog (133223 => 133224)


--- trunk/Source/WebCore/ChangeLog	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/ChangeLog	2012-11-01 20:54:20 UTC (rev 133224)
@@ -1,3 +1,75 @@
+2012-11-01  Enrica Casucci  <enr...@apple.com>
+
+        Part2 of: Extend -webkit-user-select with new value "all"
+        <rdar://problem/10161404>
+        https://bugs.webkit.org/show_bug.cgi?id=91912
+
+        Reviewed by Ryosuke Niwa.
+
+        The new value "all" for -webkit-user-select property gives content none-or-all selection option.
+        The patch was originally prepared by Alice Cheng but the approach has been changed.
+        The idea is to treat these elements like non editable, meaning that we should skip over them entirely
+        when moving the cursor and a deletion should delete the element and all its descentants at once.
+        The key change is in Node::rendererIsEditable where we now return false if the element style is
+        userSelect: all. The other change is in the way we create the selection on mouse click and dragging
+        over the element. In both cases we force the selection to extend over the entire element with
+        the user-select: all attribute.
+        This is currently enabled only for the Mac port.
+
+        Test: editing/selection/user-select-all-selection.html
+
+        * dom/Node.cpp: Added a parameter to isContentEditable to behave differently
+        when called from _javascript_. Internally isContentEditable returns false on
+        nodes with user-select: all style.
+        (WebCore::Node::isContentEditable):
+        (WebCore::Node::isContentRichlyEditable):
+        (WebCore::Node::rendererIsEditable):
+        (WebCore::Node::shouldUseInputMethod):
+        (WebCore::Node::willRespondToMouseClickEvents):
+        * dom/Node.h:
+        (WebCore::Node::rendererIsEditable):
+        (WebCore::Node::rendererIsRichlyEditable):
+        * dom/Position.cpp:
+        (WebCore::Position::nodeIsUserSelectAll): Added.
+        (WebCore::Position::rootUserSelectAllForNode): Added.
+        * dom/Position.h: Added static functions described above.
+        * editing/ApplyStyleCommand.cpp:
+        (WebCore::ApplyStyleCommand::removeInlineStyleFromElement): Added parameter to
+        isContentEditable() call.
+        (WebCore::ApplyStyleCommand::surroundNodeRangeWithElement): Added parameter to
+        isContentEditable() call.
+        * editing/DeleteFromTextNodeCommand.cpp:
+        (WebCore::DeleteFromTextNodeCommand::doApply): Added parameter to
+        isContentEditable() call.
+        * editing/FrameSelection.cpp:
+        (WebCore::adjustForwardPositionForUserSelectAll): New helper function.
+        (WebCore::adjustBackwardPositionForUserSelectAll): New helper function.
+        (WebCore::FrameSelection::modifyExtendingRight):
+        (WebCore::FrameSelection::modifyExtendingForward):
+        (WebCore::FrameSelection::modifyExtendingLeft):
+        (WebCore::FrameSelection::modifyExtendingBackward):
+        (WebCore::FrameSelection::modify):
+        (WebCore::CaretBase::invalidateCaretRect): Added parameter to
+        isContentEditable() call.
+        * editing/InsertNodeBeforeCommand.cpp:
+        (WebCore::InsertNodeBeforeCommand::doApply): Ditto.
+        (WebCore::InsertNodeBeforeCommand::doUnapply): Ditto.
+        * editing/RemoveNodeCommand.cpp:
+        (WebCore::RemoveNodeCommand::doApply): Ditto.
+        * editing/visible_units.cpp:
+        (WebCore::startOfParagraph): We should not consider a paragraph break and element
+        with user-select: all style, like we do at the border of editability.
+        (WebCore::endOfParagraph): Ditto.
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::updateSelectionForMouseDownDispatchingSelectStart): Create a selection
+        around the element whose style is user-select: all.
+        (WebCore::EventHandler::updateSelectionForMouseDrag): Ditto.
+        * rendering/RootInlineBox.cpp:
+        (WebCore::RootInlineBox::selectionState): Fixed a bug uncovered during this work.
+        If the selection starts in one of the leaf boxes and after we encounter one with SelectionNone,
+        we should return the selection state as SelectionBoth, assuming we went past the end selection.
+        This avoids doing an incorrect gap filling for the selection highlighting.
+
 2012-11-01  Alec Flett  <alecfl...@chromium.org>
 
         IndexedDB: Fix Windows build by re-adding a #include

Modified: trunk/Source/WebCore/dom/Node.cpp (133223 => 133224)


--- trunk/Source/WebCore/dom/Node.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/dom/Node.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -717,16 +717,16 @@
     return nullAtom;
 }
 
-bool Node::isContentEditable()
+bool Node::isContentEditable(UserSelectAllTreatment treatment)
 {
     document()->updateStyleIfNeeded();
-    return rendererIsEditable(Editable);
+    return rendererIsEditable(Editable, treatment);
 }
 
 bool Node::isContentRichlyEditable()
 {
     document()->updateStyleIfNeeded();
-    return rendererIsEditable(RichlyEditable);
+    return rendererIsEditable(RichlyEditable, UserSelectAllIsAlwaysNonEditable);
 }
 
 void Node::inspect()
@@ -737,7 +737,7 @@
 #endif
 }
 
-bool Node::rendererIsEditable(EditableLevel editableLevel) const
+bool Node::rendererIsEditable(EditableLevel editableLevel, UserSelectAllTreatment treatment) const
 {
     if (document()->frame() && document()->frame()->page() && document()->frame()->page()->isEditable() && !shadowRoot())
         return true;
@@ -748,6 +748,12 @@
 
     for (const Node* node = this; node; node = node->parentNode()) {
         if ((node->isHTMLElement() || node->isDocumentNode()) && node->renderer()) {
+#if ENABLE(USERSELECT_ALL)
+            // Elements with user-select: all style are considered atomic
+            // therefore non editable.
+            if (node->renderer()->style()->userSelect() == SELECT_ALL && treatment == UserSelectAllIsAlwaysNonEditable)
+                return false;
+#endif
             switch (node->renderer()->style()->userModify()) {
             case READ_ONLY:
                 return false;
@@ -785,7 +791,7 @@
 
 bool Node::shouldUseInputMethod()
 {
-    return isContentEditable();
+    return isContentEditable(UserSelectAllIsAlwaysNonEditable);
 }
 
 RenderBox* Node::renderBox() const
@@ -2746,7 +2752,7 @@
 {
     if (disabled())
         return false;
-    return isContentEditable() || hasEventListeners(eventNames().mouseupEvent) || hasEventListeners(eventNames().mousedownEvent) || hasEventListeners(eventNames().clickEvent) || hasEventListeners(eventNames().DOMActivateEvent);
+    return isContentEditable(UserSelectAllIsAlwaysNonEditable) || hasEventListeners(eventNames().mouseupEvent) || hasEventListeners(eventNames().mousedownEvent) || hasEventListeners(eventNames().clickEvent) || hasEventListeners(eventNames().DOMActivateEvent);
 }
 
 bool Node::willRespondToTouchEvents()

Modified: trunk/Source/WebCore/dom/Node.h (133223 => 133224)


--- trunk/Source/WebCore/dom/Node.h	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/dom/Node.h	2012-11-01 20:54:20 UTC (rev 133224)
@@ -375,16 +375,20 @@
     virtual bool isMouseFocusable() const;
     virtual Node* focusDelegate();
 
-    bool isContentEditable();
+    enum UserSelectAllTreatment {
+        UserSelectAllDoesNotAffectEditability,
+        UserSelectAllIsAlwaysNonEditable
+    };
+    bool isContentEditable(UserSelectAllTreatment = UserSelectAllDoesNotAffectEditability);
     bool isContentRichlyEditable();
 
     void inspect();
 
-    bool rendererIsEditable(EditableType editableType = ContentIsEditable) const
+    bool rendererIsEditable(EditableType editableType = ContentIsEditable, UserSelectAllTreatment treatment = UserSelectAllIsAlwaysNonEditable) const
     {
         switch (editableType) {
         case ContentIsEditable:
-            return rendererIsEditable(Editable);
+            return rendererIsEditable(Editable, treatment);
         case HasEditableAXRole:
             return isEditableToAccessibility(Editable);
         }
@@ -396,7 +400,7 @@
     {
         switch (editableType) {
         case ContentIsEditable:
-            return rendererIsEditable(RichlyEditable);
+            return rendererIsEditable(RichlyEditable, UserSelectAllIsAlwaysNonEditable);
         case HasEditableAXRole:
             return isEditableToAccessibility(RichlyEditable);
         }
@@ -768,7 +772,7 @@
     void setDocument(Document*);
 
     enum EditableLevel { Editable, RichlyEditable };
-    bool rendererIsEditable(EditableLevel) const;
+    bool rendererIsEditable(EditableLevel, UserSelectAllTreatment = UserSelectAllIsAlwaysNonEditable) const;
     bool isEditableToAccessibility(EditableLevel) const;
 
     void setStyleChange(StyleChangeType);

Modified: trunk/Source/WebCore/dom/Position.cpp (133223 => 133224)


--- trunk/Source/WebCore/dom/Position.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/dom/Position.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -865,6 +865,35 @@
     return node->nonShadowBoundaryParentNode();
 }
 
+#if ENABLE(USERSELECT_ALL)
+bool Position::nodeIsUserSelectAll(const Node* node)
+{
+    return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_ALL;
+}
+
+Node* Position::rootUserSelectAllForNode(Node* node)
+{
+    if (!node || !nodeIsUserSelectAll(node))
+        return 0;
+    Node* parent = node->parentNode();
+    if (!parent)
+        return node;
+
+    Node* candidateRoot = node;
+    while (parent) {
+        if (!parent->renderer()) {
+            parent = parent->parentNode();
+            continue;
+        }
+        if (!nodeIsUserSelectAll(parent))
+            break;
+        candidateRoot = parent;
+        parent = candidateRoot->parentNode();
+    }
+    return candidateRoot;
+}
+#endif
+
 bool Position::isCandidate() const
 {
     if (isNull())

Modified: trunk/Source/WebCore/dom/Position.h (133223 => 133224)


--- trunk/Source/WebCore/dom/Position.h	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/dom/Position.h	2012-11-01 20:54:20 UTC (rev 133224)
@@ -189,7 +189,10 @@
 
     static bool hasRenderedNonAnonymousDescendantsWithHeight(RenderObject*);
     static bool nodeIsUserSelectNone(Node*);
-
+#if ENABLE(USERSELECT_ALL)
+    static bool nodeIsUserSelectAll(const Node*);
+    static Node* rootUserSelectAllForNode(Node*);
+#endif
     static ContainerNode* findParent(const Node*);
     
     void debugPosition(const char* msg = "") const;

Modified: trunk/Source/WebCore/editing/ApplyStyleCommand.cpp (133223 => 133224)


--- trunk/Source/WebCore/editing/ApplyStyleCommand.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/editing/ApplyStyleCommand.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -825,7 +825,7 @@
 {
     ASSERT(element);
 
-    if (!element->parentNode() || !element->parentNode()->isContentEditable())
+    if (!element->parentNode() || !element->parentNode()->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable))
         return false;
 
     if (isStyledInlineElementToRemove(element.get())) {
@@ -1288,7 +1288,7 @@
     RefPtr<Node> node = startNode;
     while (node) {
         RefPtr<Node> next = node->nextSibling();
-        if (node->isContentEditable()) {
+        if (node->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable)) {
             removeNode(node);
             appendNode(node, element);
         }

Modified: trunk/Source/WebCore/editing/DeleteFromTextNodeCommand.cpp (133223 => 133224)


--- trunk/Source/WebCore/editing/DeleteFromTextNodeCommand.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/editing/DeleteFromTextNodeCommand.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -47,7 +47,7 @@
 {
     ASSERT(m_node);
 
-    if (!m_node->isContentEditable())
+    if (!m_node->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable))
         return;
 
     ExceptionCode ec = 0;

Modified: trunk/Source/WebCore/editing/FrameSelection.cpp (133223 => 133224)


--- trunk/Source/WebCore/editing/FrameSelection.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/editing/FrameSelection.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -556,6 +556,14 @@
     return positionForPlatform(false);
 }
 
+#if ENABLE(USERSELECT_ALL)
+static void adjustPositionForUserSelectAll(VisiblePosition& pos, bool isForward)
+{
+    if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(pos.deepEquivalent().anchorNode()))
+        pos = isForward ? positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary) : positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary);
+}
+#endif
+
 VisiblePosition FrameSelection::modifyExtendingRight(TextGranularity granularity)
 {
     VisiblePosition pos(m_selection.extent(), m_selection.affinity());
@@ -594,6 +602,9 @@
         pos = modifyExtendingForward(granularity);
         break;
     }
+#if ENABLE(USERSELECT_ALL)
+    adjustPositionForUserSelectAll(pos, directionOfEnclosingBlock() == LTR);
+#endif
     return pos;
 }
 
@@ -633,7 +644,9 @@
             pos = endOfDocument(pos);
         break;
     }
-    
+#if ENABLE(USERSELECT_ALL)
+     adjustPositionForUserSelectAll(pos, directionOfEnclosingBlock() == LTR);
+#endif
     return pos;
 }
 
@@ -760,6 +773,9 @@
         pos = modifyExtendingBackward(granularity);
         break;
     }
+#if ENABLE(USERSELECT_ALL)
+    adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
+#endif
     return pos;
 }
        
@@ -804,6 +820,9 @@
             pos = startOfDocument(pos);
         break;
     }
+#if ENABLE(USERSELECT_ALL)
+    adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
+#endif
     return pos;
 }
 
@@ -956,6 +975,7 @@
         moveTo(position, userTriggered);
         break;
     case AlterationExtend:
+
         if (!m_selection.isCaret()
             && (granularity == WordGranularity || granularity == ParagraphGranularity || granularity == LineGranularity)
             && m_frame && !m_frame->editor()->behavior().shouldExtendSelectionByWordOrLineAcrossCaret()) {
@@ -1365,7 +1385,7 @@
 
     if (!caretRectChanged) {
         RenderView* view = toRenderView(node->document()->renderer());
-        if (view && shouldRepaintCaret(view, node->isContentEditable()))
+        if (view && shouldRepaintCaret(view, node->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable)))
             view->repaintRectangleInViewAndCompositedLayers(caretRepaintRect(node), false);
     }
 }

Modified: trunk/Source/WebCore/editing/InsertNodeBeforeCommand.cpp (133223 => 133224)


--- trunk/Source/WebCore/editing/InsertNodeBeforeCommand.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/editing/InsertNodeBeforeCommand.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -48,7 +48,7 @@
 void InsertNodeBeforeCommand::doApply()
 {
     ContainerNode* parent = m_refChild->parentNode();
-    if (!parent || !parent->isContentEditable())
+    if (!parent || !parent->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable))
         return;
 
     ExceptionCode ec;
@@ -60,7 +60,7 @@
 
 void InsertNodeBeforeCommand::doUnapply()
 {
-    if (!m_insertChild->isContentEditable())
+    if (!m_insertChild->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable))
         return;
         
     // Need to notify this before actually deleting the text

Modified: trunk/Source/WebCore/editing/RemoveNodeCommand.cpp (133223 => 133224)


--- trunk/Source/WebCore/editing/RemoveNodeCommand.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/editing/RemoveNodeCommand.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -42,7 +42,7 @@
 void RemoveNodeCommand::doApply()
 {
     ContainerNode* parent = m_node->parentNode();
-    if (!parent || !parent->isContentEditable())
+    if (!parent || !parent->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable))
         return;
 
     m_parent = parent;

Modified: trunk/Source/WebCore/editing/visible_units.cpp (133223 => 133224)


--- trunk/Source/WebCore/editing/visible_units.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/editing/visible_units.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -1108,7 +1108,11 @@
 
     Node* n = startNode;
     while (n) {
+#if ENABLE(USERSELECT_ALL)
+        if (boundaryCrossingRule == CannotCrossEditingBoundary && !Position::nodeIsUserSelectAll(n) && n->rendererIsEditable() != startNode->rendererIsEditable())
+#else
         if (boundaryCrossingRule == CannotCrossEditingBoundary && n->rendererIsEditable() != startNode->rendererIsEditable())
+#endif
             break;
         if (boundaryCrossingRule == CanSkipOverEditingBoundary) {
             while (n && n->rendererIsEditable() != startNode->rendererIsEditable())
@@ -1184,7 +1188,11 @@
 
     Node* n = startNode;
     while (n) {
+#if ENABLE(USERSELECT_ALL)
+        if (boundaryCrossingRule == CannotCrossEditingBoundary && !Position::nodeIsUserSelectAll(n) && n->rendererIsEditable() != startNode->rendererIsEditable())
+#else
         if (boundaryCrossingRule == CannotCrossEditingBoundary && n->rendererIsEditable() != startNode->rendererIsEditable())
+#endif
             break;
         if (boundaryCrossingRule == CanSkipOverEditingBoundary) {
             while (n && n->rendererIsEditable() != startNode->rendererIsEditable())

Modified: trunk/Source/WebCore/page/EventHandler.cpp (133223 => 133224)


--- trunk/Source/WebCore/page/EventHandler.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -418,14 +418,21 @@
     if (!dispatchSelectStart(targetNode))
         return false;
 
-    if (newSelection.isRange())
+    VisibleSelection selection(newSelection);
+#if ENABLE(USERSELECT_ALL)
+    if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode)) {
+        selection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
+        selection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
+    }
+#endif
+    if (selection.isRange())
         m_selectionInitiationState = ExtendedSelection;
     else {
         granularity = CharacterGranularity;
         m_selectionInitiationState = PlacedCaret;
     }
 
-    m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, granularity);
+    m_frame->selection()->setNonDirectionalSelectionIfNeeded(selection, granularity);
 
     return true;
 }
@@ -844,7 +851,25 @@
         newSelection = VisibleSelection(targetPosition);
     }
 
-    newSelection.setExtent(targetPosition);
+#if ENABLE(USERSELECT_ALL)
+    Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
+    if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
+        newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
+        newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
+    } else {
+        // Reset base for user select all when base is inside user-select-all area and extent < base.
+        if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
+            newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
+        
+        Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
+        if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
+            newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
+        else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
+            newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
+        else
+            newSelection.setExtent(targetPosition);
+    }
+#endif
     if (m_frame->selection()->granularity() != CharacterGranularity)
         newSelection.expandUsingGranularity(m_frame->selection()->granularity());
 

Modified: trunk/Source/WebCore/rendering/RootInlineBox.cpp (133223 => 133224)


--- trunk/Source/WebCore/rendering/RootInlineBox.cpp	2012-11-01 20:50:43 UTC (rev 133223)
+++ trunk/Source/WebCore/rendering/RootInlineBox.cpp	2012-11-01 20:54:20 UTC (rev 133224)
@@ -499,6 +499,10 @@
                  ((boxState == RenderObject::SelectionStart || boxState == RenderObject::SelectionEnd) &&
                   (state == RenderObject::SelectionNone || state == RenderObject::SelectionInside)))
             state = boxState;
+        else if (boxState == RenderObject::SelectionNone && state == RenderObject::SelectionStart) {
+            // We are past the end of the selection.
+            state = RenderObject::SelectionBoth;
+        }
         if (state == RenderObject::SelectionBoth)
             break;
     }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to