[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.17-1283-gcf603cf
enrica at apple.com
enrica at apple.com
Tue Jan 5 23:39:30 UTC 2010
The following commit has been merged in the webkit-1.1 branch:
commit a5412f5ea36edb703efbfef8a086541a4f27b466
Author: enrica at apple.com <enrica at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Tue Dec 1 00:44:30 2009 +0000
WebCore: Can focus but not type into content editable block that contains only non-editable content.
<rdar://problem/5982901>
https://bugs.webkit.org/show_bug.cgi?id=31750
Reviewed by Darin Adler.
The goal is to change the way we choose a visible position
after hit detection, by preferring a visually equivalent editable
position if available. By doing this, it is possible to add content
to an editable block that initially contains only non editable elements.
Test: editing/selection/mixed-editability-10.html
* WebCore.base.exp: Changed to match the new signature of downstream
and upstream in the Position class.
* dom/Position.cpp:
(WebCore::Position::atEditingBoundary): Added.
(WebCore::Position::upstream): Modified to allow to cross the boundary
between editable and non editable content if required.
(WebCore::Position::downstream): Modified to allow to cross the boundary
between editable and non editable content if required.
(WebCore::Position::isCandidate): Modified to qualify as candidates positions
that are at the editability boundary.
(WebCore::Position::getInlineBoxAndOffset): Modified to retrieve the inline box
to be used in calculating the caret rectangle.
* dom/Position.h:
(WebCore::Position::):
* dom/PositionIterator.cpp:
(WebCore::PositionIterator::atEditingBoundary): Added.
(WebCore::PositionIterator::isCandidate): Modified to qualify as candidates positions
that are at the editability boundary.
* dom/PositionIterator.h:
* editing/htmlediting.cpp:
(WebCore::firstEditablePositionAfterPositionInRoot): Modified to accept not only
descendants of the editable container, but the container itself.
(WebCore::lastEditablePositionBeforePositionInRoot): Modified to accept not only
descendants of the editable container, but the container itself.
* rendering/RenderObject.cpp:
(WebCore::RenderObject::createVisiblePosition): Added logic to prefer an editable position,
if available.
* rendering/RenderText.cpp:
(WebCore::RenderText::isAllCollapsibleWhitespace): Added.
* rendering/RenderText.h:
LayoutTests: Can focus but not type into content editable block that contains only non-editable content.
<rdar://problem/5982901>
https://bugs.webkit.org/show_bug.cgi?id=31750
Reviewed by Darin Adler.
* editing/selection/5825350-1-expected.txt:
* editing/selection/5825350-1.html: Modified to use caret rectangle.
* editing/selection/5825350-2-expected.txt:
* editing/selection/5825350-2.html: Modified to use caret rectangle.
* editing/selection/mixed-editability-10-expected.txt: Added.
* editing/selection/mixed-editability-10.html: Added.
* platform/mac/editing/deleting/5390681-2-expected.txt: Re-baselined
to account for the new possible caret position.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@51522 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 70aad6d..a784868 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,20 @@
+2009-11-30 Enrica Casucci <enrica at apple.com>
+
+ Reviewed by Darin Adler.
+
+ Can focus but not type into content editable block that contains only non-editable content.
+ <rdar://problem/5982901>
+ https://bugs.webkit.org/show_bug.cgi?id=31750
+
+ * editing/selection/5825350-1-expected.txt:
+ * editing/selection/5825350-1.html: Modified to use caret rectangle.
+ * editing/selection/5825350-2-expected.txt:
+ * editing/selection/5825350-2.html: Modified to use caret rectangle.
+ * editing/selection/mixed-editability-10-expected.txt: Added.
+ * editing/selection/mixed-editability-10.html: Added.
+ * platform/mac/editing/deleting/5390681-2-expected.txt: Re-baselined
+ to account for the new possible caret position.
+
2009-11-30 Beth Dakin <bdakin at apple.com>
Reviewed by Oliver Hunt.
diff --git a/LayoutTests/editing/selection/5825350-1-expected.txt b/LayoutTests/editing/selection/5825350-1-expected.txt
index 0f3673f..62b125e 100644
--- a/LayoutTests/editing/selection/5825350-1-expected.txt
+++ b/LayoutTests/editing/selection/5825350-1-expected.txt
@@ -1,3 +1,3 @@
-This tests for a bug where moving the caret left towards a non-editable pocket of an editable region would make the caret disappear. The caret should be just after the 'b' in "Bob".
+This tests for a bug where moving the caret left towards a non-editable pocket of an editable region would make the caret disappear. The caret should be just before the 'B' in "Bob".
-Caret One: (" ; ", 0)
+Caret: (8, 538)
diff --git a/LayoutTests/editing/selection/5825350-1.html b/LayoutTests/editing/selection/5825350-1.html
index 743d3ed..5b06dcd 100644
--- a/LayoutTests/editing/selection/5825350-1.html
+++ b/LayoutTests/editing/selection/5825350-1.html
@@ -1,4 +1,4 @@
-<div id="description">This tests for a bug where moving the caret left towards a non-editable pocket of an editable region would make the caret disappear. The caret should be just after the 'b' in "Bob".</div>
+<div id="description">This tests for a bug where moving the caret left towards a non-editable pocket of an editable region would make the caret disappear. The caret should be just before the 'B' in "Bob".</div>
<div id="edit" contenteditable="true"><span contenteditable="false">Bob</span> ; <span contenteditable="false">Sally</span></div>
<script>
@@ -10,6 +10,8 @@ text = edit.childNodes[1];
s = window.getSelection();
s.setPosition(text, 0);
s.modify("move", "left", "character");
-if (window.layoutTestController)
- document.body.innerText = document.getElementById("description").innerText + "\n\nCaret One: (\"" + s.anchorNode.data + "\", " + s.anchorOffset + ")";
+if (window.layoutTestController) {
+ var caretRect = textInputController.firstRectForCharacterRange(textInputController.selectedRange()[0], 0);
+ document.body.innerText = document.getElementById("description").innerText + "\n\nCaret: (" + caretRect[0] + ", " + caretRect[1] + ")";
+}
</script>
diff --git a/LayoutTests/editing/selection/5825350-2-expected.txt b/LayoutTests/editing/selection/5825350-2-expected.txt
index 9707516..f906101 100644
--- a/LayoutTests/editing/selection/5825350-2-expected.txt
+++ b/LayoutTests/editing/selection/5825350-2-expected.txt
@@ -1,3 +1,3 @@
-This tests for a bug where moving the caret right towards a non-editable pocket of an editable region would make the caret disappear. The caret should be just before the 'S' in "Sally".
+This tests for a bug where moving the caret right towards a non-editable pocket of an editable region would make the caret disappear. The caret should be just after the 'y' in "Sally".
-Caret One: (" ; ", 3)
+Caret: (79, 538)
diff --git a/LayoutTests/editing/selection/5825350-2.html b/LayoutTests/editing/selection/5825350-2.html
index 6e7ef57..110b425 100644
--- a/LayoutTests/editing/selection/5825350-2.html
+++ b/LayoutTests/editing/selection/5825350-2.html
@@ -1,4 +1,4 @@
-<div id="description">This tests for a bug where moving the caret right towards a non-editable pocket of an editable region would make the caret disappear. The caret should be just before the 'S' in "Sally".</div>
+<div id="description">This tests for a bug where moving the caret right towards a non-editable pocket of an editable region would make the caret disappear. The caret should be just after the 'y' in "Sally".</div>
<div id="edit" contenteditable="true"><span contenteditable="false">Bob</span> ; <span contenteditable="false">Sally</span></div>
<script>
@@ -10,6 +10,8 @@ text = edit.childNodes[1];
s = window.getSelection();
s.setPosition(text, text.length);
s.modify("move", "right", "character");
-if (window.layoutTestController)
- document.body.innerText = document.getElementById("description").innerText + "\n\nCaret One: (\"" + s.anchorNode.data + "\", " + s.anchorOffset + ")";
+if (window.layoutTestController) {
+ var caretRect = textInputController.firstRectForCharacterRange(textInputController.selectedRange()[0], 0);
+ document.body.innerText = document.getElementById("description").innerText + "\n\nCaret: (" + caretRect[0] + ", " + caretRect[1] + ")";
+}
</script>
diff --git a/LayoutTests/editing/selection/mixed-editability-10-expected.txt b/LayoutTests/editing/selection/mixed-editability-10-expected.txt
new file mode 100644
index 0000000..c739819
--- /dev/null
+++ b/LayoutTests/editing/selection/mixed-editability-10-expected.txt
@@ -0,0 +1,21 @@
+#1 DIV element with a non-editable element only align center:
+
+Hello
+#2 DIV element with a non-editable element only align left:
+
+Hello
+#3 DIV element with a non-editable element only align right:
+
+Hello
+#4 DIV element with two non-editable elementwith padding:
+
+Hello World
+#5 DIV element empty
+
+Anchor ([object HTMLDivElement], 0 caret[40,540] refpos=40) is correct.
+Anchor ([object HTMLDivElement], 3 caret[75,540] refpos=75) is correct.
+Anchor ([object HTMLDivElement], 1 caret[43,472] refpos=43) is correct.
+Anchor ([object HTMLDivElement], 0 caret[8,472] refpos=8) is correct.
+Anchor ([object HTMLDivElement], 0 caret[73,404] refpos=73) is correct.
+Anchor ([object HTMLDivElement], 3 caret[47,336] refpos=47) is correct.
+Anchor ([object HTMLDivElement], 0 caret[58,268] refpos=58) is correct.
diff --git a/LayoutTests/editing/selection/mixed-editability-10.html b/LayoutTests/editing/selection/mixed-editability-10.html
new file mode 100644
index 0000000..fb7c1e7
--- /dev/null
+++ b/LayoutTests/editing/selection/mixed-editability-10.html
@@ -0,0 +1,106 @@
+<html>
+<head>
+ <title>This tests the ability to place the caret in an editable div that contains only non editable content</title>
+</head>
+<body>
+ <p>#1 DIV element with a non-editable element only <span style="color:red">align center</span>:</p>
+ <div style="width:100px;background-color:#cee;text-align: center;" contenteditable="true" id="edit1">
+ <span contenteditable="false" id="nonedit1">Hello</span>
+ </div>
+ <p>#2 DIV element with a non-editable element only <span style="color:red">align left</span>:</p>
+ <div style="width:100px;background-color:#cee;" contenteditable="true" id="edit2"><span contenteditable="false" id="nonedit2">Hello</span></div>
+ <p>#3 DIV element with a non-editable element only <span style="color:red">align right</span>:</p>
+ <div style="width:100px;background-color:#cee;text-align: right;" contenteditable="true" id="edit3">
+ <span contenteditable="false" id="nonedit3">Hello</span></div>
+ <p>#4 DIV element with two non-editable element<span style="color:red">with padding</span>:</p>
+ <div style="width:200px;background-color:#cee;" contenteditable="true" id="edit4">
+ <span contenteditable="false">Hello </span>
+ <span contenteditable="false" id="nonedit4">World</span>
+ </div>
+ <p>#5 DIV element empty</p>
+ <div style="width:100px;background-color:#cee;text-align: center;" contenteditable="true" id="edit5">
+ </div>
+ <ul id="console"></ul>
+</body>
+<script>
+function log(str) {
+ var li = document.createElement("li");
+ li.appendChild(document.createTextNode(str));
+ var console = document.getElementById("console");
+ console.appendChild(li);
+}
+
+function caretCoordinates()
+{
+ if (!window.textInputController)
+ return { x: 0, y :0 };
+ var caretRect = textInputController.firstRectForCharacterRange(textInputController.selectedRange()[0], 0);
+ return { x: caretRect[0], y: caretRect[1] };
+}
+
+function runTest(x, y, elem, offset, refpos) {
+ eventSender.mouseMoveTo(x, y);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+
+ var selection = window.getSelection();
+
+ var anchorNode = selection.anchorNode;
+ var anchorOffset = selection.anchorOffset;
+
+ var coord = caretCoordinates();
+ var anchorString = "Anchor (" + anchorNode + ", " + anchorOffset + " caret[" + coord.x + "," + coord.y + "] refpos=" + refpos + ")";
+ var anchorCorrect = anchorNode == elem && anchorOffset == offset && coord.x == refpos;
+ if (anchorCorrect)
+ log(anchorString + " is correct.");
+ else
+ log(anchorString + " is incorrect.");
+}
+
+function automaticTest() {
+ if (window.layoutTestController) {
+ window.layoutTestController.dumpAsText();
+
+ var elem;
+
+ // the div has text-alignment center
+ elem = document.getElementById("edit1");
+ x = elem.offsetLeft + 10;
+ y = elem.offsetTop + elem.offsetHeight / 2;
+ runTest(x, y, elem, 0, document.getElementById("nonedit1").offsetLeft);
+ x = elem.offsetLeft + elem.offsetWidth - 10;
+ runTest(x, y, elem, 3, document.getElementById("nonedit1").offsetLeft + document.getElementById("nonedit1").offsetWidth);
+
+ // the div has text-alignment left
+ elem = document.getElementById("edit2");
+ x = elem.offsetLeft + elem.offsetWidth - 10;
+ y = elem.offsetTop + elem.offsetHeight / 2;
+ runTest(x, y, elem, 1, document.getElementById("nonedit2").offsetLeft + document.getElementById("nonedit2").offsetWidth);
+ x = elem.offsetLeft;
+ runTest(x, y, elem, 0, document.getElementById("nonedit2").offsetLeft);
+
+ // the div has text-alignment right
+ elem = document.getElementById("edit3");
+ x = elem.offsetLeft + 10;
+ y = elem.offsetTop + elem.offsetHeight / 2;
+ runTest(x, y, elem, 0, document.getElementById("nonedit3").offsetLeft);
+
+ // the div contains 2 non editable span
+ elem = document.getElementById("edit4");
+ x = document.getElementById("nonedit4").offsetLeft;
+ y = elem.offsetTop + elem.offsetHeight / 2;
+ runTest(x, y, elem, 3, document.getElementById("nonedit4").offsetLeft);
+
+ // the div is empty
+ elem = document.getElementById("edit5");
+ x = elem.offsetLeft;
+ y = elem.offsetTop + elem.offsetHeight / 2;
+ runTest(x, y, elem, 0, (elem.offsetLeft + elem.offsetWidth)/2 + 4);
+ }
+}
+
+automaticTest();
+</script>
+</html>
diff --git a/LayoutTests/platform/mac/editing/deleting/5390681-2-expected.txt b/LayoutTests/platform/mac/editing/deleting/5390681-2-expected.txt
index 13ba0d1..a8bb54d 100644
--- a/LayoutTests/platform/mac/editing/deleting/5390681-2-expected.txt
+++ b/LayoutTests/platform/mac/editing/deleting/5390681-2-expected.txt
@@ -16,3 +16,4 @@ layer at (0,0) size 800x600
RenderInline {SPAN} at (0,0) size 20x18
RenderText {#text} at (0,0) size 20x18
text run at (0,0) width 20: "bar"
+caret: position 0 of child 2 {DIV} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index eb0e253..769717f 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,49 @@
+2009-11-30 Enrica Casucci <enrica at apple.com>
+
+ Reviewed by Darin Adler.
+
+ Can focus but not type into content editable block that contains only non-editable content.
+ <rdar://problem/5982901>
+ https://bugs.webkit.org/show_bug.cgi?id=31750
+
+ The goal is to change the way we choose a visible position
+ after hit detection, by preferring a visually equivalent editable
+ position if available. By doing this, it is possible to add content
+ to an editable block that initially contains only non editable elements.
+
+ Test: editing/selection/mixed-editability-10.html
+
+ * WebCore.base.exp: Changed to match the new signature of downstream
+ and upstream in the Position class.
+ * dom/Position.cpp:
+ (WebCore::Position::atEditingBoundary): Added.
+ (WebCore::Position::upstream): Modified to allow to cross the boundary
+ between editable and non editable content if required.
+ (WebCore::Position::downstream): Modified to allow to cross the boundary
+ between editable and non editable content if required.
+ (WebCore::Position::isCandidate): Modified to qualify as candidates positions
+ that are at the editability boundary.
+ (WebCore::Position::getInlineBoxAndOffset): Modified to retrieve the inline box
+ to be used in calculating the caret rectangle.
+ * dom/Position.h:
+ (WebCore::Position::):
+ * dom/PositionIterator.cpp:
+ (WebCore::PositionIterator::atEditingBoundary): Added.
+ (WebCore::PositionIterator::isCandidate): Modified to qualify as candidates positions
+ that are at the editability boundary.
+ * dom/PositionIterator.h:
+ * editing/htmlediting.cpp:
+ (WebCore::firstEditablePositionAfterPositionInRoot): Modified to accept not only
+ descendants of the editable container, but the container itself.
+ (WebCore::lastEditablePositionBeforePositionInRoot): Modified to accept not only
+ descendants of the editable container, but the container itself.
+ * rendering/RenderObject.cpp:
+ (WebCore::RenderObject::createVisiblePosition): Added logic to prefer an editable position,
+ if available.
+ * rendering/RenderText.cpp:
+ (WebCore::RenderText::isAllCollapsibleWhitespace): Added.
+ * rendering/RenderText.h:
+
2009-11-30 Kevin Ollivier <kevino at theolliviers.com>
wx build fix, add header needed for wx build.
diff --git a/WebCore/WebCore.base.exp b/WebCore/WebCore.base.exp
index f82c59a..5f94bbe 100644
--- a/WebCore/WebCore.base.exp
+++ b/WebCore/WebCore.base.exp
@@ -963,10 +963,10 @@ __ZNK7WebCore8Document31displayStringModifiedByEncodingERKNS_6StringE
__ZNK7WebCore8Document4bodyEv
__ZNK7WebCore8Document6domainEv
__ZNK7WebCore8IntPointcv8_NSPointEv
-__ZNK7WebCore8Position10downstreamEv
__ZNK7WebCore8Position25leadingWhitespacePositionENS_9EAffinityEb
__ZNK7WebCore8Position26trailingWhitespacePositionENS_9EAffinityEb
-__ZNK7WebCore8Position8upstreamEv
+__ZNK7WebCore8Position10downstreamENS0_27EditingBoundaryCrossingRuleE
+__ZNK7WebCore8Position8upstreamENS0_27EditingBoundaryCrossingRuleE
__ZNK7WebCore9DOMWindow27pendingUnloadEventListenersEv
__ZNK7WebCore9FloatRectcv7_NSRectEv
__ZNK7WebCore9FrameTree12traverseNextEPKNS_5FrameE
diff --git a/WebCore/dom/Position.cpp b/WebCore/dom/Position.cpp
index 060b28c..0ff8262 100644
--- a/WebCore/dom/Position.cpp
+++ b/WebCore/dom/Position.cpp
@@ -307,6 +307,27 @@ bool Position::atLastEditingPositionForNode() const
return m_offset >= lastOffsetForEditing(node());
}
+// A position is considered at editing boundary if one of the following is true:
+// 1. It is the first position in the node and the next visually equivalent position
+// is non editable.
+// 2. It is the last position in the node and the previous visually equivalent position
+// is non editable.
+// 3. It is an editable position and both the next and previous visually equivalent
+// positions are both non editable.
+bool Position::atEditingBoundary() const
+{
+ Position nextPosition = downstream(CanCrossEditingBoundary);
+ if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.node()->isContentEditable())
+ return true;
+
+ Position prevPosition = upstream(CanCrossEditingBoundary);
+ if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.node()->isContentEditable())
+ return true;
+
+ return nextPosition.isNotNull() && !nextPosition.node()->isContentEditable()
+ && prevPosition.isNotNull() && !prevPosition.node()->isContentEditable();
+}
+
bool Position::atStartOfTree() const
{
if (isNull())
@@ -448,7 +469,7 @@ static bool isStreamer(const PositionIterator& pos)
// and downstream() will return the right one.
// Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
// in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
-Position Position::upstream() const
+Position Position::upstream(EditingBoundaryCrossingRule rule) const
{
Node* startNode = node();
if (!startNode)
@@ -460,6 +481,7 @@ Position Position::upstream() const
PositionIterator currentPos = lastVisible;
bool startEditable = startNode->isContentEditable();
Node* lastNode = startNode;
+ bool boundaryCrossed = false;
for (; !currentPos.atStart(); currentPos.decrement()) {
Node* currentNode = currentPos.node();
@@ -468,8 +490,11 @@ Position Position::upstream() const
if (currentNode != lastNode) {
// Don't change editability.
bool currentEditable = currentNode->isContentEditable();
- if (startEditable != currentEditable)
- break;
+ if (startEditable != currentEditable) {
+ if (rule == CannotCrossEditingBoundary)
+ break;
+ boundaryCrossed = true;
+ }
lastNode = currentNode;
}
@@ -483,6 +508,11 @@ Position Position::upstream() const
if (!renderer || renderer->style()->visibility() != VISIBLE)
continue;
+ if (rule == CanCrossEditingBoundary && boundaryCrossed) {
+ lastVisible = currentPos;
+ break;
+ }
+
// track last visible streamer position
if (isStreamer(currentPos))
lastVisible = currentPos;
@@ -560,7 +590,7 @@ Position Position::upstream() const
// and upstream() will return the left one.
// Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
// in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
-Position Position::downstream() const
+Position Position::downstream(EditingBoundaryCrossingRule rule) const
{
Node* startNode = node();
if (!startNode)
@@ -572,6 +602,7 @@ Position Position::downstream() const
PositionIterator currentPos = lastVisible;
bool startEditable = startNode->isContentEditable();
Node* lastNode = startNode;
+ bool boundaryCrossed = false;
for (; !currentPos.atEnd(); currentPos.increment()) {
Node* currentNode = currentPos.node();
@@ -580,8 +611,12 @@ Position Position::downstream() const
if (currentNode != lastNode) {
// Don't change editability.
bool currentEditable = currentNode->isContentEditable();
- if (startEditable != currentEditable)
- break;
+ if (startEditable != currentEditable) {
+ if (rule == CannotCrossEditingBoundary)
+ break;
+ boundaryCrossed = true;
+ }
+
lastNode = currentNode;
}
@@ -604,6 +639,11 @@ Position Position::downstream() const
if (!renderer || renderer->style()->visibility() != VISIBLE)
continue;
+ if (rule == CanCrossEditingBoundary && boundaryCrossed) {
+ lastVisible = currentPos;
+ break;
+ }
+
// track last visible streamer position
if (isStreamer(currentPos))
lastVisible = currentPos;
@@ -704,10 +744,14 @@ bool Position::isCandidate() const
if (isTableElement(node()) || editingIgnoresContent(node()))
return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(node()->parent());
- if (!node()->hasTagName(htmlTag) && renderer->isBlockFlow() && !hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
- (toRenderBox(renderer)->height() || node()->hasTagName(bodyTag)))
- return atFirstEditingPositionForNode() && !nodeIsUserSelectNone(node());
-
+ if (!m_anchorNode->hasTagName(htmlTag) && renderer->isBlockFlow()) {
+ if (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)) {
+ if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
+ return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(node());
+ return m_anchorNode->isContentEditable() && !Position::nodeIsUserSelectNone(node()) && atEditingBoundary();
+ }
+ }
+
return false;
}
@@ -949,7 +993,22 @@ void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi
{
caretOffset = m_offset;
RenderObject* renderer = node()->renderer();
+
if (!renderer->isText()) {
+ if (renderer->isBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) {
+ bool lastPosition = caretOffset == lastOffsetInNode(node());
+ Node* startNode = lastPosition ? node()->childNode(caretOffset - 1) : node()->childNode(caretOffset);
+ while (startNode && (!startNode->renderer() || (startNode->isTextNode() && toRenderText(startNode->renderer())->isAllCollapsibleWhitespace())))
+ startNode = (lastPosition)? startNode->previousSibling(): startNode->nextSibling();
+ if (startNode) {
+ Position pos(startNode, 0);
+ pos = pos.downstream(CanCrossEditingBoundary);
+ pos.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
+ if (lastPosition && inlineBox)
+ caretOffset = inlineBox->caretMaxOffset();
+ return;
+ }
+ }
inlineBox = renderer->isBox() ? toRenderBox(renderer)->inlineBoxWrapper() : 0;
if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
return;
diff --git a/WebCore/dom/Position.h b/WebCore/dom/Position.h
index c08872d..1e0304e 100644
--- a/WebCore/dom/Position.h
+++ b/WebCore/dom/Position.h
@@ -56,6 +56,11 @@ public:
PositionIsBeforeAnchor
};
+ enum EditingBoundaryCrossingRule {
+ CanCrossEditingBoundary,
+ CannotCrossEditingBoundary
+ };
+
Position()
: m_offset(0)
, m_anchorType(PositionIsOffsetInAnchor)
@@ -130,6 +135,9 @@ public:
bool atFirstEditingPositionForNode() const;
bool atLastEditingPositionForNode() const;
+ // Retuns true if the visually equivalent positions around have different editability
+ bool atEditingBoundary() const;
+
bool atStartOfTree() const;
bool atEndOfTree() const;
@@ -139,8 +147,8 @@ public:
Position trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace = false) const;
// These return useful visually equivalent positions.
- Position upstream() const;
- Position downstream() const;
+ Position upstream(EditingBoundaryCrossingRule = CannotCrossEditingBoundary) const;
+ Position downstream(EditingBoundaryCrossingRule = CannotCrossEditingBoundary) const;
bool isCandidate() const;
bool inRenderedText() const;
diff --git a/WebCore/dom/PositionIterator.cpp b/WebCore/dom/PositionIterator.cpp
index 8d881ba..f5b65f5 100644
--- a/WebCore/dom/PositionIterator.cpp
+++ b/WebCore/dom/PositionIterator.cpp
@@ -156,10 +156,14 @@ bool PositionIterator::isCandidate() const
if (isTableElement(m_anchorNode) || editingIgnoresContent(m_anchorNode))
return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_anchorNode->parent());
- if (!m_anchorNode->hasTagName(htmlTag) && renderer->isBlockFlow() && !Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
- (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)))
- return atStartOfNode() && !Position::nodeIsUserSelectNone(m_anchorNode);
-
+ if (!m_anchorNode->hasTagName(htmlTag) && renderer->isBlockFlow()) {
+ if (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)) {
+ if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
+ return atStartOfNode() && !Position::nodeIsUserSelectNone(m_anchorNode);
+ return m_anchorNode->isContentEditable() && !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).atEditingBoundary();
+ }
+ }
+
return false;
}
diff --git a/WebCore/editing/htmlediting.cpp b/WebCore/editing/htmlediting.cpp
index 48a8e7c..8b1c98d 100644
--- a/WebCore/editing/htmlediting.cpp
+++ b/WebCore/editing/htmlediting.cpp
@@ -289,7 +289,7 @@ VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& positio
while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
p = isAtomicNode(p.node()) ? positionInParentAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
- if (p.node() && !p.node()->isDescendantOf(highestRoot))
+ if (p.node() && p.node() != highestRoot && !p.node()->isDescendantOf(highestRoot))
return VisiblePosition();
return VisiblePosition(p);
@@ -310,7 +310,7 @@ VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& positio
while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
p = isAtomicNode(p.node()) ? positionInParentBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
- if (p.node() && !p.node()->isDescendantOf(highestRoot))
+ if (p.node() && p.node() != highestRoot && !p.node()->isDescendantOf(highestRoot))
return VisiblePosition();
return VisiblePosition(p);
diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp
index 1e8e19f..37ac0cf 100644
--- a/WebCore/rendering/RenderObject.cpp
+++ b/WebCore/rendering/RenderObject.cpp
@@ -2366,9 +2366,20 @@ RenderBoxModelObject* RenderObject::offsetParent() const
VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity)
{
- // If this is a non-anonymous renderer, then it's simple.
- if (Node* node = this->node())
+ // If this is a non-anonymous renderer in an editable area, then it's simple.
+ if (Node* node = this->node()) {
+ if (!node->isContentEditable()) {
+ // If it can be found, we prefer a visually equivalent position that is editable.
+ Position position(node, offset);
+ Position candidate = position.downstream(Position::CanCrossEditingBoundary);
+ if (candidate.node()->isContentEditable())
+ return VisiblePosition(candidate, affinity);
+ candidate = position.upstream(Position::CanCrossEditingBoundary);
+ if (candidate.node()->isContentEditable())
+ return VisiblePosition(candidate, affinity);
+ }
return VisiblePosition(node, offset, affinity);
+ }
// We don't want to cross the boundary between editable and non-editable
// regions of the document, but that is either impossible or at least
diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp
index a4f53a2..95aa277 100644
--- a/WebCore/rendering/RenderText.cpp
+++ b/WebCore/rendering/RenderText.cpp
@@ -757,6 +757,17 @@ void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& f
setPrefWidthsDirty(false);
}
+bool RenderText::isAllCollapsibleWhitespace()
+{
+ int length = textLength();
+ const UChar* text = characters();
+ for (int i = 0; i < length; i++) {
+ if (!style()->isCollapsibleWhiteSpace(text[i]))
+ return false;
+ }
+ return true;
+}
+
bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
{
unsigned currPos;
diff --git a/WebCore/rendering/RenderText.h b/WebCore/rendering/RenderText.h
index 915ff40..d46bce9 100644
--- a/WebCore/rendering/RenderText.h
+++ b/WebCore/rendering/RenderText.h
@@ -121,7 +121,8 @@ public:
void checkConsistency() const;
virtual void calcPrefWidths(int leadWidth);
-
+ bool isAllCollapsibleWhitespace();
+
protected:
virtual void styleWillChange(StyleDifference, const RenderStyle*) { }
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list