LayoutTests:
Reviewed by Darin.
<rdar://problem/5333725> -webkit-user-select: none makes selection difficult
* editing/selection/5333725-expected.checksum: Added.
* editing/selection/5333725-expected.png: Added.
* editing/selection/5333725-expected.txt: Added.
* editing/selection/5333725.html: Added.
Added a workaround for a bug where -webkit-user-select:none
has no effect on the body if placed on the html element:
* editing/selection/select-all-user-select-none.html:
WebCore:
Reviewed by Darin.
<rdar://problem/5333725> -webkit-user-select: none makes selection difficult
Let users create selections if they mouse down in a -webkit-user-select:none
region, just (continue to) disallow selection endpoints in those regions, and
don't paint those regions as selected if they are fully enclosed by a selection.
For example, in xxyyyxx where x is -webkit-user-select:none, a user can mouse down
between the first two xs and drag across yyy to the second two xs to create a
selection xx^yyy^xx.
* editing/SelectionController.cpp:
(WebCore::SelectionController::selectAll): Allow selectAll inside a root
that has -webkit-user-select:none, because it may contain content that
is selectable (VisiblePosition and Selection creation will keep Selection
endpoints out of -webkit-user-select:none regions).
* page/EventHandler.cpp:
(WebCore::EventHandler::selectClosestWordFromMouseEvent): Use canMouseDownStartSelect
instead of the ambiguously named shouldSelect().
(WebCore::EventHandler::handleMousePressEventTripleClick): Ditto.
(WebCore::EventHandler::handleMousePressEventSingleClick): Ditto.
(WebCore::EventHandler::updateSelectionForMouseDrag): Use canMouseDragExtendSelect.
(WebCore::EventHandler::selectCursor): Paint an ibeam in -webkit-user-select:none regions,
because you can click in those regions to create a selection.
(WebCore::EventHandler::canMouseDownStartSelect): Now fires the selectStart event, and
returns true in -webkit-user-select: none regions.
(WebCore::EventHandler::canMouseDragExtendSelect): This is identical to
canMouseDownStartSelect because of 12823, even though it seems strange that we would fire
the selectStart event here.
* page/EventHandler.h:
* rendering/RenderObject.cpp:
(WebCore::RenderObject::draggableNode): Only -webkit-user-select:ignore regions will
prevent selection creation.
* rendering/RenderObject.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@25057 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 27c2fcf..7560ac5 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,18 @@
+2007-08-13 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5333725> -webkit-user-select: none makes selection difficult
+
+ * editing/selection/5333725-expected.checksum: Added.
+ * editing/selection/5333725-expected.png: Added.
+ * editing/selection/5333725-expected.txt: Added.
+ * editing/selection/5333725.html: Added.
+
+ Added a workaround for a bug where -webkit-user-select:none
+ has no effect on the body if placed on the html element:
+ * editing/selection/select-all-user-select-none.html:
+
2007-08-13 Anders Carlsson <andersca@apple.com>
Reviewed by Maciej.
diff --git a/LayoutTests/editing/selection/5333725-expected.checksum b/LayoutTests/editing/selection/5333725-expected.checksum
new file mode 100644
index 0000000..b5df204
--- /dev/null
+++ b/LayoutTests/editing/selection/5333725-expected.checksum
@@ -0,0 +1 @@
+bf4c7f58044f385ff40ffc133572fa98
\ No newline at end of file
diff --git a/LayoutTests/editing/selection/5333725-expected.png b/LayoutTests/editing/selection/5333725-expected.png
new file mode 100644
index 0000000..bdddebf
--- /dev/null
+++ b/LayoutTests/editing/selection/5333725-expected.png
Binary files differ
diff --git a/LayoutTests/editing/selection/5333725-expected.txt b/LayoutTests/editing/selection/5333725-expected.txt
new file mode 100644
index 0000000..aecdf32
--- /dev/null
+++ b/LayoutTests/editing/selection/5333725-expected.txt
@@ -0,0 +1,16 @@
+layer at (0,0) size 800x600
+ RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x584
+ RenderBlock {DIV} at (0,0) size 784x18
+ RenderInline {SPAN} at (0,0) size 32x18
+ RenderText {#text} at (0,0) size 32x18
+ text run at (0,0) width 32: "0123"
+ RenderText {#text} at (32,0) size 16x18
+ text run at (32,0) width 16: "45"
+ RenderInline {SPAN} at (0,0) size 32x18
+ RenderText {#text} at (48,0) size 32x18
+ text run at (48,0) width 32: "6789"
+selection start: position 0 of child 1 {#text} of child 0 {DIV} of child 0 {BODY} of child 0 {HTML} of document
+selection end: position 2 of child 1 {#text} of child 0 {DIV} of child 0 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/selection/5333725.html b/LayoutTests/editing/selection/5333725.html
new file mode 100644
index 0000000..e5efb1d
--- /dev/null
+++ b/LayoutTests/editing/selection/5333725.html
@@ -0,0 +1,23 @@
+<div><span id="start" style="-webkit-user-select:none;">0123</span>45<span id="end" style="-webkit-user-select:none;">6789</span></div>
+
+<script>
+if (window.layoutTestController) {
+ start = document.getElementById("start");
+ x1 = start.offsetParent.offsetLeft + start.offsetLeft + start.offsetWidth / 2;
+ y1 = start.offsetParent.offsetTop + start.offsetTop + start.offsetHeight / 2;
+ eventSender.mouseMoveTo(x1, y1);
+ eventSender.mouseDown();
+
+ eventSender.leapForward(100);
+ eventSender.mouseMoveTo(x1 + 5, y1);
+ eventSender.leapForward(100);
+ eventSender.mouseMoveTo(x1 + 10, y1);
+
+ end = document.getElementById("end");
+ x2 = end.offsetParent.offsetLeft + end.offsetLeft + end.offsetWidth / 2;
+ y2 = end.offsetParent.offsetTop + end.offsetTop + end.offsetHeight / 2;
+
+ eventSender.mouseMoveTo(x2, y2);
+ eventSender.mouseUp();
+}
+</script>
diff --git a/LayoutTests/editing/selection/select-all-user-select-none.html b/LayoutTests/editing/selection/select-all-user-select-none.html
index c05c518..06ecd8b 100644
--- a/LayoutTests/editing/selection/select-all-user-select-none.html
+++ b/LayoutTests/editing/selection/select-all-user-select-none.html
@@ -1,7 +1,7 @@
<html>
<head>
<style>
- html {
+ body {
-webkit-user-select: none;
}
</style>
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 2e4a5dc..07639c5 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,40 @@
+2007-08-13 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5333725> -webkit-user-select: none makes selection difficult
+
+ Let users create selections if they mouse down in a -webkit-user-select:none
+ region, just (continue to) disallow selection endpoints in those regions, and
+ don't paint those regions as selected if they are fully enclosed by a selection.
+ For example, in xxyyyxx where x is -webkit-user-select:none, a user can mouse down
+ between the first two xs and drag across yyy to the second two xs to create a
+ selection xx^yyy^xx.
+
+ * editing/SelectionController.cpp:
+ (WebCore::SelectionController::selectAll): Allow selectAll inside a root
+ that has -webkit-user-select:none, because it may contain content that
+ is selectable (VisiblePosition and Selection creation will keep Selection
+ endpoints out of -webkit-user-select:none regions).
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::selectClosestWordFromMouseEvent): Use canMouseDownStartSelect
+ instead of the ambiguously named shouldSelect().
+ (WebCore::EventHandler::handleMousePressEventTripleClick): Ditto.
+ (WebCore::EventHandler::handleMousePressEventSingleClick): Ditto.
+ (WebCore::EventHandler::updateSelectionForMouseDrag): Use canMouseDragExtendSelect.
+ (WebCore::EventHandler::selectCursor): Paint an ibeam in -webkit-user-select:none regions,
+ because you can click in those regions to create a selection.
+ (WebCore::EventHandler::canMouseDownStartSelect): Now fires the selectStart event, and
+ returns true in -webkit-user-select: none regions.
+ (WebCore::EventHandler::canMouseDragExtendSelect): This is identical to
+ canMouseDownStartSelect because of 12823, even though it seems strange that we would fire
+ the selectStart event here.
+ * page/EventHandler.h:
+ * rendering/RenderObject.cpp:
+ (WebCore::RenderObject::draggableNode): Only -webkit-user-select:ignore regions will
+ prevent selection creation.
+ * rendering/RenderObject.h:
+
2007-08-13 Anders Carlsson <andersca@apple.com>
Reviewed by Maciej.
diff --git a/WebCore/editing/SelectionController.cpp b/WebCore/editing/SelectionController.cpp
index f3d9ec1..6d3cdb8 100644
--- a/WebCore/editing/SelectionController.cpp
+++ b/WebCore/editing/SelectionController.cpp
@@ -1171,7 +1171,7 @@
}
Node* root = isContentEditable() ? highestEditableRoot(m_sel.start()) : document->documentElement();
- if (!root || !root->renderer() || !root->renderer()->canSelect())
+ if (!root)
return;
Selection newSelection(Selection::selectionFromContentsOfNode(root));
if (m_frame->shouldChangeSelection(newSelection))
diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp
index ae1d1f6..e635678 100644
--- a/WebCore/page/EventHandler.cpp
+++ b/WebCore/page/EventHandler.cpp
@@ -152,7 +152,7 @@
Node* innerNode = result.targetNode();
Selection newSelection;
- if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect && innerNode->renderer()->shouldSelect()) {
+ if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
if (pos.isNotNull()) {
newSelection = Selection(pos);
@@ -193,8 +193,7 @@
return false;
Node* innerNode = event.targetNode();
- if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect
- && innerNode->renderer()->shouldSelect()))
+ if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
return false;
Selection newSelection;
@@ -220,8 +219,7 @@
return false;
Node* innerNode = event.targetNode();
- if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect
- && innerNode->renderer()->shouldSelect()))
+ if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
return false;
// Extend the selection if the Shift key is down, unless the click is in a link.
@@ -408,8 +406,8 @@
RenderObject* targetRenderer = targetNode->renderer();
if (!targetRenderer)
return;
-
- if (!targetRenderer->shouldSelect())
+
+ if (!canMouseDragExtendSelect(targetNode))
return;
VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint));
@@ -727,7 +725,7 @@
bool inResizer = false;
if (m_frame->view() && layer && layer->isPointInResizeControl(m_frame->view()->windowToContents(event.event().pos())))
inResizer = true;
- if ((editable || (renderer && renderer->isText() && renderer->canSelect())) && !inResizer && !scrollbar)
+ if ((editable || (renderer && renderer->isText() && renderer->style()->userSelect() != SELECT_IGNORE)) && !inResizer && !scrollbar)
return iBeamCursor();
return pointerCursor();
}
@@ -1360,23 +1358,29 @@
m_hoverTimer.startOneShot(0);
}
+// Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event.
bool EventHandler::canMouseDownStartSelect(Node* node)
{
if (!node || !node->renderer())
return true;
- // Check to see if -webkit-user-select has been set to none
- if (!node->renderer()->canSelect())
- return false;
-
// Some controls and images can't start a select on a mouse down.
for (RenderObject* curr = node->renderer(); curr; curr = curr->parent())
if (curr->style()->userSelect() == SELECT_IGNORE)
return false;
+
+ for (RenderObject* curr = node->renderer(); curr; curr = curr->parent())
+ if (Node* node = curr->element())
+ return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true);
return true;
}
+bool EventHandler::canMouseDragExtendSelect(Node* node)
+{
+ return canMouseDownStartSelect(node);
+}
+
void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
{
m_frameSetBeingResized = frameSet;
diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h
index 98f11e7..92342dd 100644
--- a/WebCore/page/EventHandler.h
+++ b/WebCore/page/EventHandler.h
@@ -195,6 +195,7 @@
void hoverTimerFired(Timer<EventHandler>*);
static bool canMouseDownStartSelect(Node*);
+ static bool canMouseDragExtendSelect(Node*);
void handleAutoscroll(RenderObject*);
void startAutoscrollTimer();
diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp
index 18d5691..657bc7e 100644
--- a/WebCore/rendering/RenderObject.cpp
+++ b/WebCore/rendering/RenderObject.cpp
@@ -2011,40 +2011,6 @@
#endif // NDEBUG
-static Node* selectStartNode(const RenderObject* object)
-{
- Node* node = 0;
- bool forcedOn = false;
-
- for (const RenderObject* curr = object; curr; curr = curr->parent()) {
- if (curr->style()->userSelect() == SELECT_TEXT)
- forcedOn = true;
- if (!forcedOn && curr->style()->userSelect() == SELECT_NONE)
- return 0;
-
- if (!node)
- node = curr->element();
- }
-
- // somewhere up the render tree there must be an element!
- ASSERT(node);
-
- return node;
-}
-
-bool RenderObject::canSelect() const
-{
- return selectStartNode(this) != 0;
-}
-
-bool RenderObject::shouldSelect() const
-{
- if (Node* node = selectStartNode(this))
- return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true);
-
- return false;
-}
-
Color RenderObject::selectionBackgroundColor() const
{
Color color;
@@ -2093,7 +2059,7 @@
dhtmlWillDrag = false;
return curr->node();
}
- if (curr->shouldSelect())
+ if (curr->style()->userSelect() != SELECT_IGNORE)
// In this case we have a click in the unselected portion of text. If this text is
// selectable, we want to start the selection process instead of looking for a parent
// to try to drag.
diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h
index bfb07d7..b1ba0ef 100644
--- a/WebCore/rendering/RenderObject.h
+++ b/WebCore/rendering/RenderObject.h
@@ -754,13 +754,6 @@
// Whether or not a block has selected children.
virtual bool hasSelectedChildren() const { return false; }
- // Whether or not a selection can be attempted on this object.
- bool canSelect() const;
-
- // Whether or not a selection can be attempted on this object. Should only be called right before actually beginning a selection,
- // since it fires the selectstart DOM event.
- bool shouldSelect() const;
-
// Obtains the selection colors that should be used when painting a selection.
Color selectionBackgroundColor() const;
Color selectionForegroundColor() const;