- Revision
- 89683
- Author
- [email protected]
- Date
- 2011-06-24 10:45:00 -0700 (Fri, 24 Jun 2011)
Log Message
2011-06-24 Ryosuke Niwa <[email protected]>
Reviewed by Enrica Casucci.
Add BeforeChildren and AfterChildren to the Position's anchor types
https://bugs.webkit.org/show_bug.cgi?id=63100
Added PositionIsBeforeChildren and PositionIsAfterChildren to Position::AnchorType and deployed them in
firstPositionInNode and lastPositionInNode.
These new types of positions will let us express the first and the last positions in a non-text node in O(1).
No new tests because there is no new behavior or feature exposed.
* dom/Position.cpp:
(WebCore::Position::Position): Assert that the anchor type is not BeforeChildren and AfterChildren for text nodes.
(WebCore::Position::containerNode): For BeforeChildren and AfterChildren, the anchor node is the container node.
(WebCore::Position::computeOffsetInContainerNode): The offset in the container node is 0 for BeforeChildren and
the offset in the anchor node for AfterChildren.
(WebCore::Position::offsetForPositionAfterAnchor): Called by deprecatedNode; the anchor type could be AfterChildren.
(WebCore::Position::parentAnchoredEquivalent): If the anchor node is before or after children, then do the trick
for table and ignored contents like before or after anchor.
(WebCore::Position::computeNodeBeforePosition): Returns null for BeforeChildren and returns the last child of
the anchor node for AfterChildren.
(WebCore::Position::computeNodeAfterPosition): Returns the first child of the anchor node for BeforeChildren
(WebCore::Position::atFirstEditingPositionForNode): A position is at the last editing position if the anchor type
is BeforeChildren, or the anchor type is AfterChildren or AfterAnchor and the anchor doesn't have any children.
(WebCore::Position::atLastEditingPositionForNode): A position is at the last editing position if the anchor type
is AfterChildren.
(WebCore::Position::showAnchorTypeAndOffset): Supports BeforeChildren and AfterChildren.
* dom/Position.h:
(WebCore::Position::deprecatedEditingOffset): Returns m_offset if the anchor type is BeforeChildren.
(WebCore::firstPositionInNode): Returns a position in offset for a text node. Otherwise returns BeforeChildren.
(WebCore::lastPositionInNode): Returns a position in offset for a text node. Otherwise returns AfterChildren.
* editing/CompositeEditCommand.cpp:
(WebCore::CompositeEditCommand::positionOutsideTabSpan): Since the anchor node was a text node,
the anchor type shouldn't be BeforeChildren or AfterChildren.
* editing/DeleteSelectionCommand.cpp:
(WebCore::updatePositionForNodeRemoval): Supports BeforeChildren and AfterChildren.
(WebCore::DeleteSelectionCommand::handleGeneralDelete): Calls updatePositionForNodeRemoval on m_downstremEnd
when its anchor node is removed instead of manually updating the offset; also avoid calling moveToOffset
on BeforeChildren or AfterChildren position.
* editing/FormatBlockCommand.cpp:
(WebCore::FormatBlockCommand::formatRange): Since lastParagraphInBlockNode is used to insert a placeholder
after paragraphs below the block is moved into, it needs to be the position after the current last child in
the block instead of after children in the block; otherwise the position will move to the end of block.
* editing/VisiblePosition.cpp:
(WebCore::VisiblePosition::characterAfter): Since the container node is never a text for position before/after
children or before/after anchor, just return null for these anchor types.
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (89682 => 89683)
--- trunk/Source/WebCore/ChangeLog 2011-06-24 17:37:51 UTC (rev 89682)
+++ trunk/Source/WebCore/ChangeLog 2011-06-24 17:45:00 UTC (rev 89683)
@@ -1,3 +1,53 @@
+2011-06-24 Ryosuke Niwa <[email protected]>
+
+ Reviewed by Enrica Casucci.
+
+ Add BeforeChildren and AfterChildren to the Position's anchor types
+ https://bugs.webkit.org/show_bug.cgi?id=63100
+
+ Added PositionIsBeforeChildren and PositionIsAfterChildren to Position::AnchorType and deployed them in
+ firstPositionInNode and lastPositionInNode.
+
+ These new types of positions will let us express the first and the last positions in a non-text node in O(1).
+
+ No new tests because there is no new behavior or feature exposed.
+
+ * dom/Position.cpp:
+ (WebCore::Position::Position): Assert that the anchor type is not BeforeChildren and AfterChildren for text nodes.
+ (WebCore::Position::containerNode): For BeforeChildren and AfterChildren, the anchor node is the container node.
+ (WebCore::Position::computeOffsetInContainerNode): The offset in the container node is 0 for BeforeChildren and
+ the offset in the anchor node for AfterChildren.
+ (WebCore::Position::offsetForPositionAfterAnchor): Called by deprecatedNode; the anchor type could be AfterChildren.
+ (WebCore::Position::parentAnchoredEquivalent): If the anchor node is before or after children, then do the trick
+ for table and ignored contents like before or after anchor.
+ (WebCore::Position::computeNodeBeforePosition): Returns null for BeforeChildren and returns the last child of
+ the anchor node for AfterChildren.
+ (WebCore::Position::computeNodeAfterPosition): Returns the first child of the anchor node for BeforeChildren
+ (WebCore::Position::atFirstEditingPositionForNode): A position is at the last editing position if the anchor type
+ is BeforeChildren, or the anchor type is AfterChildren or AfterAnchor and the anchor doesn't have any children.
+ (WebCore::Position::atLastEditingPositionForNode): A position is at the last editing position if the anchor type
+ is AfterChildren.
+ (WebCore::Position::showAnchorTypeAndOffset): Supports BeforeChildren and AfterChildren.
+ * dom/Position.h:
+ (WebCore::Position::deprecatedEditingOffset): Returns m_offset if the anchor type is BeforeChildren.
+ (WebCore::firstPositionInNode): Returns a position in offset for a text node. Otherwise returns BeforeChildren.
+ (WebCore::lastPositionInNode): Returns a position in offset for a text node. Otherwise returns AfterChildren.
+ * editing/CompositeEditCommand.cpp:
+ (WebCore::CompositeEditCommand::positionOutsideTabSpan): Since the anchor node was a text node,
+ the anchor type shouldn't be BeforeChildren or AfterChildren.
+ * editing/DeleteSelectionCommand.cpp:
+ (WebCore::updatePositionForNodeRemoval): Supports BeforeChildren and AfterChildren.
+ (WebCore::DeleteSelectionCommand::handleGeneralDelete): Calls updatePositionForNodeRemoval on m_downstremEnd
+ when its anchor node is removed instead of manually updating the offset; also avoid calling moveToOffset
+ on BeforeChildren or AfterChildren position.
+ * editing/FormatBlockCommand.cpp:
+ (WebCore::FormatBlockCommand::formatRange): Since lastParagraphInBlockNode is used to insert a placeholder
+ after paragraphs below the block is moved into, it needs to be the position after the current last child in
+ the block instead of after children in the block; otherwise the position will move to the end of block.
+ * editing/VisiblePosition.cpp:
+ (WebCore::VisiblePosition::characterAfter): Since the container node is never a text for position before/after
+ children or before/after anchor, just return null for these anchor types.
+
2011-06-24 Dominic Cooney <[email protected]>
Reviewed by Dimitri Glazkov.
Modified: trunk/Source/WebCore/dom/Position.cpp (89682 => 89683)
--- trunk/Source/WebCore/dom/Position.cpp 2011-06-24 17:37:51 UTC (rev 89682)
+++ trunk/Source/WebCore/dom/Position.cpp 2011-06-24 17:45:00 UTC (rev 89683)
@@ -91,6 +91,7 @@
{
ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot());
ASSERT(anchorType != PositionIsOffsetInAnchor);
+ ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIsAfterChildren) && m_anchorNode->isTextNode()));
}
Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorType)
@@ -135,6 +136,8 @@
return 0;
switch (anchorType()) {
+ case PositionIsBeforeChildren:
+ case PositionIsAfterChildren:
case PositionIsOffsetInAnchor:
return m_anchorNode.get();
case PositionIsBeforeAnchor:
@@ -151,6 +154,10 @@
return 0;
switch (anchorType()) {
+ case PositionIsBeforeChildren:
+ return 0;
+ case PositionIsAfterChildren:
+ return lastOffsetInNode(m_anchorNode.get());
case PositionIsOffsetInAnchor:
return std::min(lastOffsetInNode(m_anchorNode.get()), m_offset);
case PositionIsBeforeAnchor:
@@ -164,7 +171,7 @@
int Position::offsetForPositionAfterAnchor() const
{
- ASSERT(m_anchorType == PositionIsAfterAnchor);
+ ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren);
ASSERT(!m_isLegacyEditingPosition);
return lastOffsetForEditing(m_anchorNode.get());
}
@@ -177,12 +184,13 @@
return Position();
// FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
- if (m_offset <= 0 && m_anchorType != PositionIsAfterAnchor) {
+ if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType != PositionIsAfterChildren)) {
if (m_anchorNode->nonShadowBoundaryParentNode() && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get())))
return positionInParentBeforeNode(m_anchorNode.get());
- return firstPositionInOrBeforeNode(m_anchorNode.get());
+ return Position(m_anchorNode.get(), 0, PositionIsOffsetInAnchor);
}
- if (!m_anchorNode->offsetInCharacters() && (m_anchorType == PositionIsAfterAnchor || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount())
+ if (!m_anchorNode->offsetInCharacters()
+ && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount())
&& (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get()))
&& containerNode()) {
return positionInParentAfterNode(m_anchorNode.get());
@@ -197,6 +205,10 @@
return 0;
switch (anchorType()) {
+ case PositionIsBeforeChildren:
+ return 0;
+ case PositionIsAfterChildren:
+ return m_anchorNode->lastChild();
case PositionIsOffsetInAnchor:
return m_anchorNode->childNode(m_offset - 1); // -1 converts to childNode((unsigned)-1) and returns null.
case PositionIsBeforeAnchor:
@@ -214,6 +226,10 @@
return 0;
switch (anchorType()) {
+ case PositionIsBeforeChildren:
+ return m_anchorNode->firstChild();
+ case PositionIsAfterChildren:
+ return 0;
case PositionIsOffsetInAnchor:
return m_anchorNode->childNode(m_offset);
case PositionIsBeforeAnchor:
@@ -340,14 +356,29 @@
{
if (isNull())
return true;
- return m_anchorType == PositionIsBeforeAnchor || m_offset <= 0;
+ // FIXME: Position before anchor shouldn't be considered as at the first editing position for node
+ // since that position resides outside of the node.
+ switch (m_anchorType) {
+ case PositionIsOffsetInAnchor:
+ return m_offset <= 0;
+ case PositionIsBeforeChildren:
+ case PositionIsBeforeAnchor:
+ return true;
+ case PositionIsAfterChildren:
+ case PositionIsAfterAnchor:
+ return !lastOffsetForEditing(deprecatedNode());
+ }
+ ASSERT_NOT_REACHED();
+ return false;
}
bool Position::atLastEditingPositionForNode() const
{
if (isNull())
return true;
- return m_anchorType == PositionIsAfterAnchor || m_offset >= lastOffsetForEditing(deprecatedNode());
+ // FIXME: Position after anchor shouldn't be considered as at the first editing position for node
+ // since that position resides outside of the node.
+ return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || m_offset >= lastOffsetForEditing(deprecatedNode());
}
// A position is considered at editing boundary if one of the following is true:
@@ -1269,12 +1300,18 @@
case PositionIsOffsetInAnchor:
fputs("offset", stderr);
break;
- case PositionIsAfterAnchor:
- fputs("after", stderr);
+ case PositionIsBeforeChildren:
+ fputs("beforeChildren", stderr);
break;
+ case PositionIsAfterChildren:
+ fputs("afterChildren", stderr);
+ break;
case PositionIsBeforeAnchor:
fputs("before", stderr);
break;
+ case PositionIsAfterAnchor:
+ fputs("after", stderr);
+ break;
}
fprintf(stderr, ", offset:%d\n", m_offset);
}
Modified: trunk/Source/WebCore/dom/Position.h (89682 => 89683)
--- trunk/Source/WebCore/dom/Position.h 2011-06-24 17:37:51 UTC (rev 89682)
+++ trunk/Source/WebCore/dom/Position.h 2011-06-24 17:45:00 UTC (rev 89683)
@@ -54,8 +54,10 @@
public:
enum AnchorType {
PositionIsOffsetInAnchor,
+ PositionIsBeforeAnchor,
PositionIsAfterAnchor,
- PositionIsBeforeAnchor
+ PositionIsBeforeChildren,
+ PositionIsAfterChildren,
};
Position()
@@ -107,7 +109,7 @@
// New code should not use this function.
int deprecatedEditingOffset() const
{
- if (m_isLegacyEditingPosition || m_anchorType != PositionIsAfterAnchor)
+ if (m_isLegacyEditingPosition || (m_anchorType != PositionIsAfterAnchor && m_anchorType != PositionIsAfterChildren))
return m_offset;
return offsetForPositionAfterAnchor();
}
@@ -204,7 +206,7 @@
// returns true, then other places in editing will treat m_offset == 0 as "before the anchor"
// and m_offset > 0 as "after the anchor node". See parentAnchoredEquivalent for more info.
int m_offset;
- unsigned m_anchorType : 2;
+ unsigned m_anchorType : 3;
bool m_isLegacyEditingPosition : 1;
};
@@ -265,12 +267,16 @@
// firstPositionInNode and lastPositionInNode return parent-anchored positions, lastPositionInNode construction is O(n) due to childNodeCount()
inline Position firstPositionInNode(Node* anchorNode)
{
- return Position(anchorNode, 0, Position::PositionIsOffsetInAnchor);
+ if (anchorNode->isTextNode())
+ return Position(anchorNode, 0, Position::PositionIsOffsetInAnchor);
+ return Position(anchorNode, Position::PositionIsBeforeChildren);
}
inline Position lastPositionInNode(Node* anchorNode)
{
- return Position(anchorNode, lastOffsetInNode(anchorNode), Position::PositionIsOffsetInAnchor);
+ if (anchorNode->isTextNode())
+ return Position(anchorNode, lastOffsetInNode(anchorNode), Position::PositionIsOffsetInAnchor);
+ return Position(anchorNode, Position::PositionIsAfterChildren);
}
} // namespace WebCore
Modified: trunk/Source/WebCore/editing/CompositeEditCommand.cpp (89682 => 89683)
--- trunk/Source/WebCore/editing/CompositeEditCommand.cpp 2011-06-24 17:37:51 UTC (rev 89682)
+++ trunk/Source/WebCore/editing/CompositeEditCommand.cpp 2011-06-24 17:45:00 UTC (rev 89683)
@@ -373,10 +373,18 @@
if (!isTabSpanTextNode(pos.anchorNode()))
return pos;
- if (pos.anchorType() == Position::PositionIsAfterAnchor)
+ switch (pos.anchorType()) {
+ case Position::PositionIsBeforeChildren:
+ case Position::PositionIsAfterChildren:
+ ASSERT_NOT_REACHED();
+ return pos;
+ case Position::PositionIsOffsetInAnchor:
+ break;
+ case Position::PositionIsBeforeAnchor:
+ return positionInParentBeforeNode(pos.anchorNode());
+ case Position::PositionIsAfterAnchor:
return positionInParentAfterNode(pos.anchorNode());
- if (pos.anchorType() == Position::PositionIsBeforeAnchor)
- return positionInParentBeforeNode(pos.anchorNode());
+ }
Node* tabSpan = tabSpanNode(pos.containerNode());
Modified: trunk/Source/WebCore/editing/DeleteSelectionCommand.cpp (89682 => 89683)
--- trunk/Source/WebCore/editing/DeleteSelectionCommand.cpp 2011-06-24 17:37:51 UTC (rev 89682)
+++ trunk/Source/WebCore/editing/DeleteSelectionCommand.cpp 2011-06-24 17:45:00 UTC (rev 89683)
@@ -319,6 +319,14 @@
if (position.isNull())
return;
switch (position.anchorType()) {
+ case Position::PositionIsBeforeChildren:
+ if (position.containerNode() == node)
+ position = positionInParentBeforeNode(node);
+ break;
+ case Position::PositionIsAfterChildren:
+ if (position.containerNode() == node)
+ position = positionInParentAfterNode(node);
+ break;
case Position::PositionIsOffsetInAnchor:
if (position.containerNode() == node->parentNode() && static_cast<unsigned>(position.offsetInContainerNode()) > node->nodeIndex())
position.moveToOffset(position.offsetInContainerNode() - 1);
@@ -498,11 +506,7 @@
RefPtr<Node> nextNode = node->traverseNextSibling();
// if we just removed a node from the end container, update end position so the
// check above will work
- if (node->parentNode() == m_downstreamEnd.deprecatedNode()) {
- ASSERT(m_downstreamEnd.deprecatedEditingOffset());
- ASSERT(node->nodeIndex() < (unsigned)m_downstreamEnd.deprecatedEditingOffset());
- m_downstreamEnd.moveToOffset(m_downstreamEnd.deprecatedEditingOffset() - 1);
- }
+ updatePositionForNodeRemoval(node.get(), m_downstreamEnd);
removeNode(node.get());
node = nextNode.get();
} else {
@@ -542,7 +546,7 @@
offset = n->nodeIndex() + 1;
}
removeChildrenInRange(m_downstreamEnd.deprecatedNode(), offset, m_downstreamEnd.deprecatedEditingOffset());
- m_downstreamEnd.moveToOffset(offset);
+ m_downstreamEnd = createLegacyEditingPosition(m_downstreamEnd.deprecatedNode(), offset);
}
}
}
Modified: trunk/Source/WebCore/editing/FormatBlockCommand.cpp (89682 => 89683)
--- trunk/Source/WebCore/editing/FormatBlockCommand.cpp 2011-06-24 17:37:51 UTC (rev 89682)
+++ trunk/Source/WebCore/editing/FormatBlockCommand.cpp 2011-06-24 17:45:00 UTC (rev 89683)
@@ -86,7 +86,7 @@
insertNodeBefore(blockNode, nodeAfterInsertionPosition);
}
- Position lastParagraphInBlockNode = lastPositionInNode(blockNode.get());
+ Position lastParagraphInBlockNode = blockNode->lastChild() ? positionAfterNode(blockNode->lastChild()) : Position();
bool wasEndOfParagraph = isEndOfParagraph(lastParagraphInBlockNode);
moveParagraphWithClones(start, end, blockNode.get(), outerBlock.get());
Modified: trunk/Source/WebCore/editing/VisiblePosition.cpp (89682 => 89683)
--- trunk/Source/WebCore/editing/VisiblePosition.cpp 2011-06-24 17:37:51 UTC (rev 89682)
+++ trunk/Source/WebCore/editing/VisiblePosition.cpp 2011-06-24 17:45:00 UTC (rev 89683)
@@ -541,10 +541,17 @@
// We canonicalize to the first of two equivalent candidates, but the second of the two candidates
// is the one that will be inside the text node containing the character after this visible position.
Position pos = m_deepPosition.downstream();
- Node* node = pos.containerNode();
- if (!node || !node->isTextNode() || pos.anchorType() == Position::PositionIsAfterAnchor)
+ if (!pos.containerNode() || !pos.containerNode()->isTextNode())
return 0;
- ASSERT(pos.anchorType() == Position::PositionIsBeforeAnchor || pos.anchorType() == Position::PositionIsOffsetInAnchor);
+ switch (pos.anchorType()) {
+ case Position::PositionIsAfterChildren:
+ case Position::PositionIsAfterAnchor:
+ case Position::PositionIsBeforeAnchor:
+ case Position::PositionIsBeforeChildren:
+ return 0;
+ case Position::PositionIsOffsetInAnchor:
+ break;
+ }
Text* textNode = static_cast<Text*>(pos.containerNode());
unsigned offset = pos.anchorType() == Position::PositionIsOffsetInAnchor ? pos.offsetInContainerNode() : 0;
unsigned length = textNode->length();