summaryrefslogtreecommitdiffstats
path: root/WebCore/dom/Position.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/dom/Position.cpp')
-rw-r--r--WebCore/dom/Position.cpp79
1 files changed, 69 insertions, 10 deletions
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;