summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/editing
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-24 11:24:40 +0100
committerBen Murdoch <benm@google.com>2011-06-02 09:53:15 +0100
commit81bc750723a18f21cd17d1b173cd2a4dda9cea6e (patch)
tree7a9e5ed86ff429fd347a25153107221543909b19 /Source/WebCore/editing
parent94088a6d336c1dd80a1e734af51e96abcbb689a7 (diff)
downloadexternal_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.zip
external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.gz
external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.bz2
Merge WebKit at r80534: Intial merge by Git
Change-Id: Ia7a83357124c9e1cdb1debf55d9661ec0bd09a61
Diffstat (limited to 'Source/WebCore/editing')
-rw-r--r--Source/WebCore/editing/ApplyBlockElementCommand.cpp32
-rw-r--r--Source/WebCore/editing/ApplyStyleCommand.cpp405
-rw-r--r--Source/WebCore/editing/ApplyStyleCommand.h24
-rw-r--r--Source/WebCore/editing/BreakBlockquoteCommand.cpp6
-rw-r--r--Source/WebCore/editing/CompositeEditCommand.cpp128
-rw-r--r--Source/WebCore/editing/DeleteSelectionCommand.cpp96
-rw-r--r--Source/WebCore/editing/EditCommand.cpp10
-rw-r--r--Source/WebCore/editing/EditCommand.h5
-rw-r--r--Source/WebCore/editing/EditingBoundary.h3
-rw-r--r--Source/WebCore/editing/EditingStyle.cpp432
-rw-r--r--Source/WebCore/editing/EditingStyle.h39
-rw-r--r--Source/WebCore/editing/Editor.cpp536
-rw-r--r--Source/WebCore/editing/Editor.h22
-rw-r--r--Source/WebCore/editing/EditorCommand.cpp54
-rw-r--r--Source/WebCore/editing/FormatBlockCommand.cpp4
-rw-r--r--Source/WebCore/editing/IndentOutdentCommand.cpp16
-rw-r--r--Source/WebCore/editing/InsertLineBreakCommand.cpp25
-rw-r--r--Source/WebCore/editing/InsertListCommand.cpp24
-rw-r--r--Source/WebCore/editing/InsertParagraphSeparatorCommand.cpp38
-rw-r--r--Source/WebCore/editing/InsertTextCommand.cpp37
-rw-r--r--Source/WebCore/editing/InsertTextCommand.h2
-rw-r--r--Source/WebCore/editing/ModifySelectionListLevel.cpp6
-rw-r--r--Source/WebCore/editing/MoveSelectionCommand.cpp9
-rw-r--r--Source/WebCore/editing/RemoveCSSPropertyCommand.h1
-rw-r--r--Source/WebCore/editing/ReplaceSelectionCommand.cpp114
-rw-r--r--Source/WebCore/editing/ReplaceSelectionCommand.h19
-rw-r--r--Source/WebCore/editing/SelectionController.cpp164
-rw-r--r--Source/WebCore/editing/SelectionController.h11
-rw-r--r--Source/WebCore/editing/SetSelectionCommand.cpp60
-rw-r--r--Source/WebCore/editing/SetSelectionCommand.h52
-rw-r--r--Source/WebCore/editing/SmartReplace.cpp4
-rw-r--r--Source/WebCore/editing/SmartReplaceICU.cpp4
-rw-r--r--Source/WebCore/editing/SpellChecker.cpp3
-rw-r--r--Source/WebCore/editing/SpellChecker.h6
-rw-r--r--Source/WebCore/editing/SpellingCorrectionCommand.cpp109
-rw-r--r--Source/WebCore/editing/SpellingCorrectionCommand.h53
-rw-r--r--Source/WebCore/editing/TextCheckingHelper.cpp11
-rw-r--r--Source/WebCore/editing/TextIterator.cpp72
-rw-r--r--Source/WebCore/editing/TextIterator.h13
-rw-r--r--Source/WebCore/editing/TypingCommand.cpp108
-rw-r--r--Source/WebCore/editing/TypingCommand.h29
-rw-r--r--Source/WebCore/editing/VisiblePosition.cpp84
-rw-r--r--Source/WebCore/editing/VisiblePosition.h8
-rw-r--r--Source/WebCore/editing/VisibleSelection.cpp66
-rw-r--r--Source/WebCore/editing/VisibleSelection.h3
-rw-r--r--Source/WebCore/editing/chromium/EditorChromium.cpp2
-rw-r--r--Source/WebCore/editing/chromium/SelectionControllerChromium.cpp2
-rw-r--r--Source/WebCore/editing/gtk/SelectionControllerGtk.cpp2
-rw-r--r--Source/WebCore/editing/htmlediting.cpp90
-rw-r--r--Source/WebCore/editing/mac/EditorMac.mm10
-rw-r--r--Source/WebCore/editing/mac/SelectionControllerMac.mm2
-rw-r--r--Source/WebCore/editing/markup.cpp8
-rw-r--r--Source/WebCore/editing/visible_units.cpp118
53 files changed, 1972 insertions, 1209 deletions
diff --git a/Source/WebCore/editing/ApplyBlockElementCommand.cpp b/Source/WebCore/editing/ApplyBlockElementCommand.cpp
index e700875..7e20acc 100644
--- a/Source/WebCore/editing/ApplyBlockElementCommand.cpp
+++ b/Source/WebCore/editing/ApplyBlockElementCommand.cpp
@@ -134,11 +134,11 @@ void ApplyBlockElementCommand::formatSelection(const VisiblePosition& startOfSel
// indentIntoBlockquote could move more than one paragraph if the paragraph
// is in a list item or a table. As a result, endAfterSelection could refer to a position
// no longer in the document.
- if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().node()->inDocument())
+ if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().anchorNode()->inDocument())
break;
- // Sanity check: Make sure our moveParagraph calls didn't remove endOfNextParagraph.deepEquivalent().node()
+ // Sanity check: Make sure our moveParagraph calls didn't remove endOfNextParagraph.deepEquivalent().deprecatedNode()
// If somehow we did, return to prevent crashes.
- if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().node()->inDocument()) {
+ if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().anchorNode()->inDocument()) {
ASSERT_NOT_REACHED();
return;
}
@@ -182,8 +182,8 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const
RenderStyle* startStyle = renderStyleOfEnclosingTextNode(start);
bool isStartAndEndOnSameNode = false;
if (startStyle) {
- isStartAndEndOnSameNode = renderStyleOfEnclosingTextNode(end) && start.node() == end.node();
- bool isStartAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && start.node() == m_endOfLastParagraph.node();
+ isStartAndEndOnSameNode = renderStyleOfEnclosingTextNode(end) && start.deprecatedNode() == end.deprecatedNode();
+ bool isStartAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && start.deprecatedNode() == m_endOfLastParagraph.deprecatedNode();
// Avoid obtanining the start of next paragraph for start
if (startStyle->preserveNewline() && isNewLineAtPosition(start) && !isNewLineAtPosition(start.previous()) && start.offsetInContainerNode() > 0)
@@ -192,15 +192,15 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const
// If start is in the middle of a text node, split.
if (!startStyle->collapseWhiteSpace() && start.offsetInContainerNode() > 0) {
int startOffset = start.offsetInContainerNode();
- splitTextNode(static_cast<Text*>(start.node()), startOffset);
- start = positionBeforeNode(start.node());
+ splitTextNode(static_cast<Text*>(start.deprecatedNode()), startOffset);
+ start = positionBeforeNode(start.deprecatedNode());
if (isStartAndEndOnSameNode) {
ASSERT(end.offsetInContainerNode() >= startOffset);
- end = Position(end.node(), end.offsetInContainerNode() - startOffset, Position::PositionIsOffsetInAnchor);
+ end = Position(end.deprecatedNode(), end.offsetInContainerNode() - startOffset, Position::PositionIsOffsetInAnchor);
}
if (isStartAndEndOfLastParagraphOnSameNode) {
ASSERT(m_endOfLastParagraph.offsetInContainerNode() >= startOffset);
- m_endOfLastParagraph = Position(m_endOfLastParagraph.node(), m_endOfLastParagraph.offsetInContainerNode() - startOffset,
+ m_endOfLastParagraph = Position(m_endOfLastParagraph.deprecatedNode(), m_endOfLastParagraph.offsetInContainerNode() - startOffset,
Position::PositionIsOffsetInAnchor);
}
}
@@ -208,13 +208,13 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const
RenderStyle* endStyle = renderStyleOfEnclosingTextNode(end);
if (endStyle) {
- bool isEndAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && end.node() == m_endOfLastParagraph.node();
+ bool isEndAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && end.deprecatedNode() == m_endOfLastParagraph.deprecatedNode();
// Include \n at the end of line if we're at an empty paragraph
if (endStyle->preserveNewline() && start == end
&& end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
int endOffset = end.offsetInContainerNode();
if (!isNewLineAtPosition(end.previous()) && isNewLineAtPosition(end))
- end = Position(end.node(), endOffset + 1, Position::PositionIsOffsetInAnchor);
+ end = Position(end.deprecatedNode(), endOffset + 1, Position::PositionIsOffsetInAnchor);
if (isEndAndEndOfLastParagraphOnSameNode && end.offsetInContainerNode() >= m_endOfLastParagraph.offsetInContainerNode())
m_endOfLastParagraph = end;
}
@@ -222,17 +222,17 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const
// If end is in the middle of a text node, split.
if (!endStyle->collapseWhiteSpace() && end.offsetInContainerNode()
&& end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
- splitTextNode(static_cast<Text*>(end.node()), end.offsetInContainerNode());
+ splitTextNode(static_cast<Text*>(end.deprecatedNode()), end.offsetInContainerNode());
if (isStartAndEndOnSameNode)
- start = positionBeforeNode(end.node()->previousSibling());
+ start = positionBeforeNode(end.deprecatedNode()->previousSibling());
if (isEndAndEndOfLastParagraphOnSameNode) {
if (m_endOfLastParagraph.offsetInContainerNode() == end.offsetInContainerNode())
- m_endOfLastParagraph = lastPositionInNode(end.node()->previousSibling());
+ m_endOfLastParagraph = lastPositionInNode(end.deprecatedNode()->previousSibling());
else
- m_endOfLastParagraph = Position(end.node(), m_endOfLastParagraph.offsetInContainerNode() - end.offsetInContainerNode(),
+ m_endOfLastParagraph = Position(end.deprecatedNode(), m_endOfLastParagraph.offsetInContainerNode() - end.offsetInContainerNode(),
Position::PositionIsOffsetInAnchor);
}
- end = lastPositionInNode(end.node()->previousSibling());
+ end = lastPositionInNode(end.deprecatedNode()->previousSibling());
}
}
}
diff --git a/Source/WebCore/editing/ApplyStyleCommand.cpp b/Source/WebCore/editing/ApplyStyleCommand.cpp
index ccade74..f9ed18e 100644
--- a/Source/WebCore/editing/ApplyStyleCommand.cpp
+++ b/Source/WebCore/editing/ApplyStyleCommand.cpp
@@ -141,8 +141,8 @@ StyleChange::StyleChange(CSSStyleDeclaration* style, const Position& position)
void StyleChange::init(PassRefPtr<CSSStyleDeclaration> style, const Position& position)
{
- Document* document = position.node() ? position.node()->document() : 0;
- if (!document || !document->frame())
+ Document* document = position.anchorNode() ? position.anchorNode()->document() : 0;
+ if (!style || !document || !document->frame())
return;
RefPtr<CSSComputedStyleDeclaration> computedStyle = position.computedStyle();
@@ -153,7 +153,7 @@ void StyleChange::init(PassRefPtr<CSSStyleDeclaration> style, const Position& po
extractTextStyles(document, mutableStyle.get(), computedStyle->useFixedFontDefaultSize());
// Changing the whitespace style in a tab span would collapse the tab into a space.
- if (isTabSpanTextNode(position.node()) || isTabSpanNode((position.node())))
+ if (isTabSpanTextNode(position.deprecatedNode()) || isTabSpanNode((position.deprecatedNode())))
mutableStyle->removeProperty(CSSPropertyWhiteSpace);
// If unicode-bidi is present in mutableStyle and direction is not, then add direction to mutableStyle.
@@ -274,7 +274,7 @@ void StyleChange::extractTextStyles(Document* document, CSSMutableStyleDeclarati
}
if (style->getPropertyCSSValue(CSSPropertyColor)) {
- m_applyFontColor = Color(getRGBAFontColor(style)).name();
+ m_applyFontColor = Color(getRGBAFontColor(style)).serialized();
style->removeProperty(CSSPropertyColor);
}
@@ -581,7 +581,7 @@ void ApplyStyleCommand::applyBlockStyle(EditingStyle *style)
// Save and restore the selection endpoints using their indices in the document, since
// addBlockStyleIfNeeded may moveParagraphs, which can remove these endpoints.
// Calculate start and end indices from the start of the tree that they're in.
- Node* scope = highestAncestor(visibleStart.deepEquivalent().node());
+ Node* scope = highestAncestor(visibleStart.deepEquivalent().deprecatedNode());
RefPtr<Range> startRange = Range::create(document(), firstPositionInNode(scope), visibleStart.deepEquivalent().parentAnchoredEquivalent());
RefPtr<Range> endRange = Range::create(document(), firstPositionInNode(scope), visibleEnd.deepEquivalent().parentAnchoredEquivalent());
int startIndex = TextIterator::rangeLength(startRange.get(), true);
@@ -593,7 +593,7 @@ void ApplyStyleCommand::applyBlockStyle(EditingStyle *style)
while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) {
StyleChange styleChange(style->style(), paragraphStart.deepEquivalent());
if (styleChange.cssStyle().length() || m_removeOnly) {
- RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().node());
+ RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().deprecatedNode());
if (!m_removeOnly) {
RefPtr<Node> newBlock = moveParagraphContentsToNewBlockIfNecessary(paragraphStart.deepEquivalent());
if (newBlock)
@@ -601,7 +601,7 @@ void ApplyStyleCommand::applyBlockStyle(EditingStyle *style)
}
ASSERT(block->isHTMLElement());
if (block->isHTMLElement()) {
- removeCSSStyle(style->style(), toHTMLElement(block.get()));
+ removeCSSStyle(style, toHTMLElement(block.get()));
if (!m_removeOnly)
addBlockStyle(styleChange, toHTMLElement(block.get()));
}
@@ -636,13 +636,13 @@ void ApplyStyleCommand::applyRelativeFontStyleChange(EditingStyle* style)
}
// Join up any adjacent text nodes.
- if (start.node()->isTextNode()) {
- joinChildTextNodes(start.node()->parentNode(), start, end);
+ if (start.deprecatedNode()->isTextNode()) {
+ joinChildTextNodes(start.deprecatedNode()->parentNode(), start, end);
start = startPosition();
end = endPosition();
}
- if (end.node()->isTextNode() && start.node()->parentNode() != end.node()->parentNode()) {
- joinChildTextNodes(end.node()->parentNode(), start, end);
+ if (end.deprecatedNode()->isTextNode() && start.deprecatedNode()->parentNode() != end.deprecatedNode()->parentNode()) {
+ joinChildTextNodes(end.deprecatedNode()->parentNode(), start, end);
start = startPosition();
end = endPosition();
}
@@ -664,13 +664,13 @@ void ApplyStyleCommand::applyRelativeFontStyleChange(EditingStyle* style)
// If the end node is before the start node (can only happen if the end node is
// an ancestor of the start node), we gather nodes up to the next sibling of the end node
Node *beyondEnd;
- if (start.node()->isDescendantOf(end.node()))
- beyondEnd = end.node()->traverseNextSibling();
+ if (start.deprecatedNode()->isDescendantOf(end.deprecatedNode()))
+ beyondEnd = end.deprecatedNode()->traverseNextSibling();
else
- beyondEnd = end.node()->traverseNextNode();
+ beyondEnd = end.deprecatedNode()->traverseNextNode();
start = start.upstream(); // Move upstream to ensure we do not add redundant spans.
- Node *startNode = start.node();
+ Node* startNode = start.deprecatedNode();
if (startNode->isTextNode() && start.deprecatedEditingOffset() >= caretMaxOffset(startNode)) // Move out of text node if range does not include its characters.
startNode = startNode->traverseNextNode();
@@ -856,7 +856,9 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
{
Node* startDummySpanAncestor = 0;
Node* endDummySpanAncestor = 0;
-
+
+ style->collapseTextDecorationProperties();
+
// update document layout once before removing styles
// so that we avoid the expense of updating before each and every call
// to check a computed style
@@ -874,25 +876,25 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
// split the start node and containing element if the selection starts inside of it
bool splitStart = isValidCaretPositionInTextNode(start);
if (splitStart) {
- if (shouldSplitTextElement(start.node()->parentElement(), style->style()))
+ if (shouldSplitTextElement(start.deprecatedNode()->parentElement(), style))
splitTextElementAtStart(start, end);
else
splitTextAtStart(start, end);
start = startPosition();
end = endPosition();
- startDummySpanAncestor = dummySpanAncestorForNode(start.node());
+ startDummySpanAncestor = dummySpanAncestorForNode(start.deprecatedNode());
}
// split the end node and containing element if the selection ends inside of it
bool splitEnd = isValidCaretPositionInTextNode(end);
if (splitEnd) {
- if (shouldSplitTextElement(end.node()->parentElement(), style->style()))
+ if (shouldSplitTextElement(end.deprecatedNode()->parentElement(), style))
splitTextElementAtEnd(start, end);
else
splitTextAtEnd(start, end);
start = startPosition();
end = endPosition();
- endDummySpanAncestor = dummySpanAncestorForNode(end.node());
+ endDummySpanAncestor = dummySpanAncestorForNode(end.deprecatedNode());
}
// Remove style from the selection.
@@ -901,18 +903,16 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
// and prevent us from adding redundant ones, as described in:
// <rdar://problem/3724344> Bolding and unbolding creates extraneous tags
Position removeStart = start.upstream();
- int unicodeBidi = getIdentifierValue(style->style(), CSSPropertyUnicodeBidi);
+ WritingDirection textDirection = NaturalWritingDirection;
+ bool hasTextDirection = style->textDirection(textDirection);
RefPtr<EditingStyle> styleWithoutEmbedding;
RefPtr<EditingStyle> embeddingStyle;
- if (unicodeBidi) {
- WritingDirection textDirection = NaturalWritingDirection;
- style->textDirection(textDirection);
-
+ if (hasTextDirection) {
// Leave alone an ancestor that provides the desired single level embedding, if there is one.
- HTMLElement* startUnsplitAncestor = splitAncestorsWithUnicodeBidi(start.node(), true, textDirection);
- HTMLElement* endUnsplitAncestor = splitAncestorsWithUnicodeBidi(end.node(), false, textDirection);
- removeEmbeddingUpToEnclosingBlock(start.node(), startUnsplitAncestor);
- removeEmbeddingUpToEnclosingBlock(end.node(), endUnsplitAncestor);
+ HTMLElement* startUnsplitAncestor = splitAncestorsWithUnicodeBidi(start.deprecatedNode(), true, textDirection);
+ HTMLElement* endUnsplitAncestor = splitAncestorsWithUnicodeBidi(end.deprecatedNode(), false, textDirection);
+ removeEmbeddingUpToEnclosingBlock(start.deprecatedNode(), startUnsplitAncestor);
+ removeEmbeddingUpToEnclosingBlock(end.deprecatedNode(), endUnsplitAncestor);
// Avoid removing the dir attribute and the unicode-bidi and direction properties from the unsplit ancestors.
Position embeddingRemoveStart = removeStart;
@@ -928,21 +928,19 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDirection();
if (comparePositions(embeddingRemoveStart, embeddingRemoveEnd) <= 0)
- removeInlineStyle(embeddingStyle->style(), embeddingRemoveStart, embeddingRemoveEnd);
+ removeInlineStyle(embeddingStyle.get(), embeddingRemoveStart, embeddingRemoveEnd);
}
}
- removeInlineStyle(styleWithoutEmbedding ? styleWithoutEmbedding->style() : style->style(), removeStart, end);
+ removeInlineStyle(styleWithoutEmbedding ? styleWithoutEmbedding.get() : style, removeStart, end);
start = startPosition();
end = endPosition();
if (start.isNull() || start.isOrphan() || end.isNull() || end.isOrphan())
return;
- if (splitStart) {
- if (mergeStartWithPreviousIfIdentical(start, end)) {
- start = startPosition();
- end = endPosition();
- }
+ if (splitStart && mergeStartWithPreviousIfIdentical(start, end)) {
+ start = startPosition();
+ end = endPosition();
}
if (splitEnd) {
@@ -956,11 +954,11 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
// to check a computed style
updateLayout();
- RefPtr<CSSMutableStyleDeclaration> styleToApply = style->isEmpty() ? CSSMutableStyleDeclaration::create() : style->style();
- if (unicodeBidi) {
+ RefPtr<EditingStyle> styleToApply = style;
+ if (hasTextDirection) {
// Avoid applying the unicode-bidi and direction properties beneath ancestors that already have them.
- Node* embeddingStartNode = highestEmbeddingAncestor(start.node(), enclosingBlock(start.node()));
- Node* embeddingEndNode = highestEmbeddingAncestor(end.node(), enclosingBlock(end.node()));
+ Node* embeddingStartNode = highestEmbeddingAncestor(start.deprecatedNode(), enclosingBlock(start.deprecatedNode()));
+ Node* embeddingEndNode = highestEmbeddingAncestor(end.deprecatedNode(), enclosingBlock(end.deprecatedNode()));
if (embeddingStartNode || embeddingEndNode) {
Position embeddingApplyStart = embeddingStartNode ? positionInParentAfterNode(embeddingStartNode) : start;
@@ -971,9 +969,9 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
styleWithoutEmbedding = style->copy();
embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDirection();
}
- fixRangeAndApplyInlineStyle(embeddingStyle->style(), embeddingApplyStart, embeddingApplyEnd);
+ fixRangeAndApplyInlineStyle(embeddingStyle.get(), embeddingApplyStart, embeddingApplyEnd);
- styleToApply = styleWithoutEmbedding->style();
+ styleToApply = styleWithoutEmbedding;
}
}
@@ -985,24 +983,24 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
cleanupUnstyledAppleStyleSpans(endDummySpanAncestor);
}
-void ApplyStyleCommand::fixRangeAndApplyInlineStyle(CSSMutableStyleDeclaration* style, const Position& start, const Position& end)
+void ApplyStyleCommand::fixRangeAndApplyInlineStyle(EditingStyle* style, const Position& start, const Position& end)
{
- Node* startNode = start.node();
+ Node* startNode = start.deprecatedNode();
- if (start.deprecatedEditingOffset() >= caretMaxOffset(start.node())) {
+ if (start.deprecatedEditingOffset() >= caretMaxOffset(start.deprecatedNode())) {
startNode = startNode->traverseNextNode();
if (!startNode || comparePositions(end, firstPositionInOrBeforeNode(startNode)) < 0)
return;
}
- Node* pastEndNode = end.node();
- if (end.deprecatedEditingOffset() >= caretMaxOffset(end.node()))
- pastEndNode = end.node()->traverseNextSibling();
+ Node* pastEndNode = end.deprecatedNode();
+ if (end.deprecatedEditingOffset() >= caretMaxOffset(end.deprecatedNode()))
+ pastEndNode = end.deprecatedNode()->traverseNextSibling();
// FIXME: Callers should perform this operation on a Range that includes the br
// if they want style applied to the empty line.
- if (start == end && start.node()->hasTagName(brTag))
- pastEndNode = start.node()->traverseNextNode();
+ if (start == end && start.deprecatedNode()->hasTagName(brTag))
+ pastEndNode = start.deprecatedNode()->traverseNextNode();
// Start from the highest fully selected ancestor so that we can modify the fully selected node.
// e.g. When applying font-size: large on <font color="blue">hello</font>, we need to include the font element in our run
@@ -1031,7 +1029,7 @@ static bool containsNonEditableRegion(Node* node)
return false;
}
-void ApplyStyleCommand::applyInlineStyleToNodeRange(CSSMutableStyleDeclaration* style, Node* node, Node* pastEndNode)
+void ApplyStyleCommand::applyInlineStyleToNodeRange(EditingStyle* style, Node* node, Node* pastEndNode)
{
if (m_removeOnly)
return;
@@ -1051,7 +1049,7 @@ void ApplyStyleCommand::applyInlineStyleToNodeRange(CSSMutableStyleDeclaration*
// Add to this element's inline style and skip over its contents.
HTMLElement* element = toHTMLElement(node);
RefPtr<CSSMutableStyleDeclaration> inlineStyle = element->getInlineStyleDecl()->copy();
- inlineStyle->merge(style);
+ inlineStyle->merge(style->style());
setNodeAttribute(element, styleAttr, inlineStyle->cssText());
next = node->traverseNextSibling();
continue;
@@ -1082,7 +1080,7 @@ void ApplyStyleCommand::applyInlineStyleToNodeRange(CSSMutableStyleDeclaration*
if (!removeStyleFromRunBeforeApplyingStyle(style, runStart, runEnd))
continue;
- addInlineStyleIfNeeded(style, runStart.get(), runEnd.get(), AddStyledElement);
+ addInlineStyleIfNeeded(style->style(), runStart.get(), runEnd.get(), AddStyledElement);
}
}
@@ -1092,7 +1090,7 @@ bool ApplyStyleCommand::isStyledInlineElementToRemove(Element* element) const
|| (m_isInlineElementToRemoveFunction && m_isInlineElementToRemoveFunction(element));
}
-bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(CSSMutableStyleDeclaration* style, RefPtr<Node>& runStart, RefPtr<Node>& runEnd)
+bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(EditingStyle* style, RefPtr<Node>& runStart, RefPtr<Node>& runEnd)
{
ASSERT(runStart && runEnd && runStart->parentNode() == runEnd->parentNode());
RefPtr<Node> pastEndNode = runEnd->traverseNextSibling();
@@ -1101,7 +1099,7 @@ bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(CSSMutableStyleDec
if (node->childNodeCount())
continue;
// We don't consider m_isInlineElementToRemoveFunction here because we never apply style when m_isInlineElementToRemoveFunction is specified
- if (getPropertiesNotIn(style, computedStyle(node).get())->length()
+ if ((!style->isEmpty() && getPropertiesNotIn(style->style(), computedStyle(node).get())->length())
|| (m_styledInlineElement && !enclosingNodeWithTag(positionBeforeNode(node), m_styledInlineElement->tagQName()))) {
needToApplyStyle = true;
break;
@@ -1132,7 +1130,7 @@ bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(CSSMutableStyleDec
return true;
}
-bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration* style, PassRefPtr<HTMLElement> element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
+bool ApplyStyleCommand::removeInlineStyleFromElement(EditingStyle* style, PassRefPtr<HTMLElement> element, InlineStyleRemovalMode mode, EditingStyle* extractedStyle)
{
ASSERT(element);
@@ -1143,13 +1141,17 @@ bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration*
if (mode == RemoveNone)
return true;
ASSERT(extractedStyle);
- if (element->inlineStyleDecl())
- extractedStyle->merge(element->inlineStyleDecl());
+ if (element->inlineStyleDecl()) {
+ if (extractedStyle->style())
+ extractedStyle->style()->merge(element->inlineStyleDecl());
+ else
+ extractedStyle->setStyle(element->inlineStyleDecl()->copy());
+ }
removeNodePreservingChildren(element);
return true;
}
- if (!style)
+ if (!style->style())
return false;
bool removed = false;
@@ -1167,109 +1169,6 @@ bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration*
return removed;
}
-enum EPushDownType { ShouldBePushedDown, ShouldNotBePushedDown };
-struct HTMLEquivalent {
- int propertyID;
- bool isValueList;
- int primitiveId;
- const QualifiedName* element;
- const QualifiedName* attribute;
- PassRefPtr<CSSValue> (*attributeToCSSValue)(int propertyID, const String&);
- EPushDownType pushDownType;
-};
-
-static PassRefPtr<CSSValue> stringToCSSValue(int propertyID, const String& value)
-{
- RefPtr<CSSMutableStyleDeclaration> dummyStyle;
- dummyStyle = CSSMutableStyleDeclaration::create();
- dummyStyle->setProperty(propertyID, value);
- return dummyStyle->getPropertyCSSValue(propertyID);
-}
-
-static PassRefPtr<CSSValue> fontSizeToCSSValue(int propertyID, const String& value)
-{
- UNUSED_PARAM(propertyID);
- ASSERT(propertyID == CSSPropertyFontSize);
- int size;
- if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size))
- return 0;
- return CSSPrimitiveValue::createIdentifier(size);
-}
-
-static const HTMLEquivalent HTMLEquivalents[] = {
- { CSSPropertyFontWeight, false, CSSValueBold, &bTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyFontWeight, false, CSSValueBold, &strongTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyVerticalAlign, false, CSSValueSub, &subTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyVerticalAlign, false, CSSValueSuper, &supTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyFontStyle, false, CSSValueItalic, &iTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyFontStyle, false, CSSValueItalic, &emTag, 0, 0, ShouldBePushedDown },
-
- // text-decorations should be CSSValueList
- { CSSPropertyTextDecoration, true, CSSValueUnderline, &uTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyTextDecoration, true, CSSValueLineThrough, &sTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyTextDecoration, true, CSSValueLineThrough, &strikeTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueUnderline, &uTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueLineThrough, &sTag, 0, 0, ShouldBePushedDown },
- { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueLineThrough, &strikeTag, 0, 0, ShouldBePushedDown },
-
- // FIXME: font attributes should only be removed if values were different
- { CSSPropertyColor, false, CSSValueInvalid, &fontTag, &colorAttr, stringToCSSValue, ShouldBePushedDown },
- { CSSPropertyFontFamily, false, CSSValueInvalid, &fontTag, &faceAttr, stringToCSSValue, ShouldBePushedDown },
- { CSSPropertyFontSize, false, CSSValueInvalid, &fontTag, &sizeAttr, fontSizeToCSSValue, ShouldBePushedDown },
-
- // unicode-bidi and direction are pushed down separately so don't push down with other styles.
- { CSSPropertyDirection, false, CSSValueInvalid, 0, &dirAttr, stringToCSSValue, ShouldNotBePushedDown },
- { CSSPropertyUnicodeBidi, false, CSSValueInvalid, 0, &dirAttr, stringToCSSValue, ShouldNotBePushedDown },
-};
-
-bool ApplyStyleCommand::removeImplicitlyStyledElement(CSSMutableStyleDeclaration* style, HTMLElement* element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
-{
- // Current implementation does not support stylePushedDown when mode == RemoveNone because of early exit.
- ASSERT(style);
- ASSERT(!extractedStyle || mode != RemoveNone);
- bool removed = false;
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(HTMLEquivalents); ++i) {
- const HTMLEquivalent& equivalent = HTMLEquivalents[i];
- ASSERT(equivalent.element || equivalent.attribute);
- if ((extractedStyle && equivalent.pushDownType == ShouldNotBePushedDown)
- || (equivalent.element && !element->hasTagName(*equivalent.element))
- || (equivalent.attribute && !element->hasAttribute(*equivalent.attribute)))
- continue;
-
- RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(equivalent.propertyID);
- if (!styleValue)
- continue;
- RefPtr<CSSValue> mapValue;
- if (equivalent.attribute)
- mapValue = equivalent.attributeToCSSValue(equivalent.propertyID, element->getAttribute(*equivalent.attribute));
- else
- mapValue = CSSPrimitiveValue::createIdentifier(equivalent.primitiveId).get();
-
- if (mode != RemoveAlways) {
- if (equivalent.isValueList && styleValue->isValueList() && static_cast<CSSValueList*>(styleValue.get())->hasValue(mapValue.get()))
- continue; // If CSS value assumes CSSValueList, then only skip if the value was present in style to apply.
- else if (mapValue && styleValue->cssText() == mapValue->cssText())
- continue; // If CSS value is primitive, then skip if they are equal.
- }
-
- if (extractedStyle && mapValue)
- extractedStyle->setProperty(equivalent.propertyID, mapValue->cssText());
-
- if (mode == RemoveNone)
- return true;
-
- removed = true;
- if (!equivalent.attribute) {
- replaceWithSpanOrRemoveIfWithoutAttributes(element);
- break;
- }
- removeNodeAttribute(element, *equivalent.attribute);
- if (isEmptyFontTag(element) || isSpanWithoutAttributesOrUnstyleStyleSpan(element))
- removeNodePreservingChildren(element);
- }
- return removed;
-}
-
void ApplyStyleCommand::replaceWithSpanOrRemoveIfWithoutAttributes(HTMLElement*& elem)
{
bool removeNode = false;
@@ -1293,53 +1192,65 @@ void ApplyStyleCommand::replaceWithSpanOrRemoveIfWithoutAttributes(HTMLElement*&
elem = newSpanElement;
}
}
-
-bool ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration* style, HTMLElement* element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
+
+bool ApplyStyleCommand::removeImplicitlyStyledElement(EditingStyle* style, HTMLElement* element, InlineStyleRemovalMode mode, EditingStyle* extractedStyle)
{
ASSERT(style);
- ASSERT(element);
+ if (mode == RemoveNone) {
+ ASSERT(!extractedStyle);
+ return style->conflictsWithImplicitStyleOfElement(element) || style->conflictsWithImplicitStyleOfAttributes(element);
+ }
+
+ ASSERT(mode == RemoveIfNeeded || mode == RemoveAlways);
+ if (style->conflictsWithImplicitStyleOfElement(element, extractedStyle, mode == RemoveAlways ? EditingStyle::ExtractMatchingStyle : EditingStyle::DoNotExtractMatchingStyle)) {
+ replaceWithSpanOrRemoveIfWithoutAttributes(element);
+ return true;
+ }
- CSSMutableStyleDeclaration* decl = element->inlineStyleDecl();
- if (!decl)
+ // unicode-bidi and direction are pushed down separately so don't push down with other styles
+ Vector<QualifiedName> attributes;
+ if (!style->extractConflictingImplicitStyleOfAttributes(element, extractedStyle ? EditingStyle::PreserveWritingDirection : EditingStyle::DoNotPreserveWritingDirection,
+ extractedStyle, attributes, mode == RemoveAlways ? EditingStyle::ExtractMatchingStyle : EditingStyle::DoNotExtractMatchingStyle))
return false;
- bool removed = false;
- CSSMutableStyleDeclaration::const_iterator end = style->end();
- for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
- CSSPropertyID propertyID = static_cast<CSSPropertyID>(it->id());
- RefPtr<CSSValue> value = decl->getPropertyCSSValue(propertyID);
- if (value && (propertyID != CSSPropertyWhiteSpace || !isTabSpanNode(element))) {
- removed = true;
- if (mode == RemoveNone)
- return true;
-
- ExceptionCode ec = 0;
- if (extractedStyle)
- extractedStyle->setProperty(propertyID, value->cssText(), decl->getPropertyPriority(propertyID), ec);
- removeCSSProperty(element, propertyID);
-
- if (propertyID == CSSPropertyUnicodeBidi && !decl->getPropertyValue(CSSPropertyDirection).isEmpty()) {
- if (extractedStyle)
- extractedStyle->setProperty(CSSPropertyDirection, decl->getPropertyValue(CSSPropertyDirection), decl->getPropertyPriority(CSSPropertyDirection), ec);
- removeCSSProperty(element, CSSPropertyDirection);
- }
- }
- }
+ for (size_t i = 0; i < attributes.size(); i++)
+ removeNodeAttribute(element, attributes[i]);
+
+ if (isEmptyFontTag(element) || isSpanWithoutAttributesOrUnstyleStyleSpan(element))
+ removeNodePreservingChildren(element);
+
+ return true;
+}
+
+bool ApplyStyleCommand::removeCSSStyle(EditingStyle* style, HTMLElement* element, InlineStyleRemovalMode mode, EditingStyle* extractedStyle)
+{
+ ASSERT(style);
+ ASSERT(element);
if (mode == RemoveNone)
- return removed;
+ return style->conflictsWithInlineStyleOfElement(element);
+
+ Vector<CSSPropertyID> properties;
+ if (!style->conflictsWithInlineStyleOfElement(element, extractedStyle, properties))
+ return false;
+
+ CSSMutableStyleDeclaration* inlineStyle = element->inlineStyleDecl();
+ ASSERT(inlineStyle);
+ // FIXME: We should use a mass-removal function here but we don't have an undoable one yet.
+ for (size_t i = 0; i < properties.size(); i++)
+ removeCSSProperty(element, properties[i]);
// No need to serialize <foo style=""> if we just removed the last css property
- if (decl->isEmpty())
+ if (inlineStyle->isEmpty())
removeNodeAttribute(element, styleAttr);
if (isSpanWithoutAttributesOrUnstyleStyleSpan(element))
removeNodePreservingChildren(element);
- return removed;
+ return true;
}
-HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(CSSMutableStyleDeclaration* style, Node* node)
+HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(EditingStyle* style, Node* node)
{
if (!node)
return 0;
@@ -1359,52 +1270,23 @@ HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(CSSMut
return result;
}
-void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, CSSMutableStyleDeclaration* style)
+void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, EditingStyle* style)
{
ASSERT(node);
- if (!style || !style->length() || !node->renderer())
+ if (!style || style->isEmpty() || !node->renderer())
return;
- RefPtr<CSSMutableStyleDeclaration> newInlineStyle = style;
- if (node->isHTMLElement()) {
- HTMLElement* element = toHTMLElement(node);
- CSSMutableStyleDeclaration* existingInlineStyle = element->inlineStyleDecl();
-
- // Avoid overriding existing styles of node
- if (existingInlineStyle) {
- newInlineStyle = existingInlineStyle->copy();
- CSSMutableStyleDeclaration::const_iterator end = style->end();
- for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
- ExceptionCode ec;
- if (!existingInlineStyle->getPropertyCSSValue(it->id()))
- newInlineStyle->setProperty(it->id(), it->value()->cssText(), it->isImportant(), ec);
-
- // text-decorations adds up
- if (it->id() == CSSPropertyTextDecoration && it->value()->isValueList()) {
- RefPtr<CSSValue> textDecoration = newInlineStyle->getPropertyCSSValue(CSSPropertyTextDecoration);
- if (textDecoration && textDecoration->isValueList()) {
- CSSValueList* textDecorationOfInlineStyle = static_cast<CSSValueList*>(textDecoration.get());
- CSSValueList* textDecorationOfStyleApplied = static_cast<CSSValueList*>(it->value());
-
- DEFINE_STATIC_LOCAL(RefPtr<CSSPrimitiveValue>, underline, (CSSPrimitiveValue::createIdentifier(CSSValueUnderline)));
- DEFINE_STATIC_LOCAL(RefPtr<CSSPrimitiveValue>, lineThrough, (CSSPrimitiveValue::createIdentifier(CSSValueLineThrough)));
-
- if (textDecorationOfStyleApplied->hasValue(underline.get()) && !textDecorationOfInlineStyle->hasValue(underline.get()))
- textDecorationOfInlineStyle->append(underline.get());
-
- if (textDecorationOfStyleApplied->hasValue(lineThrough.get()) && !textDecorationOfInlineStyle->hasValue(lineThrough.get()))
- textDecorationOfInlineStyle->append(lineThrough.get());
- }
- }
- }
- }
+ RefPtr<EditingStyle> newInlineStyle = style;
+ if (node->isHTMLElement() && static_cast<HTMLElement*>(node)->inlineStyleDecl()) {
+ newInlineStyle = style->copy();
+ newInlineStyle->mergeInlineStyleOfElement(static_cast<HTMLElement*>(node));
}
// Since addInlineStyleIfNeeded can't add styles to block-flow render objects, add style attribute instead.
// FIXME: applyInlineStyleToRange should be used here instead.
if ((node->renderer()->isBlockFlow() || node->childNodeCount()) && node->isHTMLElement()) {
- setNodeAttribute(toHTMLElement(node), styleAttr, newInlineStyle->cssText());
+ setNodeAttribute(toHTMLElement(node), styleAttr, newInlineStyle->style()->cssText());
return;
}
@@ -1414,10 +1296,10 @@ void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, CSSMutableStyleDe
// We can't wrap node with the styled element here because new styled element will never be removed if we did.
// If we modified the child pointer in pushDownInlineStyleAroundNode to point to new style element
// then we fall into an infinite loop where we keep removing and adding styled element wrapping node.
- addInlineStyleIfNeeded(newInlineStyle.get(), node, node, DoNotAddStyledElement);
+ addInlineStyleIfNeeded(newInlineStyle->style(), node, node, DoNotAddStyledElement);
}
-void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration* style, Node* targetNode)
+void ApplyStyleCommand::pushDownInlineStyleAroundNode(EditingStyle* style, Node* targetNode)
{
HTMLElement* highestAncestor = highestAncestorWithConflictingInlineStyle(style, targetNode);
if (!highestAncestor)
@@ -1439,7 +1321,7 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration
styledElement = static_cast<StyledElement*>(current);
elementsToPushDown.append(styledElement);
}
- RefPtr<CSSMutableStyleDeclaration> styleToPushDown = CSSMutableStyleDeclaration::create();
+ RefPtr<EditingStyle> styleToPushDown = EditingStyle::create();
removeInlineStyleFromElement(style, toHTMLElement(current), RemoveIfNeeded, styleToPushDown.get());
// The inner loop will go through children on each level
@@ -1474,20 +1356,14 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration
}
}
-void ApplyStyleCommand::removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration> style, const Position &start, const Position &end)
+void ApplyStyleCommand::removeInlineStyle(EditingStyle* style, const Position &start, const Position &end)
{
ASSERT(start.isNotNull());
ASSERT(end.isNotNull());
- ASSERT(start.node()->inDocument());
- ASSERT(end.node()->inDocument());
+ ASSERT(start.anchorNode()->inDocument());
+ ASSERT(end.anchorNode()->inDocument());
ASSERT(comparePositions(start, end) <= 0);
- RefPtr<CSSValue> textDecorationSpecialProperty = style ? style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) : 0;
- if (textDecorationSpecialProperty) {
- style = style->copy();
- style->setProperty(CSSPropertyTextDecoration, textDecorationSpecialProperty->cssText(), style->getPropertyPriority(CSSPropertyWebkitTextDecorationsInEffect));
- }
-
Position pushDownStart = start.downstream();
// If the pushDownStart is at the end of a text node, then this node is not fully selected.
// Move it to the next deep quivalent position to avoid removing the style from this node.
@@ -1497,40 +1373,41 @@ void ApplyStyleCommand::removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration>
&& pushDownStart.computeOffsetInContainerNode() == pushDownStartContainer->maxCharacterOffset())
pushDownStart = nextVisuallyDistinctCandidate(pushDownStart);
Position pushDownEnd = end.upstream();
- pushDownInlineStyleAroundNode(style.get(), pushDownStart.node());
- pushDownInlineStyleAroundNode(style.get(), pushDownEnd.node());
+
+ pushDownInlineStyleAroundNode(style, pushDownStart.deprecatedNode());
+ pushDownInlineStyleAroundNode(style, pushDownEnd.deprecatedNode());
// The s and e variables store the positions used to set the ending selection after style removal
// takes place. This will help callers to recognize when either the start node or the end node
// are removed from the document during the work of this function.
- // If pushDownInlineStyleAroundNode has pruned start.node() or end.node(),
+ // If pushDownInlineStyleAroundNode has pruned start.deprecatedNode() or end.deprecatedNode(),
// use pushDownStart or pushDownEnd instead, which pushDownInlineStyleAroundNode won't prune.
Position s = start.isNull() || start.isOrphan() ? pushDownStart : start;
Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end;
- Node* node = start.node();
+ Node* node = start.deprecatedNode();
while (node) {
RefPtr<Node> next = node->traverseNextNode();
if (node->isHTMLElement() && nodeFullySelected(node, start, end)) {
RefPtr<HTMLElement> elem = toHTMLElement(node);
RefPtr<Node> prev = elem->traversePreviousNodePostOrder();
RefPtr<Node> next = elem->traverseNextNode();
- RefPtr<CSSMutableStyleDeclaration> styleToPushDown;
+ RefPtr<EditingStyle> styleToPushDown;
PassRefPtr<Node> childNode = 0;
if (isStyledInlineElementToRemove(elem.get())) {
- styleToPushDown = CSSMutableStyleDeclaration::create();
+ styleToPushDown = EditingStyle::create();
childNode = elem->firstChild();
}
- removeInlineStyleFromElement(style.get(), elem.get(), RemoveIfNeeded, styleToPushDown.get());
+ removeInlineStyleFromElement(style, elem.get(), RemoveIfNeeded, styleToPushDown.get());
if (!elem->inDocument()) {
- if (s.node() == elem) {
+ if (s.deprecatedNode() == elem) {
// Since elem must have been fully selected, and it is at the start
// of the selection, it is clear we can set the new s offset to 0.
ASSERT(s.anchorType() == Position::PositionIsBeforeAnchor || s.offsetInContainerNode() <= 0);
s = firstPositionInOrBeforeNode(next.get());
}
- if (e.node() == elem) {
+ if (e.deprecatedNode() == elem) {
// Since elem must have been fully selected, and it is at the end
// of the selection, it is clear we can set the new e offset to
// the max range offset of prev.
@@ -1545,7 +1422,7 @@ void ApplyStyleCommand::removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration>
applyInlineStyleToPushDown(childNode.get(), styleToPushDown.get());
}
}
- if (node == end.node())
+ if (node == end.deprecatedNode())
break;
node = next.get();
}
@@ -1583,9 +1460,9 @@ void ApplyStyleCommand::splitTextAtStart(const Position& start, const Position&
else
newEnd = end;
- Text* text = static_cast<Text*>(start.node());
+ Text* text = static_cast<Text*>(start.deprecatedNode());
splitTextNode(text, start.offsetInContainerNode());
- updateStartEnd(firstPositionInNode(start.node()), newEnd);
+ updateStartEnd(firstPositionInNode(start.deprecatedNode()), newEnd);
}
void ApplyStyleCommand::splitTextAtEnd(const Position& start, const Position& end)
@@ -1593,7 +1470,7 @@ void ApplyStyleCommand::splitTextAtEnd(const Position& start, const Position& en
ASSERT(end.anchorType() == Position::PositionIsOffsetInAnchor);
bool shouldUpdateStart = start.anchorType() == Position::PositionIsOffsetInAnchor && start.containerNode() == end.containerNode();
- Text* text = static_cast<Text *>(end.node());
+ Text* text = static_cast<Text *>(end.deprecatedNode());
splitTextNode(text, end.offsetInContainerNode());
Node* prevNode = text->previousSibling();
@@ -1612,9 +1489,9 @@ void ApplyStyleCommand::splitTextElementAtStart(const Position& start, const Pos
else
newEnd = end;
- Text* text = static_cast<Text*>(start.node());
+ Text* text = static_cast<Text*>(start.deprecatedNode());
splitTextNodeContainingElement(text, start.deprecatedEditingOffset());
- updateStartEnd(Position(start.node()->parentNode(), start.node()->nodeIndex(), Position::PositionIsOffsetInAnchor), newEnd);
+ updateStartEnd(Position(start.deprecatedNode()->parentNode(), start.deprecatedNode()->nodeIndex(), Position::PositionIsOffsetInAnchor), newEnd);
}
void ApplyStyleCommand::splitTextElementAtEnd(const Position& start, const Position& end)
@@ -1622,7 +1499,7 @@ void ApplyStyleCommand::splitTextElementAtEnd(const Position& start, const Posit
ASSERT(end.anchorType() == Position::PositionIsOffsetInAnchor);
bool shouldUpdateStart = start.anchorType() == Position::PositionIsOffsetInAnchor && start.containerNode() == end.containerNode();
- Text* text = static_cast<Text*>(end.node());
+ Text* text = static_cast<Text*>(end.deprecatedNode());
splitTextNodeContainingElement(text, end.deprecatedEditingOffset());
Node* prevNode = text->parentNode()->previousSibling()->lastChild();
@@ -1631,7 +1508,7 @@ void ApplyStyleCommand::splitTextElementAtEnd(const Position& start, const Posit
updateStartEnd(newStart, Position(prevNode->parentNode(), prevNode->nodeIndex() + 1, Position::PositionIsOffsetInAnchor));
}
-bool ApplyStyleCommand::shouldSplitTextElement(Element* element, CSSMutableStyleDeclaration* style)
+bool ApplyStyleCommand::shouldSplitTextElement(Element* element, EditingStyle* style)
{
if (!element || !element->isHTMLElement())
return false;
@@ -1713,9 +1590,9 @@ bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position& start,
mergeIdenticalElements(previousElement, element);
int startOffsetAdjustment = startChild->nodeIndex();
- int endOffsetAdjustment = startNode == end.node() ? startOffsetAdjustment : 0;
+ int endOffsetAdjustment = startNode == end.deprecatedNode() ? startOffsetAdjustment : 0;
updateStartEnd(Position(startNode, startOffsetAdjustment, Position::PositionIsOffsetInAnchor),
- Position(end.node(), end.deprecatedEditingOffset() + endOffsetAdjustment, Position::PositionIsOffsetInAnchor));
+ Position(end.deprecatedNode(), end.deprecatedEditingOffset() + endOffsetAdjustment, Position::PositionIsOffsetInAnchor));
return true;
}
@@ -1731,11 +1608,11 @@ bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position& start, const
if (endOffset < lastOffsetInNode(endNode))
return false;
- unsigned parentLastOffset = end.node()->parentNode()->childNodes()->length() - 1;
- if (end.node()->nextSibling())
+ unsigned parentLastOffset = end.deprecatedNode()->parentNode()->childNodes()->length() - 1;
+ if (end.deprecatedNode()->nextSibling())
return false;
- endNode = end.node()->parentNode();
+ endNode = end.deprecatedNode()->parentNode();
endOffset = parentLastOffset;
}
@@ -1894,7 +1771,7 @@ void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style
surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), uTag));
if (styleChange.applyLineThrough())
- surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), sTag));
+ surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), strikeTag));
if (styleChange.applySubscript())
surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), subTag));
diff --git a/Source/WebCore/editing/ApplyStyleCommand.h b/Source/WebCore/editing/ApplyStyleCommand.h
index 1b2c2ef..d4444e4 100644
--- a/Source/WebCore/editing/ApplyStyleCommand.h
+++ b/Source/WebCore/editing/ApplyStyleCommand.h
@@ -77,16 +77,16 @@ private:
// style-removal helpers
bool isStyledInlineElementToRemove(Element*) const;
- bool removeStyleFromRunBeforeApplyingStyle(CSSMutableStyleDeclaration* style, RefPtr<Node>& runStart, RefPtr<Node>& runEnd);
- bool removeInlineStyleFromElement(CSSMutableStyleDeclaration*, PassRefPtr<HTMLElement>, InlineStyleRemovalMode = RemoveIfNeeded, CSSMutableStyleDeclaration* extractedStyle = 0);
- inline bool shouldRemoveInlineStyleFromElement(CSSMutableStyleDeclaration* style, HTMLElement* element) {return removeInlineStyleFromElement(style, element, RemoveNone);}
- bool removeImplicitlyStyledElement(CSSMutableStyleDeclaration*, HTMLElement*, InlineStyleRemovalMode, CSSMutableStyleDeclaration* extractedStyle);
+ bool removeStyleFromRunBeforeApplyingStyle(EditingStyle*, RefPtr<Node>& runStart, RefPtr<Node>& runEnd);
+ bool removeInlineStyleFromElement(EditingStyle*, PassRefPtr<HTMLElement>, InlineStyleRemovalMode = RemoveIfNeeded, EditingStyle* extractedStyle = 0);
+ inline bool shouldRemoveInlineStyleFromElement(EditingStyle* style, HTMLElement* element) {return removeInlineStyleFromElement(style, element, RemoveNone);}
void replaceWithSpanOrRemoveIfWithoutAttributes(HTMLElement*&);
- bool removeCSSStyle(CSSMutableStyleDeclaration*, HTMLElement*, InlineStyleRemovalMode = RemoveIfNeeded, CSSMutableStyleDeclaration* extractedStyle = 0);
- HTMLElement* highestAncestorWithConflictingInlineStyle(CSSMutableStyleDeclaration*, Node*);
- void applyInlineStyleToPushDown(Node*, CSSMutableStyleDeclaration *style);
- void pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration*, Node*);
- void removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration>, const Position& start, const Position& end);
+ bool removeImplicitlyStyledElement(EditingStyle*, HTMLElement*, InlineStyleRemovalMode, EditingStyle* extractedStyle);
+ bool removeCSSStyle(EditingStyle*, HTMLElement*, InlineStyleRemovalMode = RemoveIfNeeded, EditingStyle* extractedStyle = 0);
+ HTMLElement* highestAncestorWithConflictingInlineStyle(EditingStyle*, Node*);
+ void applyInlineStyleToPushDown(Node*, EditingStyle*);
+ void pushDownInlineStyleAroundNode(EditingStyle*, Node*);
+ void removeInlineStyle(EditingStyle* , const Position& start, const Position& end);
bool nodeFullySelected(Node*, const Position& start, const Position& end) const;
bool nodeFullyUnselected(Node*, const Position& start, const Position& end) const;
@@ -94,15 +94,15 @@ private:
void applyBlockStyle(EditingStyle*);
void applyRelativeFontStyleChange(EditingStyle*);
void applyInlineStyle(EditingStyle*);
- void fixRangeAndApplyInlineStyle(CSSMutableStyleDeclaration*, const Position& start, const Position& end);
- void applyInlineStyleToNodeRange(CSSMutableStyleDeclaration*, Node* startNode, Node* pastEndNode);
+ void fixRangeAndApplyInlineStyle(EditingStyle*, const Position& start, const Position& end);
+ void applyInlineStyleToNodeRange(EditingStyle*, Node* startNode, Node* pastEndNode);
void addBlockStyle(const StyleChange&, HTMLElement*);
void addInlineStyleIfNeeded(CSSMutableStyleDeclaration*, PassRefPtr<Node> start, PassRefPtr<Node> end, EAddStyledElement addStyledElement = AddStyledElement);
void splitTextAtStart(const Position& start, const Position& end);
void splitTextAtEnd(const Position& start, const Position& end);
void splitTextElementAtStart(const Position& start, const Position& end);
void splitTextElementAtEnd(const Position& start, const Position& end);
- bool shouldSplitTextElement(Element* elem, CSSMutableStyleDeclaration*);
+ bool shouldSplitTextElement(Element*, EditingStyle*);
bool isValidCaretPositionInTextNode(const Position& position);
bool mergeStartWithPreviousIfIdentical(const Position& start, const Position& end);
bool mergeEndWithNextIfIdentical(const Position& start, const Position& end);
diff --git a/Source/WebCore/editing/BreakBlockquoteCommand.cpp b/Source/WebCore/editing/BreakBlockquoteCommand.cpp
index ae409c6..011a787 100644
--- a/Source/WebCore/editing/BreakBlockquoteCommand.cpp
+++ b/Source/WebCore/editing/BreakBlockquoteCommand.cpp
@@ -67,7 +67,7 @@ void BreakBlockquoteCommand::doApply()
// Find the top-most blockquote from the start.
Element* topBlockquote = 0;
- for (ContainerNode* node = pos.node()->parentNode(); node; node = node->parentNode()) {
+ for (ContainerNode* node = pos.deprecatedNode()->parentNode(); node; node = node->parentNode()) {
if (isMailBlockquote(node))
topBlockquote = static_cast<Element*>(node);
}
@@ -103,11 +103,11 @@ void BreakBlockquoteCommand::doApply()
pos = pos.next();
// Adjust the position so we don't split at the beginning of a quote.
- while (isFirstVisiblePositionInNode(VisiblePosition(pos), nearestMailBlockquote(pos.node())))
+ while (isFirstVisiblePositionInNode(VisiblePosition(pos), nearestMailBlockquote(pos.deprecatedNode())))
pos = pos.previous();
// startNode is the first node that we need to move to the new blockquote.
- Node* startNode = pos.node();
+ Node* startNode = pos.deprecatedNode();
// Split at pos if in the middle of a text node.
if (startNode->isTextNode()) {
diff --git a/Source/WebCore/editing/CompositeEditCommand.cpp b/Source/WebCore/editing/CompositeEditCommand.cpp
index ac3d761..b7672ee 100644
--- a/Source/WebCore/editing/CompositeEditCommand.cpp
+++ b/Source/WebCore/editing/CompositeEditCommand.cpp
@@ -160,7 +160,7 @@ void CompositeEditCommand::insertNodeAt(PassRefPtr<Node> insertChild, const Posi
// For editing positions like [table, 0], insert before the table,
// likewise for replaced elements, brs, etc.
Position p = editingPosition.parentAnchoredEquivalent();
- Node* refChild = p.node();
+ Node* refChild = p.deprecatedNode();
int offset = p.deprecatedEditingOffset();
if (canHaveChildrenForEditing(refChild)) {
@@ -342,18 +342,23 @@ void CompositeEditCommand::replaceTextInNode(PassRefPtr<Text> node, unsigned off
Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos)
{
- if (!isTabSpanTextNode(pos.node()))
+ if (!isTabSpanTextNode(pos.anchorNode()))
return pos;
-
- Node* tabSpan = tabSpanNode(pos.node());
-
- if (pos.deprecatedEditingOffset() <= caretMinOffset(pos.node()))
+
+ if (pos.anchorType() == Position::PositionIsAfterAnchor)
+ return positionInParentAfterNode(pos.anchorNode());
+ if (pos.anchorType() == Position::PositionIsBeforeAnchor)
+ return positionInParentBeforeNode(pos.anchorNode());
+
+ Node* tabSpan = tabSpanNode(pos.containerNode());
+
+ if (pos.offsetInContainerNode() <= caretMinOffset(pos.containerNode()))
return positionInParentBeforeNode(tabSpan);
-
- if (pos.deprecatedEditingOffset() >= caretMaxOffset(pos.node()))
+
+ if (pos.offsetInContainerNode() >= caretMaxOffset(pos.containerNode()))
return positionInParentAfterNode(tabSpan);
- splitTextNodeContainingElement(static_cast<Text *>(pos.node()), pos.deprecatedEditingOffset());
+ splitTextNodeContainingElement(static_cast<Text *>(pos.containerNode()), pos.offsetInContainerNode());
return positionInParentBeforeNode(tabSpan);
}
@@ -475,7 +480,7 @@ void CompositeEditCommand::rebalanceWhitespaceOnTextSubstring(RefPtr<Text> textN
void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& position)
{
- Node* node = position.node();
+ Node* node = position.deprecatedNode();
if (!node || !node->isTextNode())
return;
Text* textNode = static_cast<Text*>(node);
@@ -495,10 +500,10 @@ void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& positio
VisiblePosition previousVisiblePos(visiblePos.previous());
Position previous(previousVisiblePos.deepEquivalent());
- if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous.node()->isTextNode() && !previous.node()->hasTagName(brTag))
- replaceTextInNode(static_cast<Text*>(previous.node()), previous.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
- if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.node()->isTextNode() && !position.node()->hasTagName(brTag))
- replaceTextInNode(static_cast<Text*>(position.node()), position.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
+ if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous.deprecatedNode()->isTextNode() && !previous.deprecatedNode()->hasTagName(brTag))
+ replaceTextInNode(static_cast<Text*>(previous.deprecatedNode()), previous.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
+ if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.deprecatedNode()->isTextNode() && !position.deprecatedNode()->hasTagName(brTag))
+ replaceTextInNode(static_cast<Text*>(position.deprecatedNode()), position.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
}
void CompositeEditCommand::rebalanceWhitespace()
@@ -600,15 +605,15 @@ void CompositeEditCommand::deleteInsignificantText(const Position& start, const
return;
Node* next;
- for (Node* node = start.node(); node; node = next) {
+ for (Node* node = start.deprecatedNode(); node; node = next) {
next = node->traverseNextNode();
if (node->isTextNode()) {
Text* textNode = static_cast<Text*>(node);
- int startOffset = node == start.node() ? start.deprecatedEditingOffset() : 0;
- int endOffset = node == end.node() ? end.deprecatedEditingOffset() : static_cast<int>(textNode->length());
+ int startOffset = node == start.deprecatedNode() ? start.deprecatedEditingOffset() : 0;
+ int endOffset = node == end.deprecatedNode() ? end.deprecatedEditingOffset() : static_cast<int>(textNode->length());
deleteInsignificantText(textNode, startOffset, endOffset);
}
- if (node == end.node())
+ if (node == end.deprecatedNode())
break;
}
}
@@ -638,7 +643,7 @@ PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& po
return 0;
// Should assert isBlockFlow || isInlineFlow when deletion improves. See 4244964.
- ASSERT(pos.node()->renderer());
+ ASSERT(pos.deprecatedNode()->renderer());
RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
insertNodeAt(placeholder, pos);
@@ -714,28 +719,26 @@ PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar
return 0;
// Perform some checks to see if we need to perform work in this function.
- if (isBlock(upstreamStart.node())) {
+ if (isBlock(upstreamStart.deprecatedNode())) {
// If the block is the root editable element, always move content to a new block,
// since it is illegal to modify attributes on the root editable element for editing.
- if (upstreamStart.node() == editableRootForPosition(upstreamStart)) {
+ if (upstreamStart.deprecatedNode() == editableRootForPosition(upstreamStart)) {
// If the block is the root editable element and it contains no visible content, create a new
// block but don't try and move content into it, since there's nothing for moveParagraphs to move.
- if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(upstreamStart.node()->renderer()))
+ if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(upstreamStart.deprecatedNode()->renderer()))
return insertNewDefaultParagraphElementAt(upstreamStart);
- } else if (isBlock(upstreamEnd.node())) {
- if (!upstreamEnd.node()->isDescendantOf(upstreamStart.node())) {
+ } else if (isBlock(upstreamEnd.deprecatedNode())) {
+ if (!upstreamEnd.deprecatedNode()->isDescendantOf(upstreamStart.deprecatedNode())) {
// If the paragraph end is a descendant of paragraph start, then we need to run
// the rest of this function. If not, we can bail here.
return 0;
}
- }
- else if (enclosingBlock(upstreamEnd.node()) != upstreamStart.node()) {
+ } else if (enclosingBlock(upstreamEnd.deprecatedNode()) != upstreamStart.deprecatedNode()) {
// The visibleEnd. It must be an ancestor of the paragraph start.
// We can bail as we have a full block to work with.
- ASSERT(upstreamStart.node()->isDescendantOf(enclosingBlock(upstreamEnd.node())));
+ ASSERT(upstreamStart.deprecatedNode()->isDescendantOf(enclosingBlock(upstreamEnd.deprecatedNode())));
return 0;
- }
- else if (isEndOfDocument(visibleEnd)) {
+ } else if (isEndOfDocument(visibleEnd)) {
// At the end of the document. We can bail here as well.
return 0;
}
@@ -743,7 +746,7 @@ PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar
RefPtr<Node> newBlock = insertNewDefaultParagraphElementAt(upstreamStart);
- bool endWasBr = visibleParagraphEnd.deepEquivalent().node()->hasTagName(brTag);
+ bool endWasBr = visibleParagraphEnd.deepEquivalent().deprecatedNode()->hasTagName(brTag);
moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(firstPositionInNode(newBlock.get())));
@@ -778,14 +781,14 @@ void CompositeEditCommand::cloneParagraphUnderNewElement(Position& start, Positi
appendNode(topNode, blockElement);
RefPtr<Node> lastNode = topNode;
- if (start.node() != outerNode) {
+ if (start.deprecatedNode() != outerNode) {
Vector<RefPtr<Node> > ancestors;
// Insert each node from innerNode to outerNode (excluded) in a list.
- for (Node* n = start.node(); n && n != outerNode; n = n->parentNode())
+ for (Node* n = start.deprecatedNode(); n && n != outerNode; n = n->parentNode())
ancestors.append(n);
- // Clone every node between start.node() and outerBlock.
+ // Clone every node between start.deprecatedNode() and outerBlock.
for (size_t i = ancestors.size(); i != 0; --i) {
Node* item = ancestors[i - 1].get();
@@ -796,25 +799,25 @@ void CompositeEditCommand::cloneParagraphUnderNewElement(Position& start, Positi
}
// Handle the case of paragraphs with more than one node,
- // cloning all the siblings until end.node() is reached.
+ // cloning all the siblings until end.deprecatedNode() is reached.
- if (start.node() != end.node() && !start.node()->isDescendantOf(end.node())) {
+ if (start.deprecatedNode() != end.deprecatedNode() && !start.deprecatedNode()->isDescendantOf(end.deprecatedNode())) {
// If end is not a descendant of outerNode we need to
// find the first common ancestor and adjust the insertion
// point accordingly.
- while (!end.node()->isDescendantOf(outerNode)) {
+ while (!end.deprecatedNode()->isDescendantOf(outerNode)) {
outerNode = outerNode->parentNode();
topNode = topNode->parentNode();
}
- for (Node* n = start.node()->traverseNextSibling(outerNode); n; n = n->traverseNextSibling(outerNode)) {
- if (n->parentNode() != start.node()->parentNode())
+ for (Node* n = start.deprecatedNode()->traverseNextSibling(outerNode); n; n = n->traverseNextSibling(outerNode)) {
+ if (n->parentNode() != start.deprecatedNode()->parentNode())
lastNode = topNode->lastChild();
RefPtr<Node> clonedNode = n->cloneNode(true);
insertNodeAfter(clonedNode, lastNode);
lastNode = clonedNode.release();
- if (n == end.node() || end.node()->isDescendantOf(n))
+ if (n == end.deprecatedNode() || end.deprecatedNode()->isDescendantOf(n))
break;
}
}
@@ -833,7 +836,7 @@ void CompositeEditCommand::cleanupAfterDeletion()
if (isStartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {
// Note: We want the rightmost candidate.
Position position = caretAfterDelete.deepEquivalent().downstream();
- Node* node = position.node();
+ Node* node = position.deprecatedNode();
// Normally deletion will leave a br as a placeholder.
if (node->hasTagName(brTag))
removeNodeAndPruneAncestors(node);
@@ -895,7 +898,7 @@ void CompositeEditCommand::moveParagraphWithClones(const VisiblePosition& startO
beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
- if (beforeParagraph.isNotNull() && !isTableElement(beforeParagraph.deepEquivalent().node())
+ if (beforeParagraph.isNotNull() && !isTableElement(beforeParagraph.deepEquivalent().deprecatedNode())
&& ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforeParagraph)) || beforeParagraph == afterParagraph)) {
// FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquivalent());
@@ -955,7 +958,7 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
// start and end can't be used directly to create a Range; they are "editing positions"
Position startRangeCompliant = start.parentAnchoredEquivalent();
Position endRangeCompliant = end.parentAnchoredEquivalent();
- RefPtr<Range> range = Range::create(document(), startRangeCompliant.node(), startRangeCompliant.deprecatedEditingOffset(), endRangeCompliant.node(), endRangeCompliant.deprecatedEditingOffset());
+ RefPtr<Range> range = Range::create(document(), startRangeCompliant.deprecatedNode(), startRangeCompliant.deprecatedEditingOffset(), endRangeCompliant.deprecatedNode(), endRangeCompliant.deprecatedEditingOffset());
// FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move. It
// shouldn't matter though, since moved paragraphs will usually be quite small.
@@ -969,7 +972,8 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
// too, <div><b><br></b></div> for example. Save it so that we can preserve it later.
RefPtr<EditingStyle> styleInEmptyParagraph;
if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle) {
- styleInEmptyParagraph = editingStyleIncludingTypingStyle(startOfParagraphToMove.deepEquivalent());
+ styleInEmptyParagraph = EditingStyle::create(startOfParagraphToMove.deepEquivalent());
+ styleInEmptyParagraph->mergeTypingStyle(document());
// The moved paragraph should assume the block style of the destination.
styleInEmptyParagraph->removeBlockProperties();
}
@@ -980,10 +984,10 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
document()->frame()->editor()->clearMisspellingsAndBadGrammar(endingSelection());
deleteSelection(false, false, false, false);
- ASSERT(destination.deepEquivalent().node()->inDocument());
+ ASSERT(destination.deepEquivalent().anchorNode()->inDocument());
cleanupAfterDeletion();
- ASSERT(destination.deepEquivalent().node()->inDocument());
+ ASSERT(destination.deepEquivalent().anchorNode()->inDocument());
// Add a br if pruning an empty block level element caused a collapse. For example:
// foo^
@@ -1006,7 +1010,10 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
setEndingSelection(destination);
ASSERT(endingSelection().isCaretOrRange());
- applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, true, false, !preserveStyle, false, true));
+ ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MovingParagraph;
+ if (!preserveStyle)
+ options |= ReplaceSelectionCommand::MatchStyle;
+ applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, options));
document()->frame()->editor()->markMisspellingsAndBadGrammar(endingSelection());
@@ -1035,7 +1042,8 @@ bool CompositeEditCommand::breakOutOfEmptyListItem()
if (!emptyListItem)
return false;
- RefPtr<EditingStyle> style = editingStyleIncludingTypingStyle(endingSelection().start());
+ RefPtr<EditingStyle> style = EditingStyle::create(endingSelection().start());
+ style->mergeTypingStyle(document());
ContainerNode* listNode = emptyListItem->parentNode();
// FIXME: Can't we do something better when the immediate parent wasn't a list node?
@@ -1125,25 +1133,25 @@ bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph()
// If this is an empty paragraph there must be a line break here.
if (!lineBreakExistsAtVisiblePosition(caret))
return false;
-
- Position caretPos(caret.deepEquivalent());
+
+ Position caretPos(caret.deepEquivalent().downstream());
// A line break is either a br or a preserved newline.
- ASSERT(caretPos.node()->hasTagName(brTag) || (caretPos.node()->isTextNode() && caretPos.node()->renderer()->style()->preserveNewline()));
+ ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedNode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveNewline()));
- if (caretPos.node()->hasTagName(brTag)) {
- Position beforeBR(positionInParentBeforeNode(caretPos.node()));
- removeNode(caretPos.node());
- prune(beforeBR.node());
- } else {
+ if (caretPos.deprecatedNode()->hasTagName(brTag)) {
+ Position beforeBR(positionInParentBeforeNode(caretPos.deprecatedNode()));
+ removeNode(caretPos.deprecatedNode());
+ prune(beforeBR.deprecatedNode());
+ } else if (caretPos.deprecatedNode()->isTextNode()) {
ASSERT(caretPos.deprecatedEditingOffset() == 0);
- Text* textNode = static_cast<Text*>(caretPos.node());
+ Text* textNode = static_cast<Text*>(caretPos.deprecatedNode());
ContainerNode* parentNode = textNode->parentNode();
// The preserved newline must be the first thing in the node, since otherwise the previous
// paragraph would be quoted, and we verified that it wasn't above.
deleteTextFromNode(textNode, 0, 1);
prune(parentNode);
}
-
+
return true;
}
@@ -1172,7 +1180,7 @@ Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
if (visiblePos == lastInAnchor) {
// Make sure anchors are pushed down before avoiding them so that we don't
// also avoid structural elements like lists and blocks (5142012).
- if (original.node() != enclosingAnchor && original.node()->parentNode() != enclosingAnchor) {
+ if (original.deprecatedNode() != enclosingAnchor && original.deprecatedNode()->parentNode() != enclosingAnchor) {
pushAnchorElementDown(enclosingAnchor);
enclosingAnchor = enclosingAnchorElement(original);
if (!enclosingAnchor)
@@ -1181,7 +1189,7 @@ Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
// Don't insert outside an anchor if doing so would skip over a line break. It would
// probably be safe to move the line break so that we could still avoid the anchor here.
Position downstream(visiblePos.deepEquivalent().downstream());
- if (lineBreakExistsAtVisiblePosition(visiblePos) && downstream.node()->isDescendantOf(enclosingAnchor))
+ if (lineBreakExistsAtVisiblePosition(visiblePos) && downstream.deprecatedNode()->isDescendantOf(enclosingAnchor))
return original;
result = positionInParentAfterNode(enclosingAnchor);
@@ -1191,7 +1199,7 @@ Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
if (visiblePos == firstInAnchor) {
// Make sure anchors are pushed down before avoiding them so that we don't
// also avoid structural elements like lists and blocks (5142012).
- if (original.node() != enclosingAnchor && original.node()->parentNode() != enclosingAnchor) {
+ if (original.deprecatedNode() != enclosingAnchor && original.deprecatedNode()->parentNode() != enclosingAnchor) {
pushAnchorElementDown(enclosingAnchor);
enclosingAnchor = enclosingAnchorElement(original);
}
diff --git a/Source/WebCore/editing/DeleteSelectionCommand.cpp b/Source/WebCore/editing/DeleteSelectionCommand.cpp
index 3ba5ae9..897c305 100644
--- a/Source/WebCore/editing/DeleteSelectionCommand.cpp
+++ b/Source/WebCore/editing/DeleteSelectionCommand.cpp
@@ -84,7 +84,7 @@ DeleteSelectionCommand::DeleteSelectionCommand(Document *document, bool smartDel
}
DeleteSelectionCommand::DeleteSelectionCommand(const VisibleSelection& selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
- : CompositeEditCommand(selection.start().node()->document()),
+ : CompositeEditCommand(selection.start().anchorNode()->document()),
m_hasSelectionToDelete(true),
m_smartDelete(smartDelete),
m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
@@ -110,10 +110,10 @@ void DeleteSelectionCommand::initializeStartEnd(Position& start, Position& end)
// For HRs, we'll get a position at (HR,1) when hitting delete from the beginning of the previous line, or (HR,0) when forward deleting,
// but in these cases, we want to delete it, so manually expand the selection
- if (start.node()->hasTagName(hrTag))
- start = positionBeforeNode(start.node());
- else if (end.node()->hasTagName(hrTag))
- end = positionAfterNode(end.node());
+ if (start.deprecatedNode()->hasTagName(hrTag))
+ start = positionBeforeNode(start.deprecatedNode());
+ else if (end.deprecatedNode()->hasTagName(hrTag))
+ end = positionAfterNode(end.deprecatedNode());
// FIXME: This is only used so that moveParagraphs can avoid the bugs in special element expansion.
if (!m_expandForSpecialElements)
@@ -275,7 +275,7 @@ void DeleteSelectionCommand::saveTypingStyleState()
// typing style at the start of the selection, nor is there a reason to
// compute the style at the start of the selection after deletion (see the
// early return in calculateTypingStyleAfterDelete).
- if (m_upstreamStart.node() == m_downstreamEnd.node() && m_upstreamStart.node()->isTextNode())
+ if (m_upstreamStart.deprecatedNode() == m_downstreamEnd.deprecatedNode() && m_upstreamStart.deprecatedNode()->isTextNode())
return;
// Figure out the typing style in effect before the delete is done.
@@ -284,7 +284,7 @@ void DeleteSelectionCommand::saveTypingStyleState()
// If we're deleting into a Mail blockquote, save the style at end() instead of start()
// We'll use this later in computeTypingStyleAfterDelete if we end up outside of a Mail blockquote
- if (nearestMailBlockquote(m_selectionToDelete.start().node()))
+ if (nearestMailBlockquote(m_selectionToDelete.start().deprecatedNode()))
m_deleteIntoBlockquoteStyle = EditingStyle::create(m_selectionToDelete.end());
else
m_deleteIntoBlockquoteStyle = 0;
@@ -293,11 +293,11 @@ void DeleteSelectionCommand::saveTypingStyleState()
bool DeleteSelectionCommand::handleSpecialCaseBRDelete()
{
// Check for special-case where the selection contains only a BR on a line by itself after another BR.
- bool upstreamStartIsBR = m_upstreamStart.node()->hasTagName(brTag);
- bool downstreamStartIsBR = m_downstreamStart.node()->hasTagName(brTag);
- bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && m_downstreamStart.node() == m_upstreamEnd.node();
+ bool upstreamStartIsBR = m_upstreamStart.deprecatedNode()->hasTagName(brTag);
+ bool downstreamStartIsBR = m_downstreamStart.deprecatedNode()->hasTagName(brTag);
+ bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && m_downstreamStart.deprecatedNode() == m_upstreamEnd.deprecatedNode();
if (isBROnLineByItself) {
- removeNode(m_downstreamStart.node());
+ removeNode(m_downstreamStart.deprecatedNode());
return true;
}
@@ -416,7 +416,7 @@ void DeleteSelectionCommand::deleteTextFromNode(PassRefPtr<Text> node, unsigned
void DeleteSelectionCommand::handleGeneralDelete()
{
int startOffset = m_upstreamStart.deprecatedEditingOffset();
- Node* startNode = m_upstreamStart.node();
+ Node* startNode = m_upstreamStart.deprecatedNode();
// Never remove the start block unless it's a table, in which case we won't merge content in.
if (startNode == m_startBlock && startOffset == 0 && canHaveChildrenForEditing(startNode) && !startNode->hasTagName(tableTag)) {
@@ -439,7 +439,7 @@ void DeleteSelectionCommand::handleGeneralDelete()
if (!startNode)
return;
- if (startNode == m_downstreamEnd.node()) {
+ if (startNode == m_downstreamEnd.deprecatedNode()) {
if (m_downstreamEnd.deprecatedEditingOffset() - startOffset > 0) {
if (startNode->isTextNode()) {
// in a text node that needs to be trimmed
@@ -456,7 +456,7 @@ void DeleteSelectionCommand::handleGeneralDelete()
removeNode(startNode);
}
else {
- bool startNodeWasDescendantOfEndNode = m_upstreamStart.node()->isDescendantOf(m_downstreamEnd.node());
+ bool startNodeWasDescendantOfEndNode = m_upstreamStart.deprecatedNode()->isDescendantOf(m_downstreamEnd.deprecatedNode());
// The selection to delete spans more than one node.
RefPtr<Node> node(startNode);
@@ -469,21 +469,21 @@ void DeleteSelectionCommand::handleGeneralDelete()
} else {
node = startNode->childNode(startOffset);
}
- } else if (startNode == m_upstreamEnd.node() && startNode->isTextNode()) {
- Text* text = static_cast<Text*>(m_upstreamEnd.node());
+ } else if (startNode == m_upstreamEnd.deprecatedNode() && startNode->isTextNode()) {
+ Text* text = static_cast<Text*>(m_upstreamEnd.deprecatedNode());
deleteTextFromNode(text, 0, m_upstreamEnd.deprecatedEditingOffset());
}
// handle deleting all nodes that are completely selected
- while (node && node != m_downstreamEnd.node()) {
+ while (node && node != m_downstreamEnd.deprecatedNode()) {
if (comparePositions(firstPositionInOrBeforeNode(node.get()), m_downstreamEnd) >= 0) {
// traverseNextSibling just blew past the end position, so stop deleting
node = 0;
- } else if (!m_downstreamEnd.node()->isDescendantOf(node.get())) {
+ } else if (!m_downstreamEnd.deprecatedNode()->isDescendantOf(node.get())) {
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.node()) {
+ if (node->parentNode() == m_downstreamEnd.deprecatedNode()) {
ASSERT(m_downstreamEnd.deprecatedEditingOffset());
ASSERT(node->nodeIndex() < (unsigned)m_downstreamEnd.deprecatedEditingOffset());
m_downstreamEnd.moveToOffset(m_downstreamEnd.deprecatedEditingOffset() - 1);
@@ -492,7 +492,7 @@ void DeleteSelectionCommand::handleGeneralDelete()
node = nextNode.get();
} else {
Node* n = node->lastDescendant();
- if (m_downstreamEnd.node() == n && m_downstreamEnd.deprecatedEditingOffset() >= caretMaxOffset(n)) {
+ if (m_downstreamEnd.deprecatedNode() == n && m_downstreamEnd.deprecatedEditingOffset() >= caretMaxOffset(n)) {
removeNode(node.get());
node = 0;
} else
@@ -500,33 +500,33 @@ void DeleteSelectionCommand::handleGeneralDelete()
}
}
- if (m_downstreamEnd.node() != startNode && !m_upstreamStart.node()->isDescendantOf(m_downstreamEnd.node()) && m_downstreamEnd.node()->inDocument() && m_downstreamEnd.deprecatedEditingOffset() >= caretMinOffset(m_downstreamEnd.node())) {
- if (m_downstreamEnd.atLastEditingPositionForNode() && !canHaveChildrenForEditing(m_downstreamEnd.node())) {
+ if (m_downstreamEnd.deprecatedNode() != startNode && !m_upstreamStart.deprecatedNode()->isDescendantOf(m_downstreamEnd.deprecatedNode()) && m_downstreamEnd.anchorNode()->inDocument() && m_downstreamEnd.deprecatedEditingOffset() >= caretMinOffset(m_downstreamEnd.deprecatedNode())) {
+ if (m_downstreamEnd.atLastEditingPositionForNode() && !canHaveChildrenForEditing(m_downstreamEnd.deprecatedNode())) {
// The node itself is fully selected, not just its contents. Delete it.
- removeNode(m_downstreamEnd.node());
+ removeNode(m_downstreamEnd.deprecatedNode());
} else {
- if (m_downstreamEnd.node()->isTextNode()) {
+ if (m_downstreamEnd.deprecatedNode()->isTextNode()) {
// in a text node that needs to be trimmed
- Text *text = static_cast<Text *>(m_downstreamEnd.node());
+ Text* text = static_cast<Text*>(m_downstreamEnd.deprecatedNode());
if (m_downstreamEnd.deprecatedEditingOffset() > 0) {
deleteTextFromNode(text, 0, m_downstreamEnd.deprecatedEditingOffset());
}
- // Remove children of m_downstreamEnd.node() that come after m_upstreamStart.
- // Don't try to remove children if m_upstreamStart was inside m_downstreamEnd.node()
+ // Remove children of m_downstreamEnd.deprecatedNode() that come after m_upstreamStart.
+ // Don't try to remove children if m_upstreamStart was inside m_downstreamEnd.deprecatedNode()
// and m_upstreamStart has been removed from the document, because then we don't
// know how many children to remove.
// FIXME: Make m_upstreamStart a position we update as we remove content, then we can
// always know which children to remove.
- } else if (!(startNodeWasDescendantOfEndNode && !m_upstreamStart.node()->inDocument())) {
+ } else if (!(startNodeWasDescendantOfEndNode && !m_upstreamStart.anchorNode()->inDocument())) {
int offset = 0;
- if (m_upstreamStart.node()->isDescendantOf(m_downstreamEnd.node())) {
- Node *n = m_upstreamStart.node();
- while (n && n->parentNode() != m_downstreamEnd.node())
+ if (m_upstreamStart.deprecatedNode()->isDescendantOf(m_downstreamEnd.deprecatedNode())) {
+ Node* n = m_upstreamStart.deprecatedNode();
+ while (n && n->parentNode() != m_downstreamEnd.deprecatedNode())
n = n->parentNode();
if (n)
offset = n->nodeIndex() + 1;
}
- removeChildrenInRange(m_downstreamEnd.node(), offset, m_downstreamEnd.deprecatedEditingOffset());
+ removeChildrenInRange(m_downstreamEnd.deprecatedNode(), offset, m_downstreamEnd.deprecatedEditingOffset());
m_downstreamEnd.moveToOffset(offset);
}
}
@@ -538,13 +538,13 @@ void DeleteSelectionCommand::fixupWhitespace()
{
updateLayout();
// FIXME: isRenderedCharacter should be removed, and we should use VisiblePosition::characterAfter and VisiblePosition::characterBefore
- if (m_leadingWhitespace.isNotNull() && !m_leadingWhitespace.isRenderedCharacter() && m_leadingWhitespace.node()->isTextNode()) {
- Text* textNode = static_cast<Text*>(m_leadingWhitespace.node());
+ if (m_leadingWhitespace.isNotNull() && !m_leadingWhitespace.isRenderedCharacter() && m_leadingWhitespace.deprecatedNode()->isTextNode()) {
+ Text* textNode = static_cast<Text*>(m_leadingWhitespace.deprecatedNode());
ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
replaceTextInNode(textNode, m_leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
}
- if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedCharacter() && m_trailingWhitespace.node()->isTextNode()) {
- Text* textNode = static_cast<Text*>(m_trailingWhitespace.node());
+ if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedCharacter() && m_trailingWhitespace.deprecatedNode()->isTextNode()) {
+ Text* textNode = static_cast<Text*>(m_trailingWhitespace.deprecatedNode());
ASSERT(!textNode->renderer() ||textNode->renderer()->style()->collapseWhiteSpace());
replaceTextInNode(textNode, m_trailingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
}
@@ -569,7 +569,7 @@ void DeleteSelectionCommand::mergeParagraphs()
ASSERT(!m_pruneStartBlockIfNecessary);
// FIXME: Deletion should adjust selection endpoints as it removes nodes so that we never get into this state (4099839).
- if (!m_downstreamEnd.node()->inDocument() || !m_upstreamStart.node()->inDocument())
+ if (!m_downstreamEnd.anchorNode()->inDocument() || !m_upstreamStart.anchorNode()->inDocument())
return;
// FIXME: The deletion algorithm shouldn't let this happen.
@@ -585,14 +585,14 @@ void DeleteSelectionCommand::mergeParagraphs()
// m_downstreamEnd's block has been emptied out by deletion. There is no content inside of it to
// move, so just remove it.
- Element* endBlock = static_cast<Element*>(enclosingBlock(m_downstreamEnd.node()));
- if (!startOfParagraphToMove.deepEquivalent().node() || !endBlock->contains(startOfParagraphToMove.deepEquivalent().node())) {
- removeNode(enclosingBlock(m_downstreamEnd.node()));
+ Element* endBlock = static_cast<Element*>(enclosingBlock(m_downstreamEnd.deprecatedNode()));
+ if (!startOfParagraphToMove.deepEquivalent().deprecatedNode() || !endBlock->contains(startOfParagraphToMove.deepEquivalent().deprecatedNode())) {
+ removeNode(enclosingBlock(m_downstreamEnd.deprecatedNode()));
return;
}
// We need to merge into m_upstreamStart's block, but it's been emptied out and collapsed by deletion.
- if (!mergeDestination.deepEquivalent().node() || !mergeDestination.deepEquivalent().node()->isDescendantOf(m_upstreamStart.node()->enclosingBlockFlowElement()) || m_startsAtEmptyLine) {
+ if (!mergeDestination.deepEquivalent().deprecatedNode() || !mergeDestination.deepEquivalent().deprecatedNode()->isDescendantOf(m_upstreamStart.deprecatedNode()->enclosingBlockFlowElement()) || m_startsAtEmptyLine) {
insertNodeAt(createBreakElement(document()).get(), m_upstreamStart);
mergeDestination = VisiblePosition(m_upstreamStart);
}
@@ -608,8 +608,8 @@ void DeleteSelectionCommand::mergeParagraphs()
// The rule for merging into an empty block is: only do so if its farther to the right.
// FIXME: Consider RTL.
if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && startOfParagraphToMove.absoluteCaretBounds().x() > mergeDestination.absoluteCaretBounds().x()) {
- if (mergeDestination.deepEquivalent().downstream().node()->hasTagName(brTag)) {
- removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downstream().node());
+ if (mergeDestination.deepEquivalent().downstream().deprecatedNode()->hasTagName(brTag)) {
+ removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downstream().deprecatedNode());
m_endingPosition = startOfParagraphToMove.deepEquivalent();
return;
}
@@ -618,7 +618,7 @@ void DeleteSelectionCommand::mergeParagraphs()
// Block images, tables and horizontal rules cannot be made inline with content at mergeDestination. If there is
// any (!isStartOfParagraph(mergeDestination)), don't merge, just move the caret to just before the selection we deleted.
// See https://bugs.webkit.org/show_bug.cgi?id=25439
- if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalent().node()) && !isStartOfParagraph(mergeDestination)) {
+ if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalent().deprecatedNode()) && !isStartOfParagraph(mergeDestination)) {
m_endingPosition = m_upstreamStart;
return;
}
@@ -666,7 +666,7 @@ void DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows()
if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow)
if (isTableRowEmpty(m_endTableRow.get())) {
// Don't remove m_endTableRow if it's where we're putting the ending selection.
- if (!m_endingPosition.node()->isDescendantOf(m_endTableRow.get())) {
+ if (!m_endingPosition.deprecatedNode()->isDescendantOf(m_endTableRow.get())) {
// FIXME: We probably shouldn't remove m_endTableRow unless it's fully selected, even if it is empty.
// We'll need to start adjusting the selection endpoints during deletion to know whether or not m_endTableRow
// was fully selected here.
@@ -687,7 +687,7 @@ void DeleteSelectionCommand::calculateTypingStyleAfterDelete()
// has completed.
// If we deleted into a blockquote, but are now no longer in a blockquote, use the alternate typing style
- if (m_deleteIntoBlockquoteStyle && !nearestMailBlockquote(m_endingPosition.node()))
+ if (m_deleteIntoBlockquoteStyle && !nearestMailBlockquote(m_endingPosition.deprecatedNode()))
m_typingStyle = m_deleteIntoBlockquoteStyle;
m_deleteIntoBlockquoteStyle = 0;
@@ -742,7 +742,7 @@ void DeleteSelectionCommand::doApply()
// If the deletion is occurring in a text field, and we're not deleting to replace the selection, then let the frame call across the bridge to notify the form delegate.
if (!m_replace) {
- Node* startNode = m_selectionToDelete.start().node();
+ Node* startNode = m_selectionToDelete.start().deprecatedNode();
Node* ancestorNode = startNode ? startNode->shadowAncestorNode() : 0;
if (ancestorNode && ancestorNode->hasTagName(inputTag)
&& static_cast<HTMLInputElement*>(ancestorNode)->isTextField()
@@ -762,7 +762,7 @@ void DeleteSelectionCommand::doApply()
// and ends inside it (we do need placeholders to hold open empty cells, but that's
// handled elsewhere).
if (Node* table = isLastPositionBeforeTable(m_selectionToDelete.visibleStart()))
- if (m_selectionToDelete.end().node()->isDescendantOf(table))
+ if (m_selectionToDelete.end().deprecatedNode()->isDescendantOf(table))
m_needPlaceholder = false;
}
diff --git a/Source/WebCore/editing/EditCommand.cpp b/Source/WebCore/editing/EditCommand.cpp
index 1b4451d..7b0eab4 100644
--- a/Source/WebCore/editing/EditCommand.cpp
+++ b/Source/WebCore/editing/EditCommand.cpp
@@ -99,6 +99,8 @@ void EditCommand::apply()
if (!isTypingCommand())
frame->editor()->appliedEditing(this);
}
+
+ setShouldRetainAutocorrectionIndicator(false);
}
void EditCommand::unapply()
@@ -192,6 +194,14 @@ bool EditCommand::isTypingCommand() const
return false;
}
+bool EditCommand::shouldRetainAutocorrectionIndicator() const
+{
+ return false;
+}
+
+void EditCommand::setShouldRetainAutocorrectionIndicator(bool)
+{
+}
void EditCommand::updateLayout() const
{
diff --git a/Source/WebCore/editing/EditCommand.h b/Source/WebCore/editing/EditCommand.h
index 4826ec0..8ee37fe 100644
--- a/Source/WebCore/editing/EditCommand.h
+++ b/Source/WebCore/editing/EditCommand.h
@@ -56,9 +56,12 @@ public:
virtual bool isTypingCommand() const;
virtual bool preservesTypingStyle() const;
-
+
bool isTopLevelCommand() const { return !m_parent; }
+ virtual bool shouldRetainAutocorrectionIndicator() const;
+ virtual void setShouldRetainAutocorrectionIndicator(bool);
+
protected:
EditCommand(Document*);
diff --git a/Source/WebCore/editing/EditingBoundary.h b/Source/WebCore/editing/EditingBoundary.h
index 1cb0849..f8ac1cb 100644
--- a/Source/WebCore/editing/EditingBoundary.h
+++ b/Source/WebCore/editing/EditingBoundary.h
@@ -30,7 +30,8 @@ namespace WebCore {
enum EditingBoundaryCrossingRule {
CanCrossEditingBoundary,
- CannotCrossEditingBoundary
+ CannotCrossEditingBoundary,
+ CanSkipOverEditingBoundary
};
}
diff --git a/Source/WebCore/editing/EditingStyle.cpp b/Source/WebCore/editing/EditingStyle.cpp
index a3f66be..de71fb7 100644
--- a/Source/WebCore/editing/EditingStyle.cpp
+++ b/Source/WebCore/editing/EditingStyle.cpp
@@ -31,11 +31,16 @@
#include "CSSComputedStyleDeclaration.h"
#include "CSSMutableStyleDeclaration.h"
#include "CSSValueKeywords.h"
+#include "CSSValueList.h"
#include "Frame.h"
+#include "HTMLFontElement.h"
+#include "HTMLNames.h"
#include "Node.h"
#include "Position.h"
#include "RenderStyle.h"
#include "SelectionController.h"
+#include "StyledElement.h"
+#include "htmlediting.h"
namespace WebCore {
@@ -82,6 +87,175 @@ static PassRefPtr<CSSMutableStyleDeclaration> editingStyleFromComputedStyle(Pass
return copyEditingProperties(style.get());
}
+class HTMLElementEquivalent {
+public:
+ static PassOwnPtr<HTMLElementEquivalent> create(CSSPropertyID propertyID, int primitiveValue, const QualifiedName& tagName)
+ {
+ return adoptPtr(new HTMLElementEquivalent(propertyID, primitiveValue, tagName));
+ }
+
+ virtual ~HTMLElementEquivalent() { }
+ virtual bool matches(Element* element) const { return !m_tagName || element->hasTagName(*m_tagName); }
+ virtual bool hasAttribute() const { return false; }
+ bool propertyExistsInStyle(CSSStyleDeclaration* style) const { return style->getPropertyCSSValue(m_propertyID); }
+ virtual bool valueIsPresentInStyle(Element*, CSSStyleDeclaration*) const;
+ virtual void addToStyle(Element*, EditingStyle*) const;
+
+protected:
+ HTMLElementEquivalent(CSSPropertyID);
+ HTMLElementEquivalent(CSSPropertyID, const QualifiedName& tagName);
+ HTMLElementEquivalent(CSSPropertyID, int primitiveValue, const QualifiedName& tagName);
+ const int m_propertyID;
+ const RefPtr<CSSPrimitiveValue> m_primitiveValue;
+ const QualifiedName* m_tagName; // We can store a pointer because HTML tag names are const global.
+};
+
+HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id)
+ : m_propertyID(id)
+ , m_tagName(0)
+{
+}
+
+HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, const QualifiedName& tagName)
+ : m_propertyID(id)
+ , m_tagName(&tagName)
+{
+}
+
+HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, int primitiveValue, const QualifiedName& tagName)
+ : m_propertyID(id)
+ , m_primitiveValue(CSSPrimitiveValue::createIdentifier(primitiveValue))
+ , m_tagName(&tagName)
+{
+ ASSERT(primitiveValue != CSSValueInvalid);
+}
+
+bool HTMLElementEquivalent::valueIsPresentInStyle(Element* element, CSSStyleDeclaration* style) const
+{
+ RefPtr<CSSValue> value = style->getPropertyCSSValue(m_propertyID);
+ return matches(element) && value && value->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(value.get())->getIdent() == m_primitiveValue->getIdent();
+}
+
+void HTMLElementEquivalent::addToStyle(Element*, EditingStyle* style) const
+{
+ style->setProperty(m_propertyID, m_primitiveValue->cssText());
+}
+
+class HTMLTextDecorationEquivalent : public HTMLElementEquivalent {
+public:
+ static PassOwnPtr<HTMLElementEquivalent> create(int primitiveValue, const QualifiedName& tagName)
+ {
+ return adoptPtr(new HTMLTextDecorationEquivalent(primitiveValue, tagName));
+ }
+ virtual bool valueIsPresentInStyle(Element*, CSSStyleDeclaration*) const;
+
+private:
+ HTMLTextDecorationEquivalent(int primitiveValue, const QualifiedName& tagName);
+};
+
+HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent(int primitiveValue, const QualifiedName& tagName)
+ : HTMLElementEquivalent(CSSPropertyTextDecoration, primitiveValue, tagName)
+{
+}
+
+bool HTMLTextDecorationEquivalent::valueIsPresentInStyle(Element* element, CSSStyleDeclaration* style) const
+{
+ RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(m_propertyID);
+ return matches(element) && styleValue && styleValue->isValueList() && static_cast<CSSValueList*>(styleValue.get())->hasValue(m_primitiveValue.get());
+}
+
+class HTMLAttributeEquivalent : public HTMLElementEquivalent {
+public:
+ static PassOwnPtr<HTMLAttributeEquivalent> create(CSSPropertyID propertyID, const QualifiedName& tagName, const QualifiedName& attrName)
+ {
+ return adoptPtr(new HTMLAttributeEquivalent(propertyID, tagName, attrName));
+ }
+ static PassOwnPtr<HTMLAttributeEquivalent> create(CSSPropertyID propertyID, const QualifiedName& attrName)
+ {
+ return adoptPtr(new HTMLAttributeEquivalent(propertyID, attrName));
+ }
+
+ bool matches(Element* elem) const { return HTMLElementEquivalent::matches(elem) && elem->hasAttribute(m_attrName); }
+ virtual bool hasAttribute() const { return true; }
+ virtual bool valueIsPresentInStyle(Element*, CSSStyleDeclaration*) const;
+ virtual void addToStyle(Element*, EditingStyle*) const;
+ virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
+ inline const QualifiedName& attributeName() const { return m_attrName; }
+
+protected:
+ HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& tagName, const QualifiedName& attrName);
+ HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName);
+ const QualifiedName& m_attrName; // We can store a reference because HTML attribute names are const global.
+};
+
+HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, const QualifiedName& tagName, const QualifiedName& attrName)
+ : HTMLElementEquivalent(id, tagName)
+ , m_attrName(attrName)
+{
+}
+
+HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, const QualifiedName& attrName)
+ : HTMLElementEquivalent(id)
+ , m_attrName(attrName)
+{
+}
+
+bool HTMLAttributeEquivalent::valueIsPresentInStyle(Element* element, CSSStyleDeclaration* style) const
+{
+ RefPtr<CSSValue> value = attributeValueAsCSSValue(element);
+ RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(m_propertyID);
+
+ // FIXME: This is very inefficient way of comparing values
+ // but we can't string compare attribute value and CSS property value.
+ return value && styleValue && value->cssText() == styleValue->cssText();
+}
+
+void HTMLAttributeEquivalent::addToStyle(Element* element, EditingStyle* style) const
+{
+ if (RefPtr<CSSValue> value = attributeValueAsCSSValue(element))
+ style->setProperty(m_propertyID, value->cssText());
+}
+
+PassRefPtr<CSSValue> HTMLAttributeEquivalent::attributeValueAsCSSValue(Element* element) const
+{
+ ASSERT(element);
+ if (!element->hasAttribute(m_attrName))
+ return 0;
+
+ RefPtr<CSSMutableStyleDeclaration> dummyStyle;
+ dummyStyle = CSSMutableStyleDeclaration::create();
+ dummyStyle->setProperty(m_propertyID, element->getAttribute(m_attrName));
+ return dummyStyle->getPropertyCSSValue(m_propertyID);
+}
+
+class HTMLFontSizeEquivalent : public HTMLAttributeEquivalent {
+public:
+ static PassOwnPtr<HTMLFontSizeEquivalent> create()
+ {
+ return adoptPtr(new HTMLFontSizeEquivalent());
+ }
+ virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
+
+private:
+ HTMLFontSizeEquivalent();
+};
+
+HTMLFontSizeEquivalent::HTMLFontSizeEquivalent()
+ : HTMLAttributeEquivalent(CSSPropertyFontSize, HTMLNames::fontTag, HTMLNames::sizeAttr)
+{
+}
+
+PassRefPtr<CSSValue> HTMLFontSizeEquivalent::attributeValueAsCSSValue(Element* element) const
+{
+ ASSERT(element);
+ if (!element->hasAttribute(m_attrName))
+ return 0;
+ int size;
+ if (!HTMLFontElement::cssValueFromFontSizeNumber(element->getAttribute(m_attrName), size))
+ return 0;
+ return CSSPrimitiveValue::createIdentifier(size);
+}
+
float EditingStyle::NoFontDelta = 0.0f;
EditingStyle::EditingStyle()
@@ -101,7 +275,7 @@ EditingStyle::EditingStyle(const Position& position)
: m_shouldUseFixedDefaultFontSize(false)
, m_fontSizeDelta(NoFontDelta)
{
- init(position.node(), OnlyInheritableProperties);
+ init(position.deprecatedNode(), OnlyInheritableProperties);
}
EditingStyle::EditingStyle(const CSSStyleDeclaration* style)
@@ -112,6 +286,14 @@ EditingStyle::EditingStyle(const CSSStyleDeclaration* style)
extractFontSizeDelta();
}
+EditingStyle::EditingStyle(int propertyID, const String& value)
+ : m_mutableStyle(0)
+ , m_shouldUseFixedDefaultFontSize(false)
+ , m_fontSizeDelta(NoFontDelta)
+{
+ setProperty(propertyID, value);
+}
+
EditingStyle::~EditingStyle()
{
}
@@ -144,6 +326,15 @@ void EditingStyle::removeTextFillAndStrokeColorsIfNeeded(RenderStyle* renderStyl
ASSERT(!ec);
}
+void EditingStyle::setProperty(int propertyID, const String& value, bool important)
+{
+ if (!m_mutableStyle)
+ m_mutableStyle = CSSMutableStyleDeclaration::create();
+
+ ExceptionCode ec;
+ m_mutableStyle->setProperty(propertyID, value, important, ec);
+}
+
void EditingStyle::replaceFontSizeByKeywordIfPossible(RenderStyle* renderStyle, CSSComputedStyleDeclaration* computedStyle)
{
ASSERT(renderStyle);
@@ -182,6 +373,9 @@ bool EditingStyle::isEmpty() const
bool EditingStyle::textDirection(WritingDirection& writingDirection) const
{
+ if (!m_mutableStyle)
+ return false;
+
RefPtr<CSSValue> unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
if (!unicodeBidi)
return false;
@@ -306,6 +500,181 @@ void EditingStyle::removeNonEditingProperties()
m_mutableStyle = copyEditingProperties(m_mutableStyle.get());
}
+void EditingStyle::collapseTextDecorationProperties()
+{
+ if (!m_mutableStyle)
+ return;
+
+ RefPtr<CSSValue> textDecorationsInEffect = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
+ if (!textDecorationsInEffect)
+ return;
+
+ m_mutableStyle->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText(), m_mutableStyle->getPropertyPriority(CSSPropertyTextDecoration));
+ m_mutableStyle->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
+}
+
+// CSS properties that create a visual difference only when applied to text.
+static const int textOnlyProperties[] = {
+ CSSPropertyTextDecoration,
+ CSSPropertyWebkitTextDecorationsInEffect,
+ CSSPropertyFontStyle,
+ CSSPropertyFontWeight,
+ CSSPropertyColor,
+};
+
+TriState EditingStyle::triStateOfStyle(CSSStyleDeclaration* styleToCompare, ShouldIgnoreTextOnlyProperties shouldIgnoreTextOnlyProperties) const
+{
+ RefPtr<CSSMutableStyleDeclaration> difference = getPropertiesNotIn(m_mutableStyle.get(), styleToCompare);
+
+ if (shouldIgnoreTextOnlyProperties == IgnoreTextOnlyProperties)
+ difference->removePropertiesInSet(textOnlyProperties, WTF_ARRAY_LENGTH(textOnlyProperties));
+
+ if (!difference->length())
+ return TrueTriState;
+ if (difference->length() == m_mutableStyle->length())
+ return FalseTriState;
+
+ return MixedTriState;
+}
+
+bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const
+{
+ ASSERT(element);
+ ASSERT(!conflictingProperties || conflictingProperties->isEmpty());
+
+ CSSMutableStyleDeclaration* inlineStyle = element->inlineStyleDecl();
+ if (!m_mutableStyle || !inlineStyle)
+ return false;
+
+ if (!conflictingProperties) {
+ CSSMutableStyleDeclaration::const_iterator end = m_mutableStyle->end();
+ for (CSSMutableStyleDeclaration::const_iterator it = m_mutableStyle->begin(); it != end; ++it) {
+ CSSPropertyID propertyID = static_cast<CSSPropertyID>(it->id());
+
+ // We don't override whitespace property of a tab span because that would collapse the tab into a space.
+ if (propertyID == CSSPropertyWhiteSpace && isTabSpanNode(element))
+ continue;
+
+ if (inlineStyle->getPropertyCSSValue(propertyID))
+ return true;
+ }
+
+ return false;
+ }
+
+ CSSMutableStyleDeclaration::const_iterator end = m_mutableStyle->end();
+ for (CSSMutableStyleDeclaration::const_iterator it = m_mutableStyle->begin(); it != end; ++it) {
+ CSSPropertyID propertyID = static_cast<CSSPropertyID>(it->id());
+ if ((propertyID == CSSPropertyWhiteSpace && isTabSpanNode(element)) || !inlineStyle->getPropertyCSSValue(propertyID))
+ continue;
+
+ if (propertyID == CSSPropertyUnicodeBidi && inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) {
+ if (extractedStyle)
+ extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->getPropertyPriority(propertyID));
+ conflictingProperties->append(CSSPropertyDirection);
+ }
+
+ conflictingProperties->append(propertyID);
+ if (extractedStyle)
+ extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->getPropertyPriority(propertyID));
+ }
+
+ return !conflictingProperties->isEmpty();
+}
+
+bool EditingStyle::conflictsWithImplicitStyleOfElement(HTMLElement* element, EditingStyle* extractedStyle, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
+{
+ if (!m_mutableStyle)
+ return false;
+
+ static const HTMLElementEquivalent* HTMLEquivalents[] = {
+ HTMLElementEquivalent::create(CSSPropertyFontWeight, CSSValueBold, HTMLNames::bTag).leakPtr(),
+ HTMLElementEquivalent::create(CSSPropertyFontWeight, CSSValueBold, HTMLNames::strongTag).leakPtr(),
+ HTMLElementEquivalent::create(CSSPropertyVerticalAlign, CSSValueSub, HTMLNames::subTag).leakPtr(),
+ HTMLElementEquivalent::create(CSSPropertyVerticalAlign, CSSValueSuper, HTMLNames::supTag).leakPtr(),
+ HTMLElementEquivalent::create(CSSPropertyFontStyle, CSSValueItalic, HTMLNames::iTag).leakPtr(),
+ HTMLElementEquivalent::create(CSSPropertyFontStyle, CSSValueItalic, HTMLNames::emTag).leakPtr(),
+
+ HTMLTextDecorationEquivalent::create(CSSValueUnderline, HTMLNames::uTag).leakPtr(),
+ HTMLTextDecorationEquivalent::create(CSSValueLineThrough, HTMLNames::sTag).leakPtr(),
+ HTMLTextDecorationEquivalent::create(CSSValueLineThrough, HTMLNames::strikeTag).leakPtr(),
+ };
+
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(HTMLEquivalents); ++i) {
+ const HTMLElementEquivalent* equivalent = HTMLEquivalents[i];
+ if (equivalent->matches(element) && equivalent->propertyExistsInStyle(m_mutableStyle.get())
+ && (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent->valueIsPresentInStyle(element, m_mutableStyle.get()))) {
+ if (extractedStyle)
+ equivalent->addToStyle(element, extractedStyle);
+ return true;
+ }
+ }
+ return false;
+}
+
+static const Vector<OwnPtr<HTMLAttributeEquivalent> >& htmlAttributeEquivalents()
+{
+ DEFINE_STATIC_LOCAL(Vector<OwnPtr<HTMLAttributeEquivalent> >, HTMLAttributeEquivalents, ());
+
+ if (!HTMLAttributeEquivalents.size()) {
+ HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create(CSSPropertyColor, HTMLNames::fontTag, HTMLNames::colorAttr));
+ HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create(CSSPropertyFontFamily, HTMLNames::fontTag, HTMLNames::faceAttr));
+ HTMLAttributeEquivalents.append(HTMLFontSizeEquivalent::create());
+
+ HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create(CSSPropertyDirection, HTMLNames::dirAttr));
+ HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create(CSSPropertyUnicodeBidi, HTMLNames::dirAttr));
+ }
+
+ return HTMLAttributeEquivalents;
+}
+
+bool EditingStyle::conflictsWithImplicitStyleOfAttributes(HTMLElement* element) const
+{
+ ASSERT(element);
+ if (!m_mutableStyle)
+ return false;
+
+ const Vector<OwnPtr<HTMLAttributeEquivalent> >& HTMLAttributeEquivalents = htmlAttributeEquivalents();
+ for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
+ if (HTMLAttributeEquivalents[i]->matches(element) && HTMLAttributeEquivalents[i]->propertyExistsInStyle(m_mutableStyle.get())
+ && !HTMLAttributeEquivalents[i]->valueIsPresentInStyle(element, m_mutableStyle.get()))
+ return true;
+ }
+
+ return false;
+}
+
+bool EditingStyle::extractConflictingImplicitStyleOfAttributes(HTMLElement* element, ShouldPreserveWritingDirection shouldPreserveWritingDirection,
+ EditingStyle* extractedStyle, Vector<QualifiedName>& conflictingAttributes, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
+{
+ ASSERT(element);
+ // HTMLAttributeEquivalent::addToStyle doesn't support unicode-bidi and direction properties
+ ASSERT(!extractedStyle || shouldPreserveWritingDirection == PreserveWritingDirection);
+ if (!m_mutableStyle)
+ return false;
+
+ const Vector<OwnPtr<HTMLAttributeEquivalent> >& HTMLAttributeEquivalents = htmlAttributeEquivalents();
+ bool removed = false;
+ for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
+ const HTMLAttributeEquivalent* equivalent = HTMLAttributeEquivalents[i].get();
+
+ // unicode-bidi and direction are pushed down separately so don't push down with other styles.
+ if (shouldPreserveWritingDirection == PreserveWritingDirection && equivalent->attributeName() == HTMLNames::dirAttr)
+ continue;
+
+ if (!equivalent->matches(element) || !equivalent->propertyExistsInStyle(m_mutableStyle.get())
+ || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(element, m_mutableStyle.get())))
+ continue;
+
+ if (extractedStyle)
+ equivalent->addToStyle(element, extractedStyle);
+ conflictingAttributes.append(equivalent->attributeName());
+ removed = true;
+ }
+
+ return removed;
+}
+
void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWritingDirection shouldPreserveWritingDirection)
{
if (!m_mutableStyle)
@@ -343,13 +712,60 @@ void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWrit
}
}
-PassRefPtr<EditingStyle> editingStyleIncludingTypingStyle(const Position& position)
+void EditingStyle::mergeTypingStyle(Document* document)
{
- RefPtr<EditingStyle> editingStyle = EditingStyle::create(position);
- RefPtr<EditingStyle> typingStyle = position.node()->document()->frame()->selection()->typingStyle();
- if (typingStyle && typingStyle->style())
- editingStyle->style()->merge(copyEditingProperties(typingStyle->style()).get());
- return editingStyle;
+ ASSERT(document);
+
+ RefPtr<EditingStyle> typingStyle = document->frame()->selection()->typingStyle();
+ if (!typingStyle || typingStyle == this)
+ return;
+
+ mergeStyle(typingStyle->style());
}
-
+
+void EditingStyle::mergeInlineStyleOfElement(StyledElement* element)
+{
+ ASSERT(element);
+ mergeStyle(element->inlineStyleDecl());
+}
+
+void EditingStyle::mergeStyle(CSSMutableStyleDeclaration* style)
+{
+ if (!style)
+ return;
+
+ if (!m_mutableStyle) {
+ m_mutableStyle = style->copy();
+ return;
+ }
+
+ CSSMutableStyleDeclaration::const_iterator end = style->end();
+ for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
+ RefPtr<CSSValue> value;
+ if ((it->id() == CSSPropertyTextDecoration || it->id() == CSSPropertyWebkitTextDecorationsInEffect) && it->value()->isValueList()) {
+ value = m_mutableStyle->getPropertyCSSValue(it->id());
+ if (value && !value->isValueList())
+ value = 0;
+ }
+
+ if (!value) {
+ ExceptionCode ec;
+ m_mutableStyle->setProperty(it->id(), it->value()->cssText(), it->isImportant(), ec);
+ continue;
+ }
+
+ CSSValueList* newTextDecorations = static_cast<CSSValueList*>(it->value());
+ CSSValueList* textDecorations = static_cast<CSSValueList*>(value.get());
+
+ DEFINE_STATIC_LOCAL(const RefPtr<CSSPrimitiveValue>, underline, (CSSPrimitiveValue::createIdentifier(CSSValueUnderline)));
+ DEFINE_STATIC_LOCAL(const RefPtr<CSSPrimitiveValue>, lineThrough, (CSSPrimitiveValue::createIdentifier(CSSValueLineThrough)));
+
+ if (newTextDecorations->hasValue(underline.get()) && !textDecorations->hasValue(underline.get()))
+ textDecorations->append(underline.get());
+
+ if (newTextDecorations->hasValue(lineThrough.get()) && !textDecorations->hasValue(lineThrough.get()))
+ textDecorations->append(lineThrough.get());
+ }
+}
+
}
diff --git a/Source/WebCore/editing/EditingStyle.h b/Source/WebCore/editing/EditingStyle.h
index 129ade5..aa310ac 100644
--- a/Source/WebCore/editing/EditingStyle.h
+++ b/Source/WebCore/editing/EditingStyle.h
@@ -31,24 +31,34 @@
#ifndef EditingStyle_h
#define EditingStyle_h
+#include "CSSPropertyNames.h"
#include "WritingDirection.h"
+#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
namespace WebCore {
class CSSStyleDeclaration;
class CSSComputedStyleDeclaration;
class CSSMutableStyleDeclaration;
+class Document;
+class HTMLElement;
class Node;
class Position;
+class QualifiedName;
class RenderStyle;
+class StyledElement;
+
+enum TriState { FalseTriState, TrueTriState, MixedTriState };
class EditingStyle : public RefCounted<EditingStyle> {
public:
enum PropertiesToInclude { AllProperties, OnlyInheritableProperties };
enum ShouldPreserveWritingDirection { PreserveWritingDirection, DoNotPreserveWritingDirection };
+ enum ShouldExtractMatchingStyle { ExtractMatchingStyle, DoNotExtractMatchingStyle };
static float NoFontDelta;
static PassRefPtr<EditingStyle> create()
@@ -71,6 +81,11 @@ public:
return adoptRef(new EditingStyle(style));
}
+ static PassRefPtr<EditingStyle> create(int propertyID, const String& value)
+ {
+ return adoptRef(new EditingStyle(propertyID, value));
+ }
+
~EditingStyle();
CSSMutableStyleDeclaration* style() { return m_mutableStyle.get(); }
@@ -86,28 +101,48 @@ public:
void removeStyleAddedByNode(Node*);
void removeStyleConflictingWithStyleOfNode(Node*);
void removeNonEditingProperties();
+ void collapseTextDecorationProperties();
+ enum ShouldIgnoreTextOnlyProperties { IgnoreTextOnlyProperties, DoNotIgnoreTextOnlyProperties };
+ TriState triStateOfStyle(CSSStyleDeclaration*, ShouldIgnoreTextOnlyProperties = DoNotIgnoreTextOnlyProperties) const;
+ bool conflictsWithInlineStyleOfElement(StyledElement* element) const { return conflictsWithInlineStyleOfElement(element, 0, 0); }
+ bool conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>& conflictingProperties) const
+ {
+ return conflictsWithInlineStyleOfElement(element, extractedStyle, &conflictingProperties);
+ }
+ bool conflictsWithImplicitStyleOfElement(HTMLElement*, EditingStyle* extractedStyle = 0, ShouldExtractMatchingStyle = DoNotExtractMatchingStyle) const;
+ bool conflictsWithImplicitStyleOfAttributes(HTMLElement*) const;
+ bool extractConflictingImplicitStyleOfAttributes(HTMLElement*, ShouldPreserveWritingDirection, EditingStyle* extractedStyle,
+ Vector<QualifiedName>& conflictingAttributes, ShouldExtractMatchingStyle) const;
void prepareToApplyAt(const Position&, ShouldPreserveWritingDirection = DoNotPreserveWritingDirection);
+ void mergeTypingStyle(Document*);
+ void mergeInlineStyleOfElement(StyledElement*);
float fontSizeDelta() const { return m_fontSizeDelta; }
bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; }
+ bool shouldUseFixedDefaultFontSize() const { return m_shouldUseFixedDefaultFontSize; }
private:
EditingStyle();
EditingStyle(Node*, PropertiesToInclude);
EditingStyle(const Position&);
EditingStyle(const CSSStyleDeclaration*);
+ EditingStyle(int propertyID, const String& value);
void init(Node*, PropertiesToInclude);
void removeTextFillAndStrokeColorsIfNeeded(RenderStyle*);
+ void setProperty(int propertyID, const String& value, bool important = false);
void replaceFontSizeByKeywordIfPossible(RenderStyle*, CSSComputedStyleDeclaration*);
void extractFontSizeDelta();
+ bool conflictsWithInlineStyleOfElement(StyledElement*, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const;
+ void mergeStyle(CSSMutableStyleDeclaration*);
RefPtr<CSSMutableStyleDeclaration> m_mutableStyle;
bool m_shouldUseFixedDefaultFontSize;
float m_fontSizeDelta;
+
+ friend class HTMLElementEquivalent;
+ friend class HTMLAttributeEquivalent;
};
-PassRefPtr<EditingStyle> editingStyleIncludingTypingStyle(const Position&);
-
} // namespace WebCore
#endif // EditingStyle_h
diff --git a/Source/WebCore/editing/Editor.cpp b/Source/WebCore/editing/Editor.cpp
index 99624b3..8807965 100644
--- a/Source/WebCore/editing/Editor.cpp
+++ b/Source/WebCore/editing/Editor.cpp
@@ -64,6 +64,7 @@
#include "NodeList.h"
#include "Page.h"
#include "Pasteboard.h"
+#include "TextCheckerClient.h"
#include "TextCheckingHelper.h"
#include "RemoveFormatCommand.h"
#include "RenderBlock.h"
@@ -73,6 +74,7 @@
#include "Settings.h"
#include "Sound.h"
#include "SpellChecker.h"
+#include "SpellingCorrectionCommand.h"
#include "Text.h"
#include "TextEvent.h"
#include "TextIterator.h"
@@ -83,11 +85,14 @@
#include "visible_units.h"
#include <wtf/UnusedParam.h>
#include <wtf/unicode/CharacterNames.h>
+#include <wtf/unicode/Unicode.h>
namespace WebCore {
using namespace std;
using namespace HTMLNames;
+using namespace WTF;
+using namespace Unicode;
static inline bool isAmbiguousBoundaryCharacter(UChar character)
{
@@ -97,19 +102,6 @@ static inline bool isAmbiguousBoundaryCharacter(UChar character)
return character == '\'' || character == rightSingleQuotationMark || character == hebrewPunctuationGershayim;
}
-#if SUPPORT_AUTOCORRECTION_PANEL
-static FloatRect boundingBoxForRange(Range* range)
-{
- Vector<FloatQuad> textQuads;
- range->getBorderAndTextQuads(textQuads);
- FloatRect totalBoundingBox;
- size_t size = textQuads.size();
- for (size_t i = 0; i< size; ++i)
- totalBoundingBox.unite(textQuads[i].boundingBox());
- return totalBoundingBox;
-}
-#endif // SUPPORT_AUTOCORRECTION_PANEL
-
static const Vector<DocumentMarker::MarkerType>& markerTypesForAutocorrection()
{
DEFINE_STATIC_LOCAL(Vector<DocumentMarker::MarkerType>, markerTypesForAutoCorrection, ());
@@ -141,7 +133,7 @@ VisibleSelection Editor::selectionForCommand(Event* event)
// If the target is a text control, and the current selection is outside of its shadow tree,
// then use the saved selection for that text control.
Node* target = event->target()->toNode();
- Node* selectionStart = selection.start().node();
+ Node* selectionStart = selection.start().deprecatedNode();
if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
RefPtr<Range> range;
if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
@@ -171,6 +163,14 @@ EditorClient* Editor::client() const
return 0;
}
+
+TextCheckerClient* Editor::textChecker() const
+{
+ if (EditorClient* owner = client())
+ return owner->textChecker();
+ return 0;
+}
+
void Editor::handleKeyboardEvent(KeyboardEvent* event)
{
if (EditorClient* c = client())
@@ -293,10 +293,10 @@ bool Editor::canDeleteRange(Range* range) const
return false;
if (range->collapsed(ec)) {
- VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
+ VisiblePosition start(Position(startContainer, range->startOffset(ec), Position::PositionIsOffsetInAnchor), DOWNSTREAM);
VisiblePosition previous = start.previous();
// FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
- if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
+ if (previous.isNull() || previous.deepEquivalent().deprecatedNode()->rootEditableElement() != startContainer->rootEditableElement())
return false;
}
return true;
@@ -427,8 +427,15 @@ void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment,
{
if (m_frame->selection()->isNone() || !fragment)
return;
-
- applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
+
+ ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::PreventNesting;
+ if (selectReplacement)
+ options |= ReplaceSelectionCommand::SelectReplacement;
+ if (smartReplace)
+ options |= ReplaceSelectionCommand::SmartReplace;
+ if (matchStyle)
+ options |= ReplaceSelectionCommand::MatchStyle;
+ applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, options, EditActionPaste));
revealSelectionAfterEditingOperation();
Node* nodeToCheck = m_frame->selection()->rootEditableElement();
@@ -536,7 +543,7 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
size_t markerCount = markers.size();
for (size_t i = 0; i < markerCount; ++i) {
const DocumentMarker& marker = markers[i];
- if (((marker.type == DocumentMarker::CorrectionIndicator && marker.description.length()) || marker.type == DocumentMarker::Spelling) && static_cast<int>(marker.endOffset) == endOffset) {
+ if (((marker.type == DocumentMarker::Replacement && !marker.description.isNull()) || marker.type == DocumentMarker::Spelling) && static_cast<int>(marker.endOffset) == endOffset) {
RefPtr<Range> wordRange = Range::create(frame()->document(), node, marker.startOffset, node, marker.endOffset);
String currentWord = plainText(wordRange.get());
if (currentWord.length()) {
@@ -558,7 +565,7 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
{
if (AXObjectCache::accessibilityEnabled()) {
- Node* node = endingSelection.start().node();
+ Node* node = endingSelection.start().deprecatedNode();
if (node)
m_frame->document()->axObjectCache()->postNotification(node->renderer(), AXObjectCache::AXValueChanged, false);
}
@@ -596,7 +603,7 @@ const SimpleFontData* Editor::fontForSelection(bool& hasMultipleFonts) const
const SimpleFontData* font = 0;
RefPtr<Range> range = m_frame->selection()->toNormalizedRange();
- Node* startNode = range->editingStartPosition().node();
+ Node* startNode = range->editingStartPosition().deprecatedNode();
if (startNode) {
Node* pastEnd = range->pastLastNode();
// In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
@@ -631,7 +638,7 @@ WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbe
Position position = m_frame->selection()->selection().start().downstream();
- Node* node = position.node();
+ Node* node = position.deprecatedNode();
if (!node)
return NaturalWritingDirection;
@@ -663,7 +670,7 @@ WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbe
hasNestedOrMultipleEmbeddings = false;
return direction;
}
- node = m_frame->selection()->selection().visibleStart().deepEquivalent().node();
+ node = m_frame->selection()->selection().visibleStart().deepEquivalent().deprecatedNode();
}
// The selection is either a caret with no typing attributes or a range in which no embedding is added, so just use the start position
@@ -702,7 +709,7 @@ WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbe
return NaturalWritingDirection;
// In the range case, make sure that the embedding element persists until the end of the range.
- if (m_frame->selection()->isRange() && !end.node()->isDescendantOf(node))
+ if (m_frame->selection()->isRange() && !end.deprecatedNode()->isDescendantOf(node))
return NaturalWritingDirection;
foundDirection = directionValue == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
@@ -718,12 +725,12 @@ bool Editor::hasBidiSelection() const
Node* startNode;
if (m_frame->selection()->isRange()) {
- startNode = m_frame->selection()->selection().start().downstream().node();
- Node* endNode = m_frame->selection()->selection().end().upstream().node();
+ startNode = m_frame->selection()->selection().start().downstream().deprecatedNode();
+ Node* endNode = m_frame->selection()->selection().end().upstream().deprecatedNode();
if (enclosingBlock(startNode) != enclosingBlock(endNode))
return false;
} else
- startNode = m_frame->selection()->selection().visibleStart().deepEquivalent().node();
+ startNode = m_frame->selection()->selection().visibleStart().deepEquivalent().deprecatedNode();
RenderObject* renderer = startNode->renderer();
while (renderer && !renderer->isRenderBlock())
@@ -938,68 +945,42 @@ void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditActi
applyParagraphStyle(style, editingAction);
}
-bool Editor::clientIsEditable() const
+bool Editor::selectionStartHasStyle(int propertyID, const String& value) const
{
- return client() && client()->isEditable();
+ RefPtr<EditingStyle> style = EditingStyle::create(propertyID, value);
+ RefPtr<EditingStyle> selectionStyle = selectionStartStyle();
+ if (!selectionStyle || !selectionStyle->style())
+ return false;
+ return style->triStateOfStyle(selectionStyle->style()) == TrueTriState;
}
-// CSS properties that only has a visual difference when applied to text.
-static const int textOnlyProperties[] = {
- CSSPropertyTextDecoration,
- CSSPropertyWebkitTextDecorationsInEffect,
- CSSPropertyFontStyle,
- CSSPropertyFontWeight,
- CSSPropertyColor,
-};
-
-static TriState triStateOfStyle(CSSStyleDeclaration* desiredStyle, CSSStyleDeclaration* styleToCompare, bool ignoreTextOnlyProperties = false)
+TriState Editor::selectionHasStyle(int propertyID, const String& value) const
{
- RefPtr<CSSMutableStyleDeclaration> diff = getPropertiesNotIn(desiredStyle, styleToCompare);
-
- if (ignoreTextOnlyProperties)
- diff->removePropertiesInSet(textOnlyProperties, WTF_ARRAY_LENGTH(textOnlyProperties));
-
- if (!diff->length())
- return TrueTriState;
- if (diff->length() == desiredStyle->length())
+ RefPtr<EditingStyle> style = EditingStyle::create(propertyID, value);
+ if (!m_frame->selection()->isCaretOrRange())
return FalseTriState;
- return MixedTriState;
-}
-bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
-{
- bool shouldUseFixedFontDefaultSize;
- RefPtr<CSSMutableStyleDeclaration> selectionStyle = selectionComputedStyle(shouldUseFixedFontDefaultSize);
- if (!selectionStyle)
- return false;
- return triStateOfStyle(style, selectionStyle.get()) == TrueTriState;
-}
+ if (m_frame->selection()->isCaret()) {
+ RefPtr<EditingStyle> selectionStyle = selectionStartStyle();
+ if (!selectionStyle || !selectionStyle->style())
+ return FalseTriState;
+ return style->triStateOfStyle(selectionStyle->style());
+ }
-TriState Editor::selectionHasStyle(CSSStyleDeclaration* style) const
-{
TriState state = FalseTriState;
-
- if (!m_frame->selection()->isRange()) {
- bool shouldUseFixedFontDefaultSize;
- RefPtr<CSSMutableStyleDeclaration> selectionStyle = selectionComputedStyle(shouldUseFixedFontDefaultSize);
- if (!selectionStyle)
- return FalseTriState;
- state = triStateOfStyle(style, selectionStyle.get());
- } else {
- for (Node* node = m_frame->selection()->start().node(); node; node = node->traverseNextNode()) {
- RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
- if (nodeStyle) {
- TriState nodeState = triStateOfStyle(style, nodeStyle.get(), !node->isTextNode());
- if (node == m_frame->selection()->start().node())
- state = nodeState;
- else if (state != nodeState && node->isTextNode()) {
- state = MixedTriState;
- break;
- }
- }
- if (node == m_frame->selection()->end().node())
+ for (Node* node = m_frame->selection()->start().deprecatedNode(); node; node = node->traverseNextNode()) {
+ RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
+ if (nodeStyle) {
+ TriState nodeState = style->triStateOfStyle(nodeStyle.get(), node->isTextNode() ? EditingStyle::DoNotIgnoreTextOnlyProperties : EditingStyle::IgnoreTextOnlyProperties);
+ if (node == m_frame->selection()->start().deprecatedNode())
+ state = nodeState;
+ else if (state != nodeState && node->isTextNode()) {
+ state = MixedTriState;
break;
+ }
}
+ if (node == m_frame->selection()->end().deprecatedNode())
+ break;
}
return state;
@@ -1023,33 +1004,30 @@ static bool hasTransparentBackgroundColor(CSSStyleDeclaration* style)
String Editor::selectionStartCSSPropertyValue(int propertyID)
{
- bool shouldUseFixedFontDefaultSize = false;
- RefPtr<CSSMutableStyleDeclaration> selectionStyle = selectionComputedStyle(shouldUseFixedFontDefaultSize);
- if (!selectionStyle)
+ RefPtr<EditingStyle> selectionStyle = selectionStartStyle();
+ if (!selectionStyle || !selectionStyle->style())
return String();
- String value = selectionStyle->getPropertyValue(propertyID);
+ String value = selectionStyle->style()->getPropertyValue(propertyID);
// If background color is transparent, traverse parent nodes until we hit a different value or document root
// Also, if the selection is a range, ignore the background color at the start of selection,
// and find the background color of the common ancestor.
- if (propertyID == CSSPropertyBackgroundColor && (m_frame->selection()->isRange() || hasTransparentBackgroundColor(selectionStyle.get()))) {
+ if (propertyID == CSSPropertyBackgroundColor && (m_frame->selection()->isRange() || hasTransparentBackgroundColor(selectionStyle->style()))) {
RefPtr<Range> range(m_frame->selection()->toNormalizedRange());
ExceptionCode ec = 0;
for (Node* ancestor = range->commonAncestorContainer(ec); ancestor; ancestor = ancestor->parentNode()) {
- selectionStyle = computedStyle(ancestor)->copy();
- if (!hasTransparentBackgroundColor(selectionStyle.get())) {
- value = selectionStyle->getPropertyValue(CSSPropertyBackgroundColor);
- break;
- }
+ RefPtr<CSSComputedStyleDeclaration> ancestorStyle = computedStyle(ancestor);
+ if (!hasTransparentBackgroundColor(ancestorStyle.get()))
+ return ancestorStyle->getPropertyValue(CSSPropertyBackgroundColor);
}
}
if (propertyID == CSSPropertyFontSize) {
- RefPtr<CSSValue> cssValue = selectionStyle->getPropertyCSSValue(CSSPropertyFontSize);
+ RefPtr<CSSValue> cssValue = selectionStyle->style()->getPropertyCSSValue(CSSPropertyFontSize);
if (cssValue->isPrimitiveValue()) {
value = String::number(legacyFontSizeFromCSSValue(m_frame->document(), static_cast<CSSPrimitiveValue*>(cssValue.get()),
- shouldUseFixedFontDefaultSize, AlwaysUseLegacyFontSize));
+ selectionStyle->shouldUseFixedDefaultFontSize(), AlwaysUseLegacyFontSize));
}
}
@@ -1079,17 +1057,13 @@ static void dispatchEditableContentChangedEvents(const EditCommand& command)
void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
{
- // We may start reversion panel timer in respondToChangedSelection().
- // So we stop the timer for current panel before calling changeSelectionAfterCommand() later in this method.
- stopCorrectionPanelTimer();
m_frame->document()->updateLayout();
dispatchEditableContentChangedEvents(*cmd);
VisibleSelection newSelection(cmd->endingSelection());
#if SUPPORT_AUTOCORRECTION_PANEL
- // Check to see if the command introduced paragraph separator. If it did, we remove existing autocorrection underlines. This is in consistency with the behavior in AppKit.
- if (cmd->isTopLevelCommand() && !inSameParagraph(cmd->startingSelection().start(), newSelection.end()))
+ if (cmd->isTopLevelCommand() && !cmd->shouldRetainAutocorrectionIndicator())
m_frame->document()->markers()->removeMarkers(DocumentMarker::CorrectionIndicator);
#endif
@@ -1124,7 +1098,7 @@ void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
m_lastEditCommand = 0;
if (client())
client()->registerCommandForRedo(cmd);
- respondToChangedContents(newSelection);
+ respondToChangedContents(newSelection);
}
void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
@@ -1139,7 +1113,7 @@ void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
m_lastEditCommand = 0;
if (client())
client()->registerCommandForUndo(cmd);
- respondToChangedContents(newSelection);
+ respondToChangedContents(newSelection);
}
Editor::Editor(Frame* frame)
@@ -1150,7 +1124,7 @@ Editor::Editor(Frame* frame)
// This is off by default, since most editors want this behavior (this matches IE but not FF).
, m_shouldStyleWithCSS(false)
, m_killRing(adoptPtr(new KillRing))
- , m_spellChecker(new SpellChecker(frame, frame->page() ? frame->page()->editorClient() : 0))
+ , m_spellChecker(new SpellChecker(frame, frame->page() ? frame->page()->editorClient()->textChecker() : 0))
, m_correctionPanelTimer(this, &Editor::correctionPanelTimerFired)
, m_areMarkedTextMatchesHighlighted(false)
{
@@ -1193,22 +1167,37 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
return true;
+#if REMOVE_MARKERS_UPON_EDITING
+ if (!text.isEmpty())
+ removeSpellAndCorrectionMarkersFromWordsToBeEdited(isSpaceOrNewline(text[0]));
+#endif
+
+ bool shouldConsiderApplyingAutocorrection = false;
if (text == " " || text == "\t")
- applyAutocorrectionBeforeTypingIfAppropriate();
+ shouldConsiderApplyingAutocorrection = true;
+
+ if (text.length() == 1 && isPunct(text[0]) && !isAmbiguousBoundaryCharacter(text[0]))
+ shouldConsiderApplyingAutocorrection = true;
+
+ bool autocorrectionWasApplied = shouldConsiderApplyingAutocorrection && applyAutocorrectionBeforeTypingIfAppropriate();
// Get the selection to use for the event that triggered this insertText.
// If the event handler changed the selection, we may want to use a different selection
// that is contained in the event target.
selection = selectionForCommand(triggeringEvent);
if (selection.isContentEditable()) {
- if (Node* selectionStart = selection.start().node()) {
+ if (Node* selectionStart = selection.start().deprecatedNode()) {
RefPtr<Document> document = selectionStart->document();
-
- // Insert the text
- TypingCommand::insertText(document.get(), text, selection, selectInsertedText,
- triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm : TypingCommand::TextCompositionNone);
- // Reveal the current selection
+ // Insert the text
+ TypingCommand::TypingCommandOptions options = 0;
+ if (selectInsertedText)
+ options |= TypingCommand::SelectInsertedText;
+ if (autocorrectionWasApplied)
+ options |= TypingCommand::RetainAutocorrectionIndicator;
+ TypingCommand::insertText(document.get(), text, selection, options, triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm : TypingCommand::TextCompositionNone);
+
+ // Reveal the current selection
if (Frame* editedFrame = document->frame())
if (Page* page = editedFrame->page())
page->focusController()->focusedOrMainFrame()->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
@@ -1226,10 +1215,10 @@ bool Editor::insertLineBreak()
if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
return true;
- applyAutocorrectionBeforeTypingIfAppropriate();
-
- TypingCommand::insertLineBreak(m_frame->document());
+ bool autocorrectionIsApplied = applyAutocorrectionBeforeTypingIfAppropriate();
+ TypingCommand::insertLineBreak(m_frame->document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0);
revealSelectionAfterEditingOperation();
+
return true;
}
@@ -1244,10 +1233,10 @@ bool Editor::insertParagraphSeparator()
if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
return true;
- applyAutocorrectionBeforeTypingIfAppropriate();
-
- TypingCommand::insertParagraphSeparator(m_frame->document());
+ bool autocorrectionIsApplied = applyAutocorrectionBeforeTypingIfAppropriate();
+ TypingCommand::insertParagraphSeparator(m_frame->document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0);
revealSelectionAfterEditingOperation();
+
return true;
}
@@ -1264,7 +1253,7 @@ void Editor::cut()
#if REMOVE_MARKERS_UPON_EDITING
removeSpellAndCorrectionMarkersFromWordsToBeEdited(true);
#endif
- if (isNodeInTextFormControl(m_frame->selection()->start().node()))
+ if (isNodeInTextFormControl(m_frame->selection()->start().deprecatedNode()))
Pasteboard::generalPasteboard()->writePlainText(selectedText());
else
Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
@@ -1282,7 +1271,7 @@ void Editor::copy()
return;
}
- if (isNodeInTextFormControl(m_frame->selection()->start().node()))
+ if (isNodeInTextFormControl(m_frame->selection()->start().deprecatedNode()))
Pasteboard::generalPasteboard()->writePlainText(selectedText());
else {
Document* document = m_frame->document();
@@ -1578,7 +1567,7 @@ void Editor::selectComposition()
// See <http://bugs.webkit.org/show_bug.cgi?id=15781>
VisibleSelection selection;
selection.setWithoutValidation(range->startPosition(), range->endPosition());
- m_frame->selection()->setSelection(selection, false, false);
+ m_frame->selection()->setSelection(selection, 0);
}
void Editor::confirmComposition()
@@ -1636,7 +1625,7 @@ void Editor::confirmComposition(const String& text, bool preserveSelection)
insertTextForConfirmedComposition(text);
if (preserveSelection) {
- m_frame->selection()->setSelection(oldSelection, false, false);
+ m_frame->selection()->setSelection(oldSelection, 0);
// An open typing command that disagrees about current selection would cause issues with typing later on.
TypingCommand::closeTyping(m_lastEditCommand.get());
}
@@ -1707,9 +1696,9 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
// Find out what node has the composition now.
Position base = m_frame->selection()->base().downstream();
Position extent = m_frame->selection()->extent();
- Node* baseNode = base.node();
+ Node* baseNode = base.deprecatedNode();
unsigned baseOffset = base.deprecatedEditingOffset();
- Node* extentNode = extent.node();
+ Node* extentNode = extent.deprecatedNode();
unsigned extentOffset = extent.deprecatedEditingOffset();
if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
@@ -1746,7 +1735,7 @@ void Editor::ignoreSpelling()
String text = selectedText();
ASSERT(text.length());
- client()->ignoreWordInSpellDocument(text);
+ textChecker()->ignoreWordInSpellDocument(text);
}
void Editor::learnSpelling()
@@ -1754,12 +1743,15 @@ void Editor::learnSpelling()
if (!client())
return;
- // FIXME: We don't call this on the Mac, and it should remove misspelling markers around the
- // learned word, see <rdar://problem/5396072>.
+ // FIXME: On Mac OS X, when use "learn" button on "Spelling and Grammar" panel, we don't call this function. It should remove misspelling markers around the learned word, see <rdar://problem/5396072>.
+
+ RefPtr<Range> selectedRange = frame()->selection()->toNormalizedRange();
+ if (selectedRange)
+ frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
String text = selectedText();
ASSERT(text.length());
- client()->learnWord(text);
+ textChecker()->learnWord(text);
}
void Editor::advanceToNextMisspelling(bool startBeforeSelection)
@@ -1775,7 +1767,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
bool startedWithSelection = false;
- if (selection.start().node()) {
+ if (selection.start().deprecatedNode()) {
startedWithSelection = true;
if (startBeforeSelection) {
VisiblePosition start(selection.visibleStart());
@@ -1799,7 +1791,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
return;
Position rangeCompliantPosition = position.parentAnchoredEquivalent();
- spellingSearchRange->setStart(rangeCompliantPosition.node(), rangeCompliantPosition.deprecatedEditingOffset(), ec);
+ spellingSearchRange->setStart(rangeCompliantPosition.deprecatedNode(), rangeCompliantPosition.deprecatedEditingOffset(), ec);
startedWithSelection = false; // won't need to wrap
}
@@ -1949,7 +1941,7 @@ bool Editor::isSelectionMisspelled()
int misspellingLocation = -1;
int misspellingLength = 0;
- client()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
+ textChecker()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
// The selection only counts as misspelled if the selected text is exactly one misspelled word
if (misspellingLength != length)
@@ -1993,7 +1985,7 @@ Vector<String> Editor::guessesForMisspelledSelection()
Vector<String> guesses;
if (client())
- client()->getGuessesForWord(selectedString, String(), guesses);
+ textChecker()->getGuessesForWord(selectedString, String(), guesses);
return guesses;
}
@@ -2110,6 +2102,7 @@ void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart,
} else {
markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), adjacentWords.toNormalizedRange().get());
}
+
#else
UNUSED_PARAM(selectionAfterTyping);
if (!isContinuousSpellCheckingEnabled())
@@ -2125,7 +2118,7 @@ void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart,
// Get the misspelled word.
const String misspelledWord = plainText(misspellingRange.get());
- String autocorrectedString = client()->getAutoCorrectSuggestionForMisspelledWord(misspelledWord);
+ String autocorrectedString = textChecker()->getAutoCorrectSuggestionForMisspelledWord(misspelledWord);
// If autocorrected word is non empty, replace the misspelled word by this word.
if (!autocorrectedString.isEmpty()) {
@@ -2204,7 +2197,7 @@ bool Editor::isSpellCheckingEnabledFor(Node* node) const
bool Editor::isSpellCheckingEnabledInFocusedNode() const
{
- return isSpellCheckingEnabledFor(m_frame->selection()->start().node());
+ return isSpellCheckingEnabledFor(m_frame->selection()->start().deprecatedNode());
}
void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange)
@@ -2260,7 +2253,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (shouldMarkGrammar ? (spellingParagraph.isRangeEmpty() && grammarParagraph.isEmpty()) : spellingParagraph.isEmpty())
return;
- if (shouldPerformReplacement) {
+ if (shouldPerformReplacement || shouldMarkSpelling) {
if (m_frame->selection()->selectionType() == VisibleSelection::CaretSelection) {
// Attempt to save the caret position so we can restore it later if needed
Position caretPosition = m_frame->selection()->end();
@@ -2296,7 +2289,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
checkingTypes |= TextCheckingTypeCorrection;
}
- client()->checkTextOfParagraph(paragraph.textCharacters(), paragraph.textLength(), checkingTypes, results);
+ textChecker()->checkTextOfParagraph(paragraph.textCharacters(), paragraph.textLength(), checkingTypes, results);
#if SUPPORT_AUTOCORRECTION_PANEL
// If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.
@@ -2345,7 +2338,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
// In this case the result range just has to touch the spelling range, so we can handle replacing non-word text such as punctuation.
ASSERT(resultLength > 0 && resultLocation >= 0);
- if (shouldShowCorrectionPanel && resultLocation + resultLength < spellingRangeEndOffset)
+ if (shouldShowCorrectionPanel && (resultLocation + resultLength < spellingRangeEndOffset || result->type != TextCheckingTypeCorrection))
continue;
int replacementLength = result->replacement.length();
@@ -2360,10 +2353,10 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
// adding links should be done only immediately after they are typed
if (result->type == TextCheckingTypeLink && selectionOffset > resultLocation + resultLength + 1)
- doReplacement = false;
+ continue;
// Don't correct spelling in an already-corrected word.
- if (doReplacement && result->type == TextCheckingTypeCorrection) {
+ if (result->type == TextCheckingTypeCorrection) {
Node* node = rangeToReplace->startContainer();
int startOffset = rangeToReplace->startOffset();
int endOffset = startOffset + replacementLength;
@@ -2379,58 +2372,71 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
break;
}
}
- if (doReplacement && !shouldShowCorrectionPanel && selectionToReplace != m_frame->selection()->selection()) {
- if (m_frame->selection()->shouldChangeSelection(selectionToReplace)) {
- m_frame->selection()->setSelection(selectionToReplace);
- selectionChanged = true;
- } else {
- doReplacement = false;
+
+ if (!doReplacement)
+ continue;
+
+#if SUPPORT_AUTOCORRECTION_PANEL
+ if (shouldShowCorrectionPanel) {
+ if (resultLocation + resultLength == spellingRangeEndOffset) {
+ // We only show the correction panel on the last word.
+ FloatRect boundingBox = windowRectForRange(rangeToReplace.get());
+ if (boundingBox.isEmpty())
+ break;
+ m_correctionPanelInfo.rangeToBeReplaced = rangeToReplace;
+ m_correctionPanelInfo.replacedString = plainText(rangeToReplace.get());
+ m_correctionPanelInfo.replacementString = result->replacement;
+ m_correctionPanelInfo.isActive = true;
+ client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, result->replacement, Vector<String>(), this);
+ break;
}
+ // If this function is called for showing correction panel, we ignore other correction or replacement.
+ continue;
}
+#endif
- String replacedString;
- if (doReplacement) {
- if (result->type == TextCheckingTypeLink) {
- restoreSelectionAfterChange = false;
- if (canEditRichly())
- applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement));
- } else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
- if (result->type == TextCheckingTypeCorrection)
- replacedString = plainText(rangeToReplace.get());
-#if SUPPORT_AUTOCORRECTION_PANEL
- if (shouldShowCorrectionPanel && resultLocation + resultLength == spellingRangeEndOffset && result->type == TextCheckingTypeCorrection) {
- // We only show the correction panel on the last word.
- Vector<FloatQuad> textQuads;
- rangeToReplace->getBorderAndTextQuads(textQuads);
- Vector<FloatQuad>::const_iterator end = textQuads.end();
- FloatRect totalBoundingBox;
- for (Vector<FloatQuad>::const_iterator it = textQuads.begin(); it < end; ++it)
- totalBoundingBox.unite(it->boundingBox());
- m_correctionPanelInfo.rangeToBeReplaced = rangeToReplace;
- m_correctionPanelInfo.replacedString = replacedString;
- m_correctionPanelInfo.replacementString = result->replacement;
- m_correctionPanelInfo.isActive = true;
- client()->showCorrectionPanel(m_correctionPanelInfo.panelType, totalBoundingBox, m_correctionPanelInfo.replacedString, result->replacement, Vector<String>(), this);
- doReplacement = false;
- }
+ if (selectionToReplace != m_frame->selection()->selection()) {
+ if (!m_frame->selection()->shouldChangeSelection(selectionToReplace))
+ continue;
+ }
+
+ if (result->type == TextCheckingTypeLink) {
+ m_frame->selection()->setSelection(selectionToReplace);
+ selectionChanged = true;
+ restoreSelectionAfterChange = false;
+ if (canEditRichly())
+ applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement));
+ } else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
+ String replacedString;
+ if (result->type == TextCheckingTypeCorrection)
+ replacedString = plainText(rangeToReplace.get());
+
+ bool useSpellingCorrectionCommand = false;
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ if (result->type == TextCheckingTypeCorrection)
+ useSpellingCorrectionCommand = true;
#endif
- if (doReplacement) {
- replaceSelectionWithText(result->replacement, false, false);
- offsetDueToReplacement += replacementLength - resultLength;
- if (resultLocation < selectionOffset) {
- selectionOffset += replacementLength - resultLength;
- if (ambiguousBoundaryOffset >= 0)
- ambiguousBoundaryOffset = selectionOffset - 1;
- }
-
- if (result->type == TextCheckingTypeCorrection) {
- // Add a marker so that corrections can easily be undone and won't be re-corrected.
- RefPtr<Range> replacedRange = paragraph.subrange(resultLocation, replacementLength);
- replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
- replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator, replacedString);
- replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::SpellCheckingExemption);
- }
- }
+ if (useSpellingCorrectionCommand)
+ applyCommand(SpellingCorrectionCommand::create(rangeToReplace, result->replacement));
+ else {
+ m_frame->selection()->setSelection(selectionToReplace);
+ replaceSelectionWithText(result->replacement, false, false);
+ }
+
+ selectionChanged = true;
+ offsetDueToReplacement += replacementLength - resultLength;
+ if (resultLocation < selectionOffset) {
+ selectionOffset += replacementLength - resultLength;
+ if (ambiguousBoundaryOffset >= 0)
+ ambiguousBoundaryOffset = selectionOffset - 1;
+ }
+
+ if (result->type == TextCheckingTypeCorrection) {
+ // Add a marker so that corrections can easily be undone and won't be re-corrected.
+ RefPtr<Range> replacedRange = paragraph.subrange(resultLocation, replacementLength);
+ replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
+ replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator);
+ replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::SpellCheckingExemption);
}
}
}
@@ -2461,10 +2467,17 @@ void Editor::changeBackToReplacedString(const String& replacedString)
if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted))
return;
+#if SUPPORT_AUTOCORRECTION_PANEL
+ String replacement = plainText(selection.get());
+ client()->recordAutocorrectionResponse(EditorClient::AutocorrectionReverted, replacedString, replacement);
+#endif
TextCheckingParagraph paragraph(selection);
replaceSelectionWithText(replacedString, false, false);
RefPtr<Range> changedRange = paragraph.subrange(paragraph.checkingStart(), replacedString.length());
changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::Replacement, String());
+#if SUPPORT_AUTOCORRECTION_PANEL
+ changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::SpellCheckingExemption);
+#endif
}
#endif
@@ -2502,7 +2515,9 @@ void Editor::correctionPanelTimerFired(Timer<Editor>*)
case CorrectionPanelInfo::PanelTypeReversion: {
m_correctionPanelInfo.isActive = true;
m_correctionPanelInfo.replacedString = plainText(m_correctionPanelInfo.rangeToBeReplaced.get());
- client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBoxForRange(m_correctionPanelInfo.rangeToBeReplaced.get()), m_correctionPanelInfo.replacedString, m_correctionPanelInfo.replacementString, Vector<String>(), this);
+ FloatRect boundingBox = windowRectForRange(m_correctionPanelInfo.rangeToBeReplaced.get());
+ if (!boundingBox.isEmpty())
+ client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, m_correctionPanelInfo.replacementString, Vector<String>(), this);
}
break;
case CorrectionPanelInfo::PanelTypeSpellingSuggestions: {
@@ -2510,7 +2525,7 @@ void Editor::correctionPanelTimerFired(Timer<Editor>*)
break;
String paragraphText = plainText(TextCheckingParagraph(m_correctionPanelInfo.rangeToBeReplaced).paragraphRange().get());
Vector<String> suggestions;
- client()->getGuessesForWord(m_correctionPanelInfo.replacedString, paragraphText, suggestions);
+ textChecker()->getGuessesForWord(m_correctionPanelInfo.replacedString, paragraphText, suggestions);
if (suggestions.isEmpty()) {
m_correctionPanelInfo.rangeToBeReplaced.clear();
break;
@@ -2518,7 +2533,9 @@ void Editor::correctionPanelTimerFired(Timer<Editor>*)
String topSuggestion = suggestions.first();
suggestions.remove(0);
m_correctionPanelInfo.isActive = true;
- client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBoxForRange(m_correctionPanelInfo.rangeToBeReplaced.get()), m_correctionPanelInfo.replacedString, topSuggestion, suggestions, this);
+ FloatRect boundingBox = windowRectForRange(m_correctionPanelInfo.rangeToBeReplaced.get());
+ if (!boundingBox.isEmpty())
+ client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, topSuggestion, suggestions, this);
}
break;
}
@@ -2640,20 +2657,22 @@ void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemove
VisiblePosition startOfLastWord = startOfWord(endOfSelection, RightWordIfOnBoundary);
VisiblePosition endOfLastWord = endOfWord(endOfSelection, RightWordIfOnBoundary);
- // This can be the case if the end of selection is at the end of document.
- if (endOfLastWord.deepEquivalent().anchorType() != Position::PositionIsOffsetInAnchor) {
- startOfLastWord = startOfWord(frame()->selection()->selection().start(), LeftWordIfOnBoundary);
- endOfLastWord = endOfWord(frame()->selection()->selection().start(), LeftWordIfOnBoundary);
+ if (startOfFirstWord.isNull()) {
+ startOfFirstWord = startOfWord(startOfSelection, RightWordIfOnBoundary);
+ endOfFirstWord = endOfWord(startOfSelection, RightWordIfOnBoundary);
+ }
+
+ if (endOfLastWord.isNull()) {
+ startOfLastWord = startOfWord(endOfSelection, LeftWordIfOnBoundary);
+ endOfLastWord = endOfWord(endOfSelection, LeftWordIfOnBoundary);
}
// If doNotRemoveIfSelectionAtWordBoundary is true, and first word ends at the start of selection,
// we choose next word as the first word.
if (doNotRemoveIfSelectionAtWordBoundary && endOfFirstWord == startOfSelection) {
startOfFirstWord = nextWordPosition(startOfFirstWord);
- if (startOfFirstWord == endOfSelection)
- return;
endOfFirstWord = endOfWord(startOfFirstWord, RightWordIfOnBoundary);
- if (endOfFirstWord.deepEquivalent().anchorType() != Position::PositionIsOffsetInAnchor)
+ if (startOfFirstWord == endOfSelection)
return;
}
@@ -2662,10 +2681,13 @@ void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemove
if (doNotRemoveIfSelectionAtWordBoundary && startOfLastWord == endOfSelection) {
startOfLastWord = previousWordPosition(startOfLastWord);
endOfLastWord = endOfWord(startOfLastWord, RightWordIfOnBoundary);
- if (endOfLastWord == startOfFirstWord)
+ if (endOfLastWord == startOfSelection)
return;
}
+ if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || startOfLastWord.isNull() || endOfLastWord.isNull())
+ return;
+
// Now we remove markers on everything between startOfFirstWord and endOfLastWord.
// However, if an autocorrection change a single word to multiple words, we want to remove correction mark from all the
// resulted words even we only edit one of them. For example, assuming autocorrection changes "avantgarde" to "avant
@@ -2676,10 +2698,12 @@ void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemove
RefPtr<Range> wordRange = Range::create(document, startOfFirstWord.deepEquivalent(), endOfLastWord.deepEquivalent());
document->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator | DocumentMarker::SpellCheckingExemption, DocumentMarkerController::RemovePartiallyOverlappingMarker);
+ document->markers()->clearDescriptionOnMarkersIntersectingRange(wordRange.get(), DocumentMarker::Replacement);
}
void Editor::applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd)
{
+#if SUPPORT_AUTOCORRECTION_PANEL
if (!m_correctionPanelInfo.rangeToBeReplaced)
return;
@@ -2711,36 +2735,66 @@ void Editor::applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>&
// Clone the range, since the caller of this method may want to keep the original range around.
RefPtr<Range> rangeToBeReplaced = m_correctionPanelInfo.rangeToBeReplaced->cloneRange(ec);
- VisibleSelection selectionToReplace(rangeToBeReplaced.get(), DOWNSTREAM);
- if (m_frame->selection()->shouldChangeSelection(selectionToReplace)) {
- m_frame->selection()->setSelection(selectionToReplace);
- replaceSelectionWithText(m_correctionPanelInfo.replacementString, false, false);
- setEnd(paragraphRangeContainingCorrection.get(), m_frame->selection()->selection().start());
- RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, m_correctionPanelInfo.replacementString.length());
- DocumentMarkerController* markers = replacementRange->startContainer()->document()->markers();
- size_t size = markerTypesToAdd.size();
- for (size_t i = 0; i < size; ++i) {
- if (m_correctionPanelInfo.panelType == CorrectionPanelInfo::PanelTypeReversion)
- markers->addMarker(replacementRange.get(), markerTypesToAdd[i]);
- else
- markers->addMarker(replacementRange.get(), markerTypesToAdd[i], m_correctionPanelInfo.replacedString);
- }
+ applyCommand(SpellingCorrectionCommand::create(rangeToBeReplaced, m_correctionPanelInfo.replacementString));
+ setEnd(paragraphRangeContainingCorrection.get(), m_frame->selection()->selection().start());
+ RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, m_correctionPanelInfo.replacementString.length());
+ String newText = plainText(replacementRange.get());
+
+ // Check to see if replacement succeeded.
+ if (newText != m_correctionPanelInfo.replacementString)
+ return;
+
+ DocumentMarkerController* markers = replacementRange->startContainer()->document()->markers();
+ size_t size = markerTypesToAdd.size();
+ for (size_t i = 0; i < size; ++i) {
+ if (m_correctionPanelInfo.panelType == CorrectionPanelInfo::PanelTypeReversion)
+ markers->addMarker(replacementRange.get(), markerTypesToAdd[i]);
+ else
+ markers->addMarker(replacementRange.get(), markerTypesToAdd[i], m_correctionPanelInfo.replacedString);
}
+#else // SUPPORT_AUTOCORRECTION_PANEL
+ UNUSED_PARAM(markerTypesToAdd);
+#endif // SUPPORT_AUTOCORRECTION_PANEL
}
-void Editor::applyAutocorrectionBeforeTypingIfAppropriate()
+bool Editor::applyAutocorrectionBeforeTypingIfAppropriate()
{
if (!m_correctionPanelInfo.rangeToBeReplaced || !m_correctionPanelInfo.isActive)
- return;
+ return false;
if (m_correctionPanelInfo.panelType != CorrectionPanelInfo::PanelTypeCorrection)
- return;
+ return false;
Position caretPosition = m_frame->selection()->selection().start();
+ if (m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition) {
+ dismissCorrectionPanel(ReasonForDismissingCorrectionPanelAccepted);
+ return true;
+ }
+
// Pending correction should always be where caret is. But in case this is not always true, we still want to dismiss the panel without accepting the correction.
ASSERT(m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition);
- dismissCorrectionPanel(m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition ? ReasonForDismissingCorrectionPanelAccepted : ReasonForDismissingCorrectionPanelIgnored);
+ dismissCorrectionPanel(ReasonForDismissingCorrectionPanelIgnored);
+ return false;
+}
+
+void Editor::unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction)
+{
+#if SUPPORT_AUTOCORRECTION_PANEL
+ client()->recordAutocorrectionResponse(EditorClient::AutocorrectionReverted, corrected, correction);
+ m_frame->document()->updateLayout();
+ m_frame->selection()->setSelection(selectionOfCorrected, SelectionController::CloseTyping | SelectionController::ClearTypingStyle | SelectionController::SpellCorrectionTriggered);
+ RefPtr<Range> range = Range::create(m_frame->document(), m_frame->selection()->selection().start(), m_frame->selection()->selection().end());
+
+ DocumentMarkerController* markers = m_frame->document()->markers();
+ markers->removeMarkers(range.get(), DocumentMarker::Spelling);
+ markers->addMarker(range.get(), DocumentMarker::Replacement);
+ markers->addMarker(range.get(), DocumentMarker::SpellCheckingExemption);
+#else // SUPPORT_AUTOCORRECTION_PANEL
+ UNUSED_PARAM(selectionOfCorrected);
+ UNUSED_PARAM(corrected);
+ UNUSED_PARAM(correction);
+#endif // SUPPORT_AUTOCORRECTION_PANEL
}
PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
@@ -2794,10 +2848,10 @@ bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selecti
if (!m_compositionNode)
return false;
Position start = m_frame->selection()->start();
- if (start.node() != m_compositionNode)
+ if (start.deprecatedNode() != m_compositionNode)
return false;
Position end = m_frame->selection()->end();
- if (end.node() != m_compositionNode)
+ if (end.deprecatedNode() != m_compositionNode)
return false;
if (static_cast<unsigned>(start.deprecatedEditingOffset()) < m_compositionStart)
@@ -3014,8 +3068,14 @@ void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, b
// The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
// See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()->selection();
- if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection))
- m_frame->selection()->setSelection(newSelection, closeTyping, clearTypingStyle);
+ if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection)) {
+ SelectionController::SetSelectionOptions options = 0;
+ if (closeTyping)
+ options |= SelectionController::CloseTyping;
+ if (clearTypingStyle)
+ options |= SelectionController::ClearTypingStyle;
+ m_frame->selection()->setSelection(newSelection, options);
+ }
// Some editing operations change the selection visually without affecting its position within the DOM.
// For example when you press return in the following (the caret is marked by ^):
@@ -3047,7 +3107,7 @@ IntRect Editor::firstRectForRange(Range* range) const
return IntRect();
startPosition.getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset);
- RenderObject* startRenderer = startPosition.node()->renderer();
+ RenderObject* startRenderer = startPosition.deprecatedNode()->renderer();
ASSERT(startRenderer);
IntRect startCaretRect = startRenderer->localCaretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine);
if (startCaretRect != IntRect())
@@ -3060,7 +3120,7 @@ IntRect Editor::firstRectForRange(Range* range) const
return IntRect();
endPosition.getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset);
- RenderObject* endRenderer = endPosition.node()->renderer();
+ RenderObject* endRenderer = endPosition.deprecatedNode()->renderer();
ASSERT(endRenderer);
IntRect endCaretRect = endRenderer->localCaretRect(endInlineBox, endCaretOffset);
if (endCaretRect != IntRect())
@@ -3112,7 +3172,7 @@ void Editor::computeAndSetTypingStyle(CSSStyleDeclaration* style, EditAction edi
m_frame->selection()->setTypingStyle(typingStyle);
}
-PassRefPtr<CSSMutableStyleDeclaration> Editor::selectionComputedStyle(bool& shouldUseFixedFontDefaultSize) const
+PassRefPtr<EditingStyle> Editor::selectionStartStyle() const
{
if (m_frame->selection()->isNone())
return 0;
@@ -3132,19 +3192,9 @@ PassRefPtr<CSSMutableStyleDeclaration> Editor::selectionComputedStyle(bool& shou
if (!element)
return 0;
- RefPtr<Element> styleElement = element;
- RefPtr<CSSComputedStyleDeclaration> style = computedStyle(styleElement.release());
- RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->copy();
- shouldUseFixedFontDefaultSize = style->useFixedFontDefaultSize();
-
- if (!m_frame->selection()->typingStyle())
- return mutableStyle;
-
- RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle()->copy();
- typingStyle->prepareToApplyAt(position);
- mutableStyle->merge(typingStyle->style());
-
- return mutableStyle;
+ RefPtr<EditingStyle> style = EditingStyle::create(element, EditingStyle::AllProperties);
+ style->mergeTypingStyle(m_frame->document());
+ return style;
}
void Editor::textFieldDidBeginEditing(Element* e)
@@ -3220,12 +3270,12 @@ RenderStyle* Editor::styleForSelectionStart(Node *&nodeToRemove) const
Position position = m_frame->selection()->selection().visibleStart().deepEquivalent();
if (!position.isCandidate())
return 0;
- if (!position.node())
+ if (!position.deprecatedNode())
return 0;
RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle();
if (!typingStyle || !typingStyle->style())
- return position.node()->renderer()->style();
+ return position.deprecatedNode()->renderer()->style();
RefPtr<Element> styleElement = m_frame->document()->createElement(spanTag, false);
@@ -3237,7 +3287,7 @@ RenderStyle* Editor::styleForSelectionStart(Node *&nodeToRemove) const
styleElement->appendChild(m_frame->document()->createEditingTextNode(""), ec);
ASSERT(!ec);
- position.node()->parentNode()->appendChild(styleElement, ec);
+ position.deprecatedNode()->parentNode()->appendChild(styleElement, ec);
ASSERT(!ec);
nodeToRemove = styleElement.get();
@@ -3439,7 +3489,7 @@ void Editor::setMarkedTextMatchesAreHighlighted(bool flag)
m_frame->document()->markers()->repaintMarkers(DocumentMarker::TextMatch);
}
-void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping)
+void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, SelectionController::SetSelectionOptions options)
{
#if SUPPORT_AUTOCORRECTION_PANEL
// Make sure there's no pending autocorrection before we call markMisspellingsAndBadGrammar() below.
@@ -3450,6 +3500,7 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, boo
}
#endif // SUPPORT_AUTOCORRECTION_PANEL
+ bool closeTyping = options & SelectionController::CloseTyping;
bool isContinuousSpellCheckingEnabled = this->isContinuousSpellCheckingEnabled();
bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && isGrammarCheckingEnabled();
if (isContinuousSpellCheckingEnabled) {
@@ -3463,10 +3514,16 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, boo
newSelectedSentence = VisibleSelection(startOfSentence(newStart), endOfSentence(newStart));
}
+ bool shouldCheckSpellingAndGrammar = true;
+#if SUPPORT_AUTOCORRECTION_PANEL
+ // Don't check spelling and grammar if the change of selection is triggered by spelling correction itself.
+ shouldCheckSpellingAndGrammar = !(options & SelectionController::SpellCorrectionTriggered);
+#endif
+
// When typing we check spelling elsewhere, so don't redo it here.
// If this is a change in selection resulting from a delete operation,
// oldSelection may no longer be in the document.
- if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
+ if (shouldCheckSpellingAndGrammar && closeTyping && oldSelection.isContentEditable() && oldSelection.start().deprecatedNode() && oldSelection.start().anchorNode()->inDocument()) {
VisiblePosition oldStart(oldSelection.visibleStart());
VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
if (oldAdjacentWords != newAdjacentWords) {
@@ -3505,7 +3562,7 @@ static Node* findFirstMarkable(Node* node)
if (node->renderer()->isText())
return node;
if (node->renderer()->isTextControl())
- node = toRenderTextControl(node->renderer())->visiblePositionForIndex(1).deepEquivalent().node();
+ node = toRenderTextControl(node->renderer())->visiblePositionForIndex(1).deepEquivalent().deprecatedNode();
else if (node->firstChild())
node = node->firstChild();
else
@@ -3517,7 +3574,7 @@ static Node* findFirstMarkable(Node* node)
bool Editor::selectionStartHasSpellingMarkerFor(int from, int length) const
{
- Node* node = findFirstMarkable(m_frame->selection()->start().node());
+ Node* node = findFirstMarkable(m_frame->selection()->start().deprecatedNode());
if (!node)
return false;
@@ -3533,5 +3590,10 @@ bool Editor::selectionStartHasSpellingMarkerFor(int from, int length) const
return false;
}
+FloatRect Editor::windowRectForRange(const Range* range) const
+{
+ FrameView* view = frame()->view();
+ return view ? view->contentsToWindow(IntRect(range->boundingRect())) : FloatRect();
+}
} // namespace WebCore
diff --git a/Source/WebCore/editing/Editor.h b/Source/WebCore/editing/Editor.h
index 0a06a4a..e1a7119 100644
--- a/Source/WebCore/editing/Editor.h
+++ b/Source/WebCore/editing/Editor.h
@@ -35,6 +35,7 @@
#include "EditorDeleteAction.h"
#include "EditorInsertAction.h"
#include "FindOptions.h"
+#include "SelectionController.h"
#include "Timer.h"
#include "VisibleSelection.h"
#include "WritingDirection.h"
@@ -61,6 +62,7 @@ class Pasteboard;
class SimpleFontData;
class SpellChecker;
class Text;
+class TextCheckerClient;
class TextEvent;
struct CompositionUnderline {
@@ -74,7 +76,6 @@ struct CompositionUnderline {
bool thick;
};
-enum TriState { FalseTriState, TrueTriState, MixedTriState };
enum EditorCommandSource { CommandFromMenuOrKeyBinding, CommandFromDOM, CommandFromDOMWithUserInterface };
class Editor {
@@ -83,6 +84,8 @@ public:
~Editor();
EditorClient* client() const;
+ TextCheckerClient* textChecker() const;
+
Frame* frame() const { return m_frame; }
DeleteButtonController* deleteButtonController() const { return m_deleteButtonController.get(); }
EditCommand* lastEditCommand() { return m_lastEditCommand.get(); }
@@ -129,7 +132,8 @@ public:
void respondToChangedSelection(const VisibleSelection& oldSelection);
void respondToChangedContents(const VisibleSelection& endingSelection);
- TriState selectionHasStyle(CSSStyleDeclaration*) const;
+ bool selectionStartHasStyle(int propertyID, const String& value) const;
+ TriState selectionHasStyle(int propertyID, const String& value) const;
String selectionStartCSSPropertyValue(int propertyID);
const SimpleFontData* fontForSelection(bool&) const;
WritingDirection textDirectionForSelection(bool&) const;
@@ -164,11 +168,8 @@ public:
void appliedEditing(PassRefPtr<EditCommand>);
void unappliedEditing(PassRefPtr<EditCommand>);
void reappliedEditing(PassRefPtr<EditCommand>);
-
- bool selectionStartHasStyle(CSSStyleDeclaration*) const;
+ void unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction);
- bool clientIsEditable() const;
-
void setShouldStyleWithCSS(bool flag) { m_shouldStyleWithCSS = flag; }
bool shouldStyleWithCSS() const { return m_shouldStyleWithCSS; }
@@ -350,7 +351,7 @@ public:
IntRect firstRectForRange(Range*) const;
- void respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping);
+ void respondToChangedSelection(const VisibleSelection& oldSelection, SelectionController::SetSelectionOptions);
bool shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity, bool stillSelecting) const;
RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const;
@@ -360,7 +361,7 @@ public:
bool markedTextMatchesAreHighlighted() const;
void setMarkedTextMatchesAreHighlighted(bool);
- PassRefPtr<CSSMutableStyleDeclaration> selectionComputedStyle(bool& shouldUseFixedFontDefaultSize) const;
+ PassRefPtr<EditingStyle> selectionStartStyle() const;
void textFieldDidBeginEditing(Element*);
void textFieldDidEndEditing(Element*);
@@ -374,6 +375,7 @@ public:
NSWritingDirection baseWritingDirectionForSelectionStart() const;
bool canCopyExcludingStandaloneImages();
void takeFindStringFromSelection();
+ void writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes);
#endif
bool selectionStartHasSpellingMarkerFor(int from, int length) const;
@@ -424,7 +426,9 @@ private:
void stopCorrectionPanelTimer();
void dismissCorrectionPanel(ReasonForDismissingCorrectionPanel);
void applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd);
- void applyAutocorrectionBeforeTypingIfAppropriate();
+ // Return true if correction was applied, false otherwise.
+ bool applyAutocorrectionBeforeTypingIfAppropriate();
+ FloatRect windowRectForRange(const Range*) const;
};
inline void Editor::setStartNewKillRingSequence(bool flag)
diff --git a/Source/WebCore/editing/EditorCommand.cpp b/Source/WebCore/editing/EditorCommand.cpp
index 451d855..6ea9954 100644
--- a/Source/WebCore/editing/EditorCommand.cpp
+++ b/Source/WebCore/editing/EditorCommand.cpp
@@ -132,12 +132,11 @@ static bool executeApplyStyle(Frame* frame, EditorCommandSource source, EditActi
static bool executeToggleStyleInList(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, CSSValue* value)
{
ExceptionCode ec = 0;
- bool shouldUseFixedFontDefaultSize;
- RefPtr<CSSMutableStyleDeclaration> selectionStyle = frame->editor()->selectionComputedStyle(shouldUseFixedFontDefaultSize);
- if (!selectionStyle)
+ RefPtr<EditingStyle> selectionStyle = frame->editor()->selectionStartStyle();
+ if (!selectionStyle || !selectionStyle->style())
return false;
- RefPtr<CSSValue> selectedCSSValue = selectionStyle->getPropertyCSSValue(propertyID);
+ RefPtr<CSSValue> selectedCSSValue = selectionStyle->style()->getPropertyCSSValue(propertyID);
String newStyle = "none";
if (selectedCSSValue->isValueList()) {
RefPtr<CSSValueList> selectedCSSValueList = static_cast<CSSValueList*>(selectedCSSValue.get());
@@ -157,21 +156,18 @@ static bool executeToggleStyleInList(Frame* frame, EditorCommandSource source, E
static bool executeToggleStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const char* offValue, const char* onValue)
{
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- style->setProperty(propertyID, onValue); // We need to add this style to pass it to selectionStartHasStyle / selectionHasStyle
-
// Style is considered present when
// Mac: present at the beginning of selection
// other: present throughout the selection
bool styleIsPresent;
if (frame->editor()->behavior().shouldToggleStyleBasedOnStartOfSelection())
- styleIsPresent = frame->editor()->selectionStartHasStyle(style.get());
+ styleIsPresent = frame->editor()->selectionStartHasStyle(propertyID, onValue);
else
- styleIsPresent = frame->editor()->selectionHasStyle(style.get()) == TrueTriState;
+ styleIsPresent = frame->editor()->selectionHasStyle(propertyID, onValue) == TrueTriState;
- style->setProperty(propertyID, styleIsPresent ? offValue : onValue);
- return applyCommandToFrame(frame, source, action, style.get());
+ RefPtr<EditingStyle> style = EditingStyle::create(propertyID, styleIsPresent ? offValue : onValue);
+ return applyCommandToFrame(frame, source, action, style->style());
}
static bool executeApplyParagraphStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const String& propertyValue)
@@ -194,8 +190,7 @@ static bool executeApplyParagraphStyle(Frame* frame, EditorCommandSource source,
static bool executeInsertFragment(Frame* frame, PassRefPtr<DocumentFragment> fragment)
{
- applyCommand(ReplaceSelectionCommand::create(frame->document(), fragment,
- false, false, false, true, false, EditActionUnspecified));
+ applyCommand(ReplaceSelectionCommand::create(frame->document(), fragment, ReplaceSelectionCommand::PreventNesting, EditActionUnspecified));
return true;
}
@@ -229,12 +224,9 @@ static bool expandSelectionToGranularity(Frame* frame, TextGranularity granulari
static TriState stateStyle(Frame* frame, int propertyID, const char* desiredValue)
{
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- style->setProperty(propertyID, desiredValue);
-
if (frame->editor()->behavior().shouldToggleStyleBasedOnStartOfSelection())
- return frame->editor()->selectionStartHasStyle(style.get()) ? TrueTriState : FalseTriState;
- return frame->editor()->selectionHasStyle(style.get());
+ return frame->editor()->selectionStartHasStyle(propertyID, desiredValue) ? TrueTriState : FalseTriState;
+ return frame->editor()->selectionHasStyle(propertyID, desiredValue);
}
static String valueStyle(Frame* frame, int propertyID)
@@ -511,7 +503,7 @@ static bool executeInsertLineBreak(Frame* frame, Event* event, EditorCommandSour
// Doesn't scroll to make the selection visible, or modify the kill ring.
// InsertLineBreak is not implemented in IE or Firefox, so this behavior is only needed for
// backward compatibility with ourselves, and for consistency with other commands.
- TypingCommand::insertLineBreak(frame->document());
+ TypingCommand::insertLineBreak(frame->document(), 0);
return true;
}
ASSERT_NOT_REACHED();
@@ -538,7 +530,7 @@ static bool executeInsertOrderedList(Frame* frame, Event*, EditorCommandSource,
static bool executeInsertParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
{
- TypingCommand::insertParagraphSeparator(frame->document());
+ TypingCommand::insertParagraphSeparator(frame->document(), 0);
return true;
}
@@ -549,7 +541,7 @@ static bool executeInsertTab(Frame* frame, Event* event, EditorCommandSource, co
static bool executeInsertText(Frame* frame, Event*, EditorCommandSource, const String& value)
{
- TypingCommand::insertText(frame->document(), value);
+ TypingCommand::insertText(frame->document(), value, 0);
return true;
}
@@ -1121,14 +1113,26 @@ static bool supportedFromMenuOrKeyBinding(Frame*)
static bool supportedCopyCut(Frame* frame)
{
- Settings* settings = frame ? frame->settings() : 0;
- return settings && settings->javaScriptCanAccessClipboard();
+ if (!frame)
+ return false;
+
+ Settings* settings = frame->settings();
+ bool defaultValue = settings && settings->javaScriptCanAccessClipboard();
+
+ EditorClient* client = frame->editor()->client();
+ return client ? client->canCopyCut(defaultValue) : defaultValue;
}
static bool supportedPaste(Frame* frame)
{
- Settings* settings = frame ? frame->settings() : 0;
- return settings && (settings->javaScriptCanAccessClipboard() ? settings->isDOMPasteAllowed() : 0);
+ if (!frame)
+ return false;
+
+ Settings* settings = frame->settings();
+ bool defaultValue = settings && settings->javaScriptCanAccessClipboard() && settings->isDOMPasteAllowed();
+
+ EditorClient* client = frame->editor()->client();
+ return client ? client->canPaste(defaultValue) : defaultValue;
}
// Enabled functions
diff --git a/Source/WebCore/editing/FormatBlockCommand.cpp b/Source/WebCore/editing/FormatBlockCommand.cpp
index 58157af..9d90a1e 100644
--- a/Source/WebCore/editing/FormatBlockCommand.cpp
+++ b/Source/WebCore/editing/FormatBlockCommand.cpp
@@ -60,8 +60,8 @@ void FormatBlockCommand::formatSelection(const VisiblePosition& startOfSelection
void FormatBlockCommand::formatRange(const Position& start, const Position& end, const Position& endOfSelection, RefPtr<Element>& blockNode)
{
- Node* nodeToSplitTo = enclosingBlockToSplitTreeTo(start.node());
- RefPtr<Node> outerBlock = (start.node() == nodeToSplitTo) ? start.node() : splitTreeToNode(start.node(), nodeToSplitTo);
+ Node* nodeToSplitTo = enclosingBlockToSplitTreeTo(start.deprecatedNode());
+ RefPtr<Node> outerBlock = (start.deprecatedNode() == nodeToSplitTo) ? start.deprecatedNode() : splitTreeToNode(start.deprecatedNode(), nodeToSplitTo);
RefPtr<Node> nodeAfterInsertionPosition = outerBlock;
RefPtr<Range> range = Range::create(document(), start, endOfSelection);
diff --git a/Source/WebCore/editing/IndentOutdentCommand.cpp b/Source/WebCore/editing/IndentOutdentCommand.cpp
index 9d1adc1..82bec06 100644
--- a/Source/WebCore/editing/IndentOutdentCommand.cpp
+++ b/Source/WebCore/editing/IndentOutdentCommand.cpp
@@ -59,7 +59,7 @@ IndentOutdentCommand::IndentOutdentCommand(Document* document, EIndentType typeO
bool IndentOutdentCommand::tryIndentingAsListItem(const Position& start, const Position& end)
{
// If our selection is not inside a list, bail out.
- Node* lastNodeInSelectedParagraph = start.node();
+ Node* lastNodeInSelectedParagraph = start.deprecatedNode();
RefPtr<Element> listNode = enclosingList(lastNodeInSelectedParagraph);
if (!listNode)
return false;
@@ -94,15 +94,15 @@ void IndentOutdentCommand::indentIntoBlockquote(const Position& start, const Pos
Node* nodeToSplitTo;
if (enclosingCell)
nodeToSplitTo = enclosingCell;
- else if (enclosingList(start.node()))
- nodeToSplitTo = enclosingBlock(start.node());
+ else if (enclosingList(start.deprecatedNode()))
+ nodeToSplitTo = enclosingBlock(start.deprecatedNode());
else
nodeToSplitTo = editableRootForPosition(start);
if (!nodeToSplitTo)
return;
- RefPtr<Node> outerBlock = (start.node() == nodeToSplitTo) ? start.node() : splitTreeToNode(start.node(), nodeToSplitTo);
+ RefPtr<Node> outerBlock = (start.deprecatedNode() == nodeToSplitTo) ? start.deprecatedNode() : splitTreeToNode(start.deprecatedNode(), nodeToSplitTo);
if (!targetBlockquote) {
// Create a new blockquote and insert it as a child of the root editable element. We accomplish
@@ -166,13 +166,13 @@ void IndentOutdentCommand::outdentParagraph()
return;
}
- Node* enclosingBlockFlow = enclosingBlock(visibleStartOfParagraph.deepEquivalent().node());
+ Node* enclosingBlockFlow = enclosingBlock(visibleStartOfParagraph.deepEquivalent().deprecatedNode());
RefPtr<Node> splitBlockquoteNode = enclosingNode;
if (enclosingBlockFlow != enclosingNode)
splitBlockquoteNode = splitTreeToNode(enclosingBlockFlow, enclosingNode, true);
else {
// We split the blockquote at where we start outdenting.
- splitElement(static_cast<Element*>(enclosingNode), visibleStartOfParagraph.deepEquivalent().node());
+ splitElement(static_cast<Element*>(enclosingNode), visibleStartOfParagraph.deepEquivalent().deprecatedNode());
}
RefPtr<Node> placeholder = createBreakElement(document());
insertNodeBefore(placeholder, splitBlockquoteNode);
@@ -205,10 +205,10 @@ void IndentOutdentCommand::outdentRegion(const VisiblePosition& startOfSelection
// outdentParagraph could move more than one paragraph if the paragraph
// is in a list item. As a result, endAfterSelection and endOfNextParagraph
// could refer to positions no longer in the document.
- if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().node()->inDocument())
+ if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().anchorNode()->inDocument())
break;
- if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().node()->inDocument()) {
+ if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().anchorNode()->inDocument()) {
endOfCurrentParagraph = endingSelection().end();
endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
}
diff --git a/Source/WebCore/editing/InsertLineBreakCommand.cpp b/Source/WebCore/editing/InsertLineBreakCommand.cpp
index af8f2fc..2260a00 100644
--- a/Source/WebCore/editing/InsertLineBreakCommand.cpp
+++ b/Source/WebCore/editing/InsertLineBreakCommand.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "InsertLineBreakCommand.h"
-#include "CSSMutableStyleDeclaration.h"
#include "Document.h"
#include "Frame.h"
#include "HTMLElement.h"
@@ -57,11 +56,11 @@ void InsertLineBreakCommand::insertNodeAfterPosition(Node* node, const Position&
// Insert the BR after the caret position. In the case the
// position is a block, do an append. We don't want to insert
// the BR *after* the block.
- Element* cb = pos.node()->enclosingBlockFlowElement();
- if (cb == pos.node())
+ Element* cb = pos.deprecatedNode()->enclosingBlockFlowElement();
+ if (cb == pos.deprecatedNode())
appendNode(node, cb);
else
- insertNodeAfter(node, pos.node());
+ insertNodeAfter(node, pos.deprecatedNode());
}
void InsertLineBreakCommand::insertNodeBeforePosition(Node* node, const Position& pos)
@@ -69,11 +68,11 @@ void InsertLineBreakCommand::insertNodeBeforePosition(Node* node, const Position
// Insert the BR after the caret position. In the case the
// position is a block, do an append. We don't want to insert
// the BR *before* the block.
- Element* cb = pos.node()->enclosingBlockFlowElement();
- if (cb == pos.node())
+ Element* cb = pos.deprecatedNode()->enclosingBlockFlowElement();
+ if (cb == pos.deprecatedNode())
appendNode(node, cb);
else
- insertNodeBefore(node, pos.node());
+ insertNodeBefore(node, pos.deprecatedNode());
}
// Whether we should insert a break element or a '\n'.
@@ -83,7 +82,7 @@ bool InsertLineBreakCommand::shouldUseBreakElement(const Position& insertionPos)
// the input element, and in that case we need to check the input element's
// parent's renderer.
Position p(insertionPos.parentAnchoredEquivalent());
- return p.node()->renderer() && !p.node()->renderer()->style()->preserveNewline();
+ return p.deprecatedNode()->renderer() && !p.deprecatedNode()->renderer()->style()->preserveNewline();
}
void InsertLineBreakCommand::doApply()
@@ -114,7 +113,7 @@ void InsertLineBreakCommand::doApply()
// FIXME: Need to merge text nodes when inserting just after or before text.
if (isEndOfParagraph(caret) && !lineBreakExistsAtVisiblePosition(caret)) {
- bool needExtraLineBreak = !pos.node()->hasTagName(hrTag) && !pos.node()->hasTagName(tableTag);
+ bool needExtraLineBreak = !pos.deprecatedNode()->hasTagName(hrTag) && !pos.deprecatedNode()->hasTagName(tableTag);
insertNodeAt(nodeToInsert.get(), pos);
@@ -123,7 +122,7 @@ void InsertLineBreakCommand::doApply()
VisiblePosition endingPosition(positionBeforeNode(nodeToInsert.get()));
setEndingSelection(VisibleSelection(endingPosition));
- } else if (pos.deprecatedEditingOffset() <= caretMinOffset(pos.node())) {
+ } else if (pos.deprecatedEditingOffset() <= caretMinOffset(pos.deprecatedNode())) {
insertNodeAt(nodeToInsert.get(), pos);
// Insert an extra br or '\n' if the just inserted one collapsed.
@@ -133,12 +132,12 @@ void InsertLineBreakCommand::doApply()
setEndingSelection(VisibleSelection(positionInParentAfterNode(nodeToInsert.get()), DOWNSTREAM));
// If we're inserting after all of the rendered text in a text node, or into a non-text node,
// a simple insertion is sufficient.
- } else if (pos.deprecatedEditingOffset() >= caretMaxOffset(pos.node()) || !pos.node()->isTextNode()) {
+ } else if (pos.deprecatedEditingOffset() >= caretMaxOffset(pos.deprecatedNode()) || !pos.deprecatedNode()->isTextNode()) {
insertNodeAt(nodeToInsert.get(), pos);
setEndingSelection(VisibleSelection(positionInParentAfterNode(nodeToInsert.get()), DOWNSTREAM));
- } else if (pos.node()->isTextNode()) {
+ } else if (pos.deprecatedNode()->isTextNode()) {
// Split a text node
- Text* textNode = static_cast<Text*>(pos.node());
+ Text* textNode = static_cast<Text*>(pos.deprecatedNode());
splitTextNode(textNode, pos.deprecatedEditingOffset());
insertNodeBefore(nodeToInsert, textNode);
Position endingPosition = firstPositionInNode(textNode);
diff --git a/Source/WebCore/editing/InsertListCommand.cpp b/Source/WebCore/editing/InsertListCommand.cpp
index c24c683..68661b4 100644
--- a/Source/WebCore/editing/InsertListCommand.cpp
+++ b/Source/WebCore/editing/InsertListCommand.cpp
@@ -84,12 +84,12 @@ bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection
{
VisiblePosition start = selection.visibleStart();
- if (!enclosingList(start.deepEquivalent().node()))
+ if (!enclosingList(start.deepEquivalent().deprecatedNode()))
return false;
VisiblePosition end = selection.visibleEnd();
while (start.isNotNull() && start != end) {
- Element* listNode = enclosingList(start.deepEquivalent().node());
+ Element* listNode = enclosingList(start.deepEquivalent().deprecatedNode());
if (!listNode || !listNode->hasTagName(listTag))
return false;
start = startOfNextParagraph(start);
@@ -143,7 +143,7 @@ void InsertListCommand::doApply()
// infinite loop and because there is no more work to be done.
// FIXME(<rdar://problem/5983974>): The endingSelection() may be incorrect here. Compute
// the new location of endOfSelection and use it as the end of the new selection.
- if (!startOfLastParagraph.deepEquivalent().node()->inDocument())
+ if (!startOfLastParagraph.deepEquivalent().anchorNode()->inDocument())
return;
setEndingSelection(startOfCurrentParagraph);
@@ -191,7 +191,7 @@ void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const Qu
// FIXME: This will produce unexpected results for a selection that starts just before a
// table and ends inside the first cell, selectionForParagraphIteration should probably
// be renamed and deployed inside setEndingSelection().
- Node* selectionNode = endingSelection().start().node();
+ Node* selectionNode = endingSelection().start().deprecatedNode();
Node* listChildNode = enclosingListChild(selectionNode);
bool switchListType = false;
if (listChildNode) {
@@ -217,7 +217,7 @@ void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const Qu
RefPtr<HTMLElement> newList = createHTMLElement(document(), listTag);
insertNodeBefore(newList, listNode);
- Node* firstChildInList = enclosingListChild(VisiblePosition(firstPositionInNode(listNode.get())).deepEquivalent().node(), listNode.get());
+ Node* firstChildInList = enclosingListChild(VisiblePosition(firstPositionInNode(listNode.get())).deepEquivalent().deprecatedNode(), listNode.get());
Node* outerBlock = firstChildInList->isBlockFlow() ? firstChildInList : listNode.get();
moveParagraphWithClones(firstPositionInNode(listNode.get()), lastPositionInNode(listNode.get()), newList.get(), outerBlock);
@@ -265,9 +265,9 @@ void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart,
// A paragraph is visually a list item minus a list marker. The paragraph will be moved.
start = startOfParagraph(originalStart);
end = endOfParagraph(start);
- nextListChild = enclosingListChild(end.next().deepEquivalent().node(), listNode);
+ nextListChild = enclosingListChild(end.next().deepEquivalent().deprecatedNode(), listNode);
ASSERT(nextListChild != listChildNode);
- previousListChild = enclosingListChild(start.previous().deepEquivalent().node(), listNode);
+ previousListChild = enclosingListChild(start.previous().deepEquivalent().deprecatedNode(), listNode);
ASSERT(previousListChild != listChildNode);
}
// When removing a list, we must always create a placeholder to act as a point of insertion
@@ -308,7 +308,7 @@ void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart,
static Element* adjacentEnclosingList(const VisiblePosition& pos, const VisiblePosition& adjacentPos, const QualifiedName& listTag)
{
- Element* listNode = outermostEnclosingList(adjacentPos.deepEquivalent().node());
+ Element* listNode = outermostEnclosingList(adjacentPos.deepEquivalent().deprecatedNode());
if (!listNode)
return 0;
@@ -317,9 +317,9 @@ static Element* adjacentEnclosingList(const VisiblePosition& pos, const VisibleP
Node* currentCell = enclosingTableCell(adjacentPos.deepEquivalent());
if (!listNode->hasTagName(listTag)
- || listNode->contains(pos.deepEquivalent().node())
+ || listNode->contains(pos.deepEquivalent().deprecatedNode())
|| previousCell != currentCell
- || enclosingList(listNode) != enclosingList(pos.deepEquivalent().node()))
+ || enclosingList(listNode) != enclosingList(pos.deepEquivalent().deprecatedNode()))
return 0;
return listNode;
@@ -351,7 +351,7 @@ PassRefPtr<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePositio
listElement = createHTMLElement(document(), listTag);
appendNode(listItemElement, listElement);
- if (start == end && isBlock(start.deepEquivalent().node())) {
+ if (start == end && isBlock(start.deepEquivalent().deprecatedNode())) {
// Inserting the list into an empty paragraph that isn't held open
// by a br or a '\n', will invalidate start and end. Insert
// a placeholder and then recompute start and end.
@@ -367,7 +367,7 @@ PassRefPtr<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePositio
// clean markup when inline elements are pushed down as far as possible.
Position insertionPos(start.deepEquivalent().upstream());
// Also avoid the containing list item.
- Node* listChild = enclosingListChild(insertionPos.node());
+ Node* listChild = enclosingListChild(insertionPos.deprecatedNode());
if (listChild && listChild->hasTagName(liTag))
insertionPos = positionInParentBeforeNode(listChild);
diff --git a/Source/WebCore/editing/InsertParagraphSeparatorCommand.cpp b/Source/WebCore/editing/InsertParagraphSeparatorCommand.cpp
index 1d50851..771c56a 100644
--- a/Source/WebCore/editing/InsertParagraphSeparatorCommand.cpp
+++ b/Source/WebCore/editing/InsertParagraphSeparatorCommand.cpp
@@ -78,8 +78,10 @@ void InsertParagraphSeparatorCommand::calculateStyleBeforeInsertion(const Positi
VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
if (!isStartOfParagraph(visiblePos) && !isEndOfParagraph(visiblePos))
return;
-
- m_style = editingStyleIncludingTypingStyle(pos);
+
+ ASSERT(pos.isNotNull());
+ m_style = EditingStyle::create(pos);
+ m_style->mergeTypingStyle(pos.anchorNode()->document());
}
void InsertParagraphSeparatorCommand::applyStyleAfterInsertion(Node* originalEnclosingBlock)
@@ -169,8 +171,8 @@ void InsertParagraphSeparatorCommand::doApply()
|| isTableCell(startBlock)
|| startBlock->hasTagName(formTag)
// FIXME: If the node is hidden, we don't have a canonical position so we will do the wrong thing for tables and <hr>. https://bugs.webkit.org/show_bug.cgi?id=40342
- || (!canonicalPos.isNull() && canonicalPos.node()->renderer() && canonicalPos.node()->renderer()->isTable())
- || (!canonicalPos.isNull() && canonicalPos.node()->hasTagName(hrTag))) {
+ || (!canonicalPos.isNull() && canonicalPos.deprecatedNode()->renderer() && canonicalPos.deprecatedNode()->renderer()->isTable())
+ || (!canonicalPos.isNull() && canonicalPos.deprecatedNode()->hasTagName(hrTag))) {
applyCommandToComposite(InsertLineBreakCommand::create(document()));
return;
}
@@ -237,7 +239,7 @@ void InsertParagraphSeparatorCommand::doApply()
// Recreate the same structure in the new paragraph.
Vector<Element*> ancestors;
- getAncestorsInsideBlock(insertionPosition.node(), startBlock, ancestors);
+ getAncestorsInsideBlock(insertionPosition.deprecatedNode(), startBlock, ancestors);
RefPtr<Element> parent = cloneHierarchyUnderNewBlock(ancestors, blockToInsert);
appendBlockPlaceholder(parent);
@@ -254,11 +256,11 @@ void InsertParagraphSeparatorCommand::doApply()
Node *refNode;
if (isFirstInBlock && !nestNewBlock)
refNode = startBlock;
- else if (insertionPosition.node() == startBlock && nestNewBlock) {
+ else if (insertionPosition.deprecatedNode() == startBlock && nestNewBlock) {
refNode = startBlock->childNode(insertionPosition.deprecatedEditingOffset());
ASSERT(refNode); // must be true or we'd be in the end of block case
} else
- refNode = insertionPosition.node();
+ refNode = insertionPosition.deprecatedNode();
// find ending selection position easily before inserting the paragraph
insertionPosition = insertionPosition.downstream();
@@ -268,7 +270,7 @@ void InsertParagraphSeparatorCommand::doApply()
// Recreate the same structure in the new paragraph.
Vector<Element*> ancestors;
- getAncestorsInsideBlock(positionAvoidingSpecialElementBoundary(insertionPosition).node(), startBlock, ancestors);
+ getAncestorsInsideBlock(positionAvoidingSpecialElementBoundary(insertionPosition).deprecatedNode(), startBlock, ancestors);
appendBlockPlaceholder(cloneHierarchyUnderNewBlock(ancestors, blockToInsert));
@@ -301,22 +303,22 @@ void InsertParagraphSeparatorCommand::doApply()
// Build up list of ancestors in between the start node and the start block.
Vector<Element*> ancestors;
- getAncestorsInsideBlock(insertionPosition.node(), startBlock, ancestors);
+ getAncestorsInsideBlock(insertionPosition.deprecatedNode(), startBlock, ancestors);
// Make sure we do not cause a rendered space to become unrendered.
// FIXME: We need the affinity for pos, but pos.downstream() does not give it
Position leadingWhitespace = insertionPosition.leadingWhitespacePosition(VP_DEFAULT_AFFINITY);
// FIXME: leadingWhitespacePosition is returning the position before preserved newlines for positions
// after the preserved newline, causing the newline to be turned into a nbsp.
- if (leadingWhitespace.isNotNull() && leadingWhitespace.node()->isTextNode()) {
- Text* textNode = static_cast<Text*>(leadingWhitespace.node());
+ if (leadingWhitespace.isNotNull() && leadingWhitespace.deprecatedNode()->isTextNode()) {
+ Text* textNode = static_cast<Text*>(leadingWhitespace.deprecatedNode());
ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
replaceTextInNode(textNode, leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
}
// Split at pos if in the middle of a text node.
- if (insertionPosition.node()->isTextNode()) {
- Text* textNode = static_cast<Text*>(insertionPosition.node());
+ if (insertionPosition.deprecatedNode()->isTextNode()) {
+ Text* textNode = static_cast<Text*>(insertionPosition.deprecatedNode());
bool atEnd = (unsigned)insertionPosition.deprecatedEditingOffset() >= textNode->length();
if (insertionPosition.deprecatedEditingOffset() > 0 && !atEnd) {
splitTextNode(textNode, insertionPosition.deprecatedEditingOffset());
@@ -344,8 +346,8 @@ void InsertParagraphSeparatorCommand::doApply()
appendNode(createBreakElement(document()).get(), blockToInsert.get());
// Move the start node and the siblings of the start node.
- if (insertionPosition.node() != startBlock) {
- Node* n = insertionPosition.node();
+ if (insertionPosition.deprecatedNode() != startBlock) {
+ Node* n = insertionPosition.deprecatedNode();
if (insertionPosition.deprecatedEditingOffset() >= caretMaxOffset(n))
n = n->nextSibling();
@@ -382,10 +384,10 @@ void InsertParagraphSeparatorCommand::doApply()
insertionPosition.moveToOffset(0);
if (!insertionPosition.isRenderedCharacter()) {
// Clear out all whitespace and insert one non-breaking space
- ASSERT(!insertionPosition.node()->renderer() || insertionPosition.node()->renderer()->style()->collapseWhiteSpace());
+ ASSERT(!insertionPosition.deprecatedNode()->renderer() || insertionPosition.deprecatedNode()->renderer()->style()->collapseWhiteSpace());
deleteInsignificantTextDownstream(insertionPosition);
- if (insertionPosition.node()->isTextNode())
- insertTextIntoNode(static_cast<Text*>(insertionPosition.node()), 0, nonBreakingSpaceString());
+ if (insertionPosition.deprecatedNode()->isTextNode())
+ insertTextIntoNode(static_cast<Text*>(insertionPosition.deprecatedNode()), 0, nonBreakingSpaceString());
}
}
diff --git a/Source/WebCore/editing/InsertTextCommand.cpp b/Source/WebCore/editing/InsertTextCommand.cpp
index 1ec11ad..33ebe3a 100644
--- a/Source/WebCore/editing/InsertTextCommand.cpp
+++ b/Source/WebCore/editing/InsertTextCommand.cpp
@@ -26,19 +26,13 @@
#include "config.h"
#include "InsertTextCommand.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSMutableStyleDeclaration.h"
-#include "CSSPropertyNames.h"
#include "Document.h"
#include "Element.h"
#include "EditingText.h"
#include "Editor.h"
#include "Frame.h"
-#include "Logging.h"
#include "HTMLInterchange.h"
#include "htmlediting.h"
-#include "TextIterator.h"
-#include "TypingCommand.h"
#include "visible_units.h"
#include <wtf/unicode/CharacterNames.h>
@@ -53,20 +47,20 @@ void InsertTextCommand::doApply()
{
}
-Position InsertTextCommand::prepareForTextInsertion(const Position& p)
+Position InsertTextCommand::positionInsideTextNode(const Position& p)
{
Position pos = p;
- // Prepare for text input by looking at the specified position.
- // It may be necessary to insert a text node to receive characters.
- if (!pos.node()->isTextNode()) {
+ if (isTabSpanTextNode(pos.anchorNode())) {
RefPtr<Node> textNode = document()->createEditingTextNode("");
- insertNodeAt(textNode.get(), pos);
+ insertNodeAtTabSpanPosition(textNode.get(), pos);
return firstPositionInNode(textNode.get());
}
- if (isTabSpanTextNode(pos.node())) {
+ // Prepare for text input by looking at the specified position.
+ // It may be necessary to insert a text node to receive characters.
+ if (!pos.containerNode()->isTextNode()) {
RefPtr<Node> textNode = document()->createEditingTextNode("");
- insertNodeAtTabSpanPosition(textNode.get(), pos);
+ insertNodeAt(textNode.get(), pos);
return firstPositionInNode(textNode.get());
}
@@ -147,9 +141,9 @@ void InsertTextCommand::input(const String& text, bool selectInsertedText, Rebal
// It is possible for the node that contains startPosition to contain only unrendered whitespace,
// and so deleteInsignificantText could remove it. Save the position before the node in case that happens.
- Position positionBeforeStartNode(positionInParentBeforeNode(startPosition.node()));
+ Position positionBeforeStartNode(positionInParentBeforeNode(startPosition.containerNode()));
deleteInsignificantText(startPosition.upstream(), startPosition.downstream());
- if (!startPosition.node()->inDocument())
+ if (!startPosition.anchorNode()->inDocument())
startPosition = positionBeforeStartNode;
if (!startPosition.isCandidate())
startPosition = startPosition.downstream();
@@ -165,11 +159,14 @@ void InsertTextCommand::input(const String& text, bool selectInsertedText, Rebal
removePlaceholderAt(placeholder);
} else {
// Make sure the document is set up to receive text
- startPosition = prepareForTextInsertion(startPosition);
+ startPosition = positionInsideTextNode(startPosition);
+ ASSERT(startPosition.anchorType() == Position::PositionIsOffsetInAnchor);
+ ASSERT(startPosition.containerNode());
+ ASSERT(startPosition.containerNode()->isTextNode());
if (placeholder.isNotNull())
removePlaceholderAt(placeholder);
- Text *textNode = static_cast<Text *>(startPosition.node());
- int offset = startPosition.deprecatedEditingOffset();
+ Text* textNode = static_cast<Text*>(startPosition.containerNode());
+ const unsigned offset = startPosition.offsetInContainerNode();
insertTextIntoNode(textNode, offset, text);
endPosition = Position(textNode, offset + text.length(), Position::PositionIsOffsetInAnchor);
@@ -183,7 +180,7 @@ void InsertTextCommand::input(const String& text, bool selectInsertedText, Rebal
} else {
ASSERT(whitespaceRebalance == RebalanceAllWhitespaces);
if (canRebalance(startPosition) && canRebalance(endPosition))
- rebalanceWhitespaceOnTextSubstring(textNode, startPosition.deprecatedEditingOffset(), endPosition.deprecatedEditingOffset());
+ rebalanceWhitespaceOnTextSubstring(textNode, startPosition.offsetInContainerNode(), endPosition.offsetInContainerNode());
}
}
@@ -209,7 +206,7 @@ Position InsertTextCommand::insertTab(const Position& pos)
{
Position insertPos = VisiblePosition(pos, DOWNSTREAM).deepEquivalent();
- Node *node = insertPos.node();
+ Node* node = insertPos.deprecatedNode();
unsigned int offset = insertPos.deprecatedEditingOffset();
// keep tabs coalesced in tab span
diff --git a/Source/WebCore/editing/InsertTextCommand.h b/Source/WebCore/editing/InsertTextCommand.h
index 672e576..da86a7b 100644
--- a/Source/WebCore/editing/InsertTextCommand.h
+++ b/Source/WebCore/editing/InsertTextCommand.h
@@ -53,7 +53,7 @@ private:
virtual void doApply();
virtual bool isInsertTextCommand() const;
- Position prepareForTextInsertion(const Position&);
+ Position positionInsideTextNode(const Position&);
Position insertTab(const Position&);
bool performTrivialReplace(const String&, bool selectInsertedText);
diff --git a/Source/WebCore/editing/ModifySelectionListLevel.cpp b/Source/WebCore/editing/ModifySelectionListLevel.cpp
index 3e6754e..cbcd488 100644
--- a/Source/WebCore/editing/ModifySelectionListLevel.cpp
+++ b/Source/WebCore/editing/ModifySelectionListLevel.cpp
@@ -52,12 +52,12 @@ static bool getStartEndListChildren(const VisibleSelection& selection, Node*& st
return false;
// start must be in a list child
- Node* startListChild = enclosingListChild(selection.start().node());
+ Node* startListChild = enclosingListChild(selection.start().anchorNode());
if (!startListChild)
return false;
-
+
// end must be in a list child
- Node* endListChild = selection.isRange() ? enclosingListChild(selection.end().node()) : startListChild;
+ Node* endListChild = selection.isRange() ? enclosingListChild(selection.end().anchorNode()) : startListChild;
if (!endListChild)
return false;
diff --git a/Source/WebCore/editing/MoveSelectionCommand.cpp b/Source/WebCore/editing/MoveSelectionCommand.cpp
index 0f23b29..cdf05ee 100644
--- a/Source/WebCore/editing/MoveSelectionCommand.cpp
+++ b/Source/WebCore/editing/MoveSelectionCommand.cpp
@@ -32,7 +32,7 @@
namespace WebCore {
MoveSelectionCommand::MoveSelectionCommand(PassRefPtr<DocumentFragment> fragment, const Position& position, bool smartInsert, bool smartDelete)
- : CompositeEditCommand(position.node()->document()), m_fragment(fragment), m_position(position), m_smartInsert(smartInsert), m_smartDelete(smartDelete)
+ : CompositeEditCommand(position.anchorNode()->document()), m_fragment(fragment), m_position(position), m_smartInsert(smartInsert), m_smartDelete(smartDelete)
{
ASSERT(m_fragment);
}
@@ -62,7 +62,7 @@ void MoveSelectionCommand::doApply()
// set the destination to the ending point after the deletion.
// Fixes: <rdar://problem/3910425> REGRESSION (Mail): Crash in ReplaceSelectionCommand;
// selection is empty, leading to null deref
- if (!pos.node()->inDocument())
+ if (!pos.anchorNode()->inDocument())
pos = endingSelection().start();
setEndingSelection(VisibleSelection(pos, endingSelection().affinity()));
@@ -70,7 +70,10 @@ void MoveSelectionCommand::doApply()
// Document was modified out from under us.
return;
}
- applyCommandToComposite(ReplaceSelectionCommand::create(document(), m_fragment, true, m_smartInsert));
+ ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::PreventNesting;
+ if (m_smartInsert)
+ options |= ReplaceSelectionCommand::SmartReplace;
+ applyCommandToComposite(ReplaceSelectionCommand::create(document(), m_fragment, options));
}
EditAction MoveSelectionCommand::editingAction() const
diff --git a/Source/WebCore/editing/RemoveCSSPropertyCommand.h b/Source/WebCore/editing/RemoveCSSPropertyCommand.h
index 46e0498..00ed3bc 100644
--- a/Source/WebCore/editing/RemoveCSSPropertyCommand.h
+++ b/Source/WebCore/editing/RemoveCSSPropertyCommand.h
@@ -27,7 +27,6 @@
#define RemoveCSSPropertyCommand_h
#include "EditCommand.h"
-#include "CSSMutableStyleDeclaration.h"
#include "CSSPropertyNames.h"
#include "StyledElement.h"
diff --git a/Source/WebCore/editing/ReplaceSelectionCommand.cpp b/Source/WebCore/editing/ReplaceSelectionCommand.cpp
index 846b932..b0a2d68 100644
--- a/Source/WebCore/editing/ReplaceSelectionCommand.cpp
+++ b/Source/WebCore/editing/ReplaceSelectionCommand.cpp
@@ -110,15 +110,15 @@ static bool isInterchangeConvertedSpaceSpan(const Node *node)
static Position positionAvoidingPrecedingNodes(Position pos)
{
// If we're already on a break, it's probably a placeholder and we shouldn't change our position.
- if (pos.node()->hasTagName(brTag))
+ if (pos.deprecatedNode()->hasTagName(brTag))
return pos;
// We also stop when changing block flow elements because even though the visual position is the
// same. E.g.,
// <div>foo^</div>^
// The two positions above are the same visual position, but we want to stay in the same block.
- Node* stopNode = pos.node()->enclosingBlockFlowElement();
- while (stopNode != pos.node() && VisiblePosition(pos) == VisiblePosition(pos.next()))
+ Node* stopNode = pos.deprecatedNode()->enclosingBlockFlowElement();
+ while (stopNode != pos.deprecatedNode() && VisiblePosition(pos) == VisiblePosition(pos.next()))
pos = pos.next();
return pos;
}
@@ -152,7 +152,7 @@ ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* f
return;
}
- Node* styleNode = selection.base().node();
+ Node* styleNode = selection.base().deprecatedNode();
RefPtr<StyledElement> holder = insertFragmentForTestRendering(styleNode);
RefPtr<Range> range = VisibleSelection::selectionFromContentsOfNode(holder.get()).toNormalizedRange();
@@ -340,18 +340,16 @@ void ReplacementFragment::removeInterchangeNodes(Node* container)
}
}
-ReplaceSelectionCommand::ReplaceSelectionCommand(Document* document, PassRefPtr<DocumentFragment> fragment,
- bool selectReplacement, bool smartReplace, bool matchStyle, bool preventNesting, bool movingParagraph,
- EditAction editAction)
- : CompositeEditCommand(document),
- m_selectReplacement(selectReplacement),
- m_smartReplace(smartReplace),
- m_matchStyle(matchStyle),
- m_documentFragment(fragment),
- m_preventNesting(preventNesting),
- m_movingParagraph(movingParagraph),
- m_editAction(editAction),
- m_shouldMergeEnd(false)
+ReplaceSelectionCommand::ReplaceSelectionCommand(Document* document, PassRefPtr<DocumentFragment> fragment, CommandOptions options, EditAction editAction)
+ : CompositeEditCommand(document)
+ , m_selectReplacement(options & SelectReplacement)
+ , m_smartReplace(options & SmartReplace)
+ , m_matchStyle(options & MatchStyle)
+ , m_documentFragment(fragment)
+ , m_preventNesting(options & PreventNesting)
+ , m_movingParagraph(options & MovingParagraph)
+ , m_editAction(editAction)
+ , m_shouldMergeEnd(false)
{
}
@@ -359,7 +357,7 @@ static bool hasMatchingQuoteLevel(VisiblePosition endOfExistingContent, VisibleP
{
Position existing = endOfExistingContent.deepEquivalent();
Position inserted = endOfInsertedContent.deepEquivalent();
- bool isInsideMailBlockquote = nearestMailBlockquote(inserted.node());
+ bool isInsideMailBlockquote = nearestMailBlockquote(inserted.deprecatedNode());
return isInsideMailBlockquote && (numEnclosingMailBlockquotes(existing) == numEnclosingMailBlockquotes(inserted));
}
@@ -381,11 +379,11 @@ bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfPara
if (isStartOfParagraph(startOfInsertedContent) && selectionStartWasInsideMailBlockquote && hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent()))
return true;
- return !selectionStartWasStartOfParagraph &&
- !fragmentHasInterchangeNewlineAtStart &&
- isStartOfParagraph(startOfInsertedContent) &&
- !startOfInsertedContent.deepEquivalent().node()->hasTagName(brTag) &&
- shouldMerge(startOfInsertedContent, prev);
+ return !selectionStartWasStartOfParagraph
+ && !fragmentHasInterchangeNewlineAtStart
+ && isStartOfParagraph(startOfInsertedContent)
+ && !startOfInsertedContent.deepEquivalent().deprecatedNode()->hasTagName(brTag)
+ && shouldMerge(startOfInsertedContent, prev);
}
bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph)
@@ -395,10 +393,10 @@ bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph)
if (next.isNull())
return false;
- return !selectionEndWasEndOfParagraph &&
- isEndOfParagraph(endOfInsertedContent) &&
- !endOfInsertedContent.deepEquivalent().node()->hasTagName(brTag) &&
- shouldMerge(endOfInsertedContent, next);
+ return !selectionEndWasEndOfParagraph
+ && isEndOfParagraph(endOfInsertedContent)
+ && !endOfInsertedContent.deepEquivalent().deprecatedNode()->hasTagName(brTag)
+ && shouldMerge(endOfInsertedContent, next);
}
static bool isMailPasteAsQuotationNode(const Node* node)
@@ -455,8 +453,8 @@ bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V
if (source.isNull() || destination.isNull())
return false;
- Node* sourceNode = source.deepEquivalent().node();
- Node* destinationNode = destination.deepEquivalent().node();
+ Node* sourceNode = source.deepEquivalent().deprecatedNode();
+ Node* destinationNode = destination.deepEquivalent().deprecatedNode();
Node* sourceBlock = enclosingBlock(sourceNode);
Node* destinationBlock = enclosingBlock(destinationNode);
return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotationNode) &&
@@ -742,7 +740,7 @@ void ReplaceSelectionCommand::mergeEndIfNeeded()
// To avoid this, we add a placeholder node before the start of the paragraph.
if (endOfParagraph(startOfParagraphToMove) == destination) {
RefPtr<Node> placeholder = createBreakElement(document());
- insertNodeBefore(placeholder, startOfParagraphToMove.deepEquivalent().node());
+ insertNodeBefore(placeholder, startOfParagraphToMove.deepEquivalent().deprecatedNode());
destination = VisiblePosition(positionBeforeNode(placeholder.get()));
}
@@ -753,9 +751,9 @@ void ReplaceSelectionCommand::mergeEndIfNeeded()
// only ever used to create positions where inserted content starts/ends. Also, we sometimes insert content
// directly into text nodes already in the document, in which case tracking inserted nodes is inadequate.
if (mergeForward) {
- m_lastLeafInserted = destination.previous().deepEquivalent().node();
+ m_lastLeafInserted = destination.previous().deepEquivalent().deprecatedNode();
if (!m_firstNodeInserted->inDocument())
- m_firstNodeInserted = endingSelection().visibleStart().deepEquivalent().node();
+ m_firstNodeInserted = endingSelection().visibleStart().deepEquivalent().deprecatedNode();
// If we merged text nodes, m_lastLeafInserted could be null. If this is the case,
// we use m_firstNodeInserted.
if (!m_lastLeafInserted)
@@ -782,8 +780,8 @@ void ReplaceSelectionCommand::doApply()
{
VisibleSelection selection = endingSelection();
ASSERT(selection.isCaretOrRange());
- ASSERT(selection.start().node());
- if (!selection.isNonOrphanedCaretOrRange() || !selection.start().node())
+ ASSERT(selection.start().deprecatedNode());
+ if (!selection.isNonOrphanedCaretOrRange() || !selection.start().deprecatedNode())
return;
bool selectionIsPlainText = !selection.isContentRichlyEditable();
@@ -795,12 +793,14 @@ void ReplaceSelectionCommand::doApply()
return;
// We can skip matching the style if the selection is plain text.
- if ((selection.start().node()->renderer() && selection.start().node()->renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY) &&
- (selection.end().node()->renderer() && selection.end().node()->renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY))
+ if ((selection.start().deprecatedNode()->renderer() && selection.start().deprecatedNode()->renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY)
+ && (selection.end().deprecatedNode()->renderer() && selection.end().deprecatedNode()->renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY))
m_matchStyle = false;
- if (m_matchStyle)
- m_insertionStyle = editingStyleIncludingTypingStyle(selection.start());
+ if (m_matchStyle) {
+ m_insertionStyle = EditingStyle::create(selection.start());
+ m_insertionStyle->mergeTypingStyle(document());
+ }
VisiblePosition visibleStart = selection.visibleStart();
VisiblePosition visibleEnd = selection.visibleEnd();
@@ -808,10 +808,10 @@ void ReplaceSelectionCommand::doApply()
bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);
bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart);
- Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().node());
+ Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().deprecatedNode());
Position insertionPos = selection.start();
- bool startIsInsideMailBlockquote = nearestMailBlockquote(insertionPos.node());
+ bool startIsInsideMailBlockquote = nearestMailBlockquote(insertionPos.deprecatedNode());
if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !startIsInsideMailBlockquote) ||
startBlock == currentRoot || isListItem(startBlock) || selectionIsPlainText)
@@ -864,7 +864,7 @@ void ReplaceSelectionCommand::doApply()
if (startIsInsideMailBlockquote && m_preventNesting && !(enclosingNodeOfType(insertionPos, &isTableStructureNode))) {
applyCommandToComposite(BreakBlockquoteCommand::create(document()));
// This will leave a br between the split.
- Node* br = endingSelection().start().node();
+ Node* br = endingSelection().start().deprecatedNode();
ASSERT(br->hasTagName(brTag));
// Insert content between the two blockquotes, but remove the br (since it was just a placeholder).
insertionPos = positionInParentBeforeNode(br);
@@ -875,18 +875,18 @@ void ReplaceSelectionCommand::doApply()
prepareWhitespaceAtPositionForSplit(insertionPos);
// If the downstream node has been removed there's no point in continuing.
- if (!insertionPos.downstream().node())
+ if (!insertionPos.downstream().deprecatedNode())
return;
// NOTE: This would be an incorrect usage of downstream() if downstream() were changed to mean the last position after
// p that maps to the same visible position as p (since in the case where a br is at the end of a block and collapsed
// away, there are positions after the br which map to the same visible position as [br, 0]).
- Node* endBR = insertionPos.downstream().node()->hasTagName(brTag) ? insertionPos.downstream().node() : 0;
+ Node* endBR = insertionPos.downstream().deprecatedNode()->hasTagName(brTag) ? insertionPos.downstream().deprecatedNode() : 0;
VisiblePosition originalVisPosBeforeEndBR;
if (endBR)
- originalVisPosBeforeEndBR = VisiblePosition(endBR, 0, DOWNSTREAM).previous();
+ originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), DOWNSTREAM).previous();
- startBlock = enclosingBlock(insertionPos.node());
+ startBlock = enclosingBlock(insertionPos.deprecatedNode());
// Adjust insertionPos to prevent nesting.
// If the start was in a Mail blockquote, we will have already handled adjusting insertionPos above.
@@ -941,7 +941,7 @@ void ReplaceSelectionCommand::doApply()
fragment.removeNode(refNode);
- Node* blockStart = enclosingBlock(insertionPos.node());
+ Node* blockStart = enclosingBlock(insertionPos.deprecatedNode());
if ((isListElement(refNode.get()) || (isStyleSpan(refNode.get()) && isListElement(refNode->firstChild())))
&& blockStart->renderer()->isListItem())
refNode = insertAsListItems(refNode, blockStart, insertionPos);
@@ -985,7 +985,7 @@ void ReplaceSelectionCommand::doApply()
// We inserted before the startBlock to prevent nesting, and the content before the startBlock wasn't in its own block and
// didn't have a br after it, so the inserted content ended up in the same paragraph.
- if (startBlock && insertionPos.node() == startBlock->parentNode() && (unsigned)insertionPos.deprecatedEditingOffset() < startBlock->nodeIndex() && !isStartOfParagraph(startOfInsertedContent))
+ if (startBlock && insertionPos.deprecatedNode() == startBlock->parentNode() && (unsigned)insertionPos.deprecatedEditingOffset() < startBlock->nodeIndex() && !isStartOfParagraph(startOfInsertedContent))
insertNodeAt(createBreakElement(document()).get(), startOfInsertedContent.deepEquivalent());
Position lastPositionToSelect;
@@ -1005,7 +1005,7 @@ void ReplaceSelectionCommand::doApply()
// We need to handle the case where we need to merge the end
// but our destination node is inside an inline that is the last in the block.
// We insert a placeholder before the newly inserted content to avoid being merged into the inline.
- Node* destinationNode = destination.deepEquivalent().node();
+ Node* destinationNode = destination.deepEquivalent().deprecatedNode();
if (m_shouldMergeEnd && destinationNode != enclosingInline(destinationNode) && enclosingInline(destinationNode)->nextSibling())
insertNodeBefore(createBreakElement(document()), refNode.get());
@@ -1020,16 +1020,16 @@ void ReplaceSelectionCommand::doApply()
if (startOfParagraph(endOfInsertedContent) == startOfParagraphToMove) {
insertNodeAt(createBreakElement(document()).get(), endOfInsertedContent.deepEquivalent());
// Mutation events (bug 22634) triggered by inserting the <br> might have removed the content we're about to move
- if (!startOfParagraphToMove.deepEquivalent().node()->inDocument())
+ if (!startOfParagraphToMove.deepEquivalent().anchorNode()->inDocument())
return;
}
// FIXME: Maintain positions for the start and end of inserted content instead of keeping nodes. The nodes are
// only ever used to create positions where inserted content starts/ends.
moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);
- m_firstNodeInserted = endingSelection().visibleStart().deepEquivalent().downstream().node();
+ m_firstNodeInserted = endingSelection().visibleStart().deepEquivalent().downstream().deprecatedNode();
if (!m_lastLeafInserted->inDocument())
- m_lastLeafInserted = endingSelection().visibleEnd().deepEquivalent().upstream().node();
+ m_lastLeafInserted = endingSelection().visibleEnd().deepEquivalent().upstream().deprecatedNode();
}
endOfInsertedContent = positionAtEndOfInsertedContent();
@@ -1041,7 +1041,7 @@ void ReplaceSelectionCommand::doApply()
if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedContent) || next.isNull()) {
if (!isStartOfParagraph(endOfInsertedContent)) {
setEndingSelection(endOfInsertedContent);
- Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEquivalent().node());
+ Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEquivalent().deprecatedNode());
if (isListItem(enclosingNode)) {
RefPtr<Node> newListItem = createListItemElement(document());
insertNodeAfter(newListItem, enclosingNode);
@@ -1053,7 +1053,7 @@ void ReplaceSelectionCommand::doApply()
// Select up to the paragraph separator that was added.
lastPositionToSelect = endingSelection().visibleStart().deepEquivalent();
- updateNodesInserted(lastPositionToSelect.node());
+ updateNodesInserted(lastPositionToSelect.deprecatedNode());
}
} else {
// Select up to the beginning of the next paragraph.
@@ -1081,7 +1081,7 @@ void ReplaceSelectionCommand::doApply()
if (needsTrailingSpace) {
RenderObject* renderer = m_lastLeafInserted->renderer();
bool collapseWhiteSpace = !renderer || renderer->style()->collapseWhiteSpace();
- Node* endNode = positionAtEndOfInsertedContent().deepEquivalent().upstream().node();
+ Node* endNode = positionAtEndOfInsertedContent().deepEquivalent().upstream().deprecatedNode();
if (endNode->isTextNode()) {
Text* text = static_cast<Text*>(endNode);
insertTextIntoNode(text, text->length(), collapseWhiteSpace ? nonBreakingSpaceString() : " ");
@@ -1096,7 +1096,7 @@ void ReplaceSelectionCommand::doApply()
if (needsLeadingSpace) {
RenderObject* renderer = m_lastLeafInserted->renderer();
bool collapseWhiteSpace = !renderer || renderer->style()->collapseWhiteSpace();
- Node* startNode = positionAtStartOfInsertedContent().deepEquivalent().downstream().node();
+ Node* startNode = positionAtStartOfInsertedContent().deepEquivalent().downstream().deprecatedNode();
if (startNode->isTextNode()) {
Text* text = static_cast<Text*>(startNode);
insertTextIntoNode(text, 0, collapseWhiteSpace ? nonBreakingSpaceString() : " ");
@@ -1214,9 +1214,9 @@ Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<Node> listElement, N
// list items and insert these nodes between them.
if (isMiddle) {
int textNodeOffset = insertPos.offsetInContainerNode();
- if (insertPos.node()->isTextNode() && textNodeOffset > 0)
- splitTextNode(static_cast<Text*>(insertPos.node()), textNodeOffset);
- splitTreeToNode(insertPos.node(), lastNode, true);
+ if (insertPos.deprecatedNode()->isTextNode() && textNodeOffset > 0)
+ splitTextNode(static_cast<Text*>(insertPos.deprecatedNode()), textNodeOffset);
+ splitTreeToNode(insertPos.deprecatedNode(), lastNode, true);
}
while (RefPtr<Node> listItem = listElement->firstChild()) {
diff --git a/Source/WebCore/editing/ReplaceSelectionCommand.h b/Source/WebCore/editing/ReplaceSelectionCommand.h
index 9fc4a49..3d49af1 100644
--- a/Source/WebCore/editing/ReplaceSelectionCommand.h
+++ b/Source/WebCore/editing/ReplaceSelectionCommand.h
@@ -36,16 +36,23 @@ class ReplacementFragment;
class ReplaceSelectionCommand : public CompositeEditCommand {
public:
- static PassRefPtr<ReplaceSelectionCommand> create(Document* document, PassRefPtr<DocumentFragment> fragment,
- bool selectReplacement = true, bool smartReplace = false, bool matchStyle = false, bool preventNesting = true, bool movingParagraph = false,
- EditAction action = EditActionPaste)
+ enum CommandOption {
+ SelectReplacement = 1 << 0,
+ SmartReplace = 1 << 1,
+ MatchStyle = 1 << 2,
+ PreventNesting = 1 << 3,
+ MovingParagraph = 1 << 4
+ };
+
+ typedef unsigned CommandOptions;
+
+ static PassRefPtr<ReplaceSelectionCommand> create(Document* document, PassRefPtr<DocumentFragment> fragment, CommandOptions options, EditAction action = EditActionPaste)
{
- return adoptRef(new ReplaceSelectionCommand(document, fragment, selectReplacement, smartReplace, matchStyle, preventNesting, movingParagraph, action));
+ return adoptRef(new ReplaceSelectionCommand(document, fragment, options, action));
}
private:
- ReplaceSelectionCommand(Document*, PassRefPtr<DocumentFragment>,
- bool selectReplacement, bool smartReplace, bool matchStyle, bool preventNesting, bool movingParagraph, EditAction);
+ ReplaceSelectionCommand(Document*, PassRefPtr<DocumentFragment>, CommandOptions, EditAction);
virtual void doApply();
virtual EditAction editingAction() const;
diff --git a/Source/WebCore/editing/SelectionController.cpp b/Source/WebCore/editing/SelectionController.cpp
index a574b5a..65f9062 100644
--- a/Source/WebCore/editing/SelectionController.cpp
+++ b/Source/WebCore/editing/SelectionController.cpp
@@ -91,34 +91,53 @@ SelectionController::SelectionController(Frame* frame, bool isDragCaretControlle
void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered, CursorAlignOnScroll align)
{
- setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered, align);
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
+ setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), options, align);
}
void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered)
{
- setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), true, true, userTriggered);
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
+ setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), options);
}
void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered)
{
- setSelection(VisibleSelection(pos, affinity), true, true, userTriggered);
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
+ setSelection(VisibleSelection(pos, affinity), options);
}
void SelectionController::moveTo(const Range *r, EAffinity affinity, bool userTriggered)
{
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
VisibleSelection selection = r ? VisibleSelection(r->startPosition(), r->endPosition(), affinity) : VisibleSelection(Position(), Position(), affinity);
- setSelection(selection, true, true, userTriggered);
+ setSelection(selection, options);
}
void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered)
{
- setSelection(VisibleSelection(base, extent, affinity), true, true, userTriggered);
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
+ setSelection(VisibleSelection(base, extent, affinity), options);
}
-void SelectionController::setSelection(const VisibleSelection& s, bool closeTyping, bool shouldClearTypingStyle, bool userTriggered, CursorAlignOnScroll align, TextGranularity granularity, DirectionalityPolicy directionalityPolicy)
+void SelectionController::setSelection(const VisibleSelection& s, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity, DirectionalityPolicy directionalityPolicy)
{
m_granularity = granularity;
+ bool closeTyping = options & CloseTyping;
+ bool shouldClearTypingStyle = options & ClearTypingStyle;
+ bool userTriggered = options & UserTriggered;
+
setIsDirectional(directionalityPolicy == MakeDirectionalSelection);
if (m_isDragCaretController) {
@@ -134,7 +153,7 @@ void SelectionController::setSelection(const VisibleSelection& s, bool closeTypi
return;
}
- Node* baseNode = s.base().node();
+ Node* baseNode = s.base().deprecatedNode();
Document* document = 0;
if (baseNode)
document = baseNode->document();
@@ -142,10 +161,10 @@ void SelectionController::setSelection(const VisibleSelection& s, bool closeTypi
// <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at SelectionController::setSelection
// if document->frame() == m_frame we can get into an infinite loop
if (document && document->frame() && document->frame() != m_frame && document != m_frame->document()) {
- document->frame()->selection()->setSelection(s, closeTyping, shouldClearTypingStyle, userTriggered);
+ document->frame()->selection()->setSelection(s, options);
return;
}
-
+
if (closeTyping)
TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());
@@ -171,7 +190,7 @@ void SelectionController::setSelection(const VisibleSelection& s, bool closeTypi
m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
selectFrameElementInParentIfFullySelected();
notifyRendererOfSelectionChange(userTriggered);
- m_frame->editor()->respondToChangedSelection(oldSelection, closeTyping);
+ m_frame->editor()->respondToChangedSelection(oldSelection, options);
if (userTriggered) {
ScrollAlignment alignment;
@@ -184,21 +203,22 @@ void SelectionController::setSelection(const VisibleSelection& s, bool closeTypi
}
notifyAccessibilityForSelectionChange();
+ m_frame->document()->enqueueDocumentEvent(Event::create(eventNames().selectionchangeEvent, false, false));
}
static bool removingNodeRemovesPosition(Node* node, const Position& position)
{
- if (!position.node())
+ if (!position.deprecatedNode())
return false;
- if (position.node() == node)
+ if (position.deprecatedNode() == node)
return true;
if (!node->isElementNode())
return false;
Element* element = static_cast<Element*>(node);
- return element->contains(position.node()) || element->contains(position.node()->shadowAncestorNode());
+ return element->contains(position.deprecatedNode()) || element->contains(position.deprecatedNode()->shadowAncestorNode());
}
void SelectionController::nodeWillBeRemoved(Node *node)
@@ -246,14 +266,14 @@ void SelectionController::respondToNodeModification(Node* node, bool baseRemoved
}
if (clearRenderTreeSelection) {
- RefPtr<Document> document = m_selection.start().node()->document();
+ RefPtr<Document> document = m_selection.start().anchorNode()->document();
document->updateStyleIfNeeded();
if (RenderView* view = toRenderView(document->renderer()))
view->clearSelection();
}
if (clearDOMTreeSelection)
- setSelection(VisibleSelection(), false, false);
+ setSelection(VisibleSelection(), 0);
}
enum EndPointType { EndPointIsStart, EndPointIsEnd };
@@ -263,12 +283,16 @@ static bool shouldRemovePositionAfterAdoptingTextReplacement(Position& position,
if (!position.anchorNode() || position.anchorNode() != node || position.anchorType() != Position::PositionIsOffsetInAnchor)
return false;
- if (static_cast<unsigned>(position.offsetInContainerNode()) > offset && static_cast<unsigned>(position.offsetInContainerNode()) < offset + oldLength)
+ ASSERT(position.offsetInContainerNode() >= 0);
+ unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
+ if (positionOffset > offset && positionOffset < offset + oldLength)
return true;
- if ((type == EndPointIsStart && static_cast<unsigned>(position.offsetInContainerNode()) >= offset + oldLength)
- || (type == EndPointIsEnd && static_cast<unsigned>(position.offsetInContainerNode()) > offset + oldLength))
- position.moveToOffset(position.offsetInContainerNode() - oldLength + newLength);
+ // Adjust the offset if the position is after or at the end of the deleted contents (positionOffset >= offset + oldLength)
+ // to avoid having a stale offset except when the position is the end of selection and nothing is deleted, in which case,
+ // adjusting offset results in incorrectly extending the selection until the end of newly inserted contents.
+ if ((positionOffset > offset + oldLength) || (positionOffset == offset + oldLength && (type == EndPointIsStart || oldLength)))
+ position.moveToOffset(positionOffset - oldLength + newLength);
return false;
}
@@ -290,14 +314,18 @@ void SelectionController::textWillBeReplaced(CharacterData* node, unsigned offse
if ((base != m_selection.base() || extent != m_selection.extent() || start != m_selection.start() || end != m_selection.end())
&& !shouldRemoveStart && !shouldRemoveEnd) {
+ VisibleSelection newSelection;
if (!shouldRemoveBase && !shouldRemoveExtent)
- m_selection.setWithoutValidation(base, extent);
+ newSelection.setWithoutValidation(base, extent);
else {
- if (m_selection.isBaseFirst())
- m_selection.setWithoutValidation(m_selection.start(), m_selection.end());
+ if (newSelection.isBaseFirst())
+ newSelection.setWithoutValidation(start, end);
else
- m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
+ newSelection.setWithoutValidation(end, start);
}
+ m_frame->document()->updateLayout();
+ setSelection(newSelection, 0);
+ return;
}
respondToNodeModification(node, shouldRemoveBase, shouldRemoveExtent, shouldRemoveStart, shouldRemoveEnd);
@@ -359,7 +387,7 @@ void SelectionController::willBeModified(EAlteration alter, SelectionDirection d
TextDirection SelectionController::directionOfEnclosingBlock()
{
- Node* enclosingBlockNode = enclosingBlock(m_selection.extent().node());
+ Node* enclosingBlockNode = enclosingBlock(m_selection.extent().deprecatedNode());
if (!enclosingBlockNode)
return LTR;
RenderObject* renderer = enclosingBlockNode->renderer();
@@ -413,11 +441,16 @@ VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granul
else
pos = previousWordPosition(pos);
break;
+ case LineBoundary:
+ if (directionOfEnclosingBlock() == LTR)
+ pos = modifyExtendingForward(granularity);
+ else
+ pos = modifyExtendingBackward(granularity);
+ break;
case SentenceGranularity:
case LineGranularity:
case ParagraphGranularity:
case SentenceBoundary:
- case LineBoundary:
case ParagraphBoundary:
case DocumentBoundary:
// FIXME: implement all of the above?
@@ -425,7 +458,7 @@ VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granul
}
return pos;
}
-
+
VisiblePosition SelectionController::modifyExtendingForward(TextGranularity granularity)
{
VisiblePosition pos(m_selection.extent(), m_selection.affinity());
@@ -566,11 +599,16 @@ VisiblePosition SelectionController::modifyExtendingLeft(TextGranularity granula
else
pos = nextWordPosition(pos);
break;
+ case LineBoundary:
+ if (directionOfEnclosingBlock() == LTR)
+ pos = modifyExtendingBackward(granularity);
+ else
+ pos = modifyExtendingForward(granularity);
+ break;
case SentenceGranularity:
case LineGranularity:
case ParagraphGranularity:
case SentenceBoundary:
- case LineBoundary:
case ParagraphBoundary:
case DocumentBoundary:
pos = modifyExtendingBackward(granularity);
@@ -767,7 +805,8 @@ bool SelectionController::modify(EAlteration alter, SelectionDirection direction
if (!m_frame || !m_frame->editor()->behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity))
setExtent(position, userTriggered);
else {
- if (direction == DirectionForward || direction == DirectionRight)
+ TextDirection textDirection = directionOfEnclosingBlock();
+ if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft))
setEnd(position, userTriggered);
else
setStart(position, userTriggered);
@@ -905,7 +944,7 @@ int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
break;
}
- Frame* frame = pos.node()->document()->frame();
+ Frame* frame = pos.anchorNode()->document()->frame();
if (!frame)
return x;
@@ -945,22 +984,34 @@ void SelectionController::setEnd(const VisiblePosition &pos, bool userTriggered)
void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
{
- setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity()), true, true, userTriggered);
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
+ setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity()), options);
}
void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered)
{
- setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
+ setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity()), options);
}
void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered)
{
- setSelection(VisibleSelection(pos, m_selection.extent(), affinity), true, true, userTriggered);
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
+ setSelection(VisibleSelection(pos, m_selection.extent(), affinity), options);
}
void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered)
{
- setSelection(VisibleSelection(m_selection.base(), pos, affinity), true, true, userTriggered);
+ SetSelectionOptions options = CloseTyping | ClearTypingStyle;
+ if (userTriggered)
+ options |= UserTriggered;
+ setSelection(VisibleSelection(m_selection.base(), pos, affinity), options);
}
void SelectionController::setCaretRectNeedsUpdate(bool flag)
@@ -970,19 +1021,19 @@ void SelectionController::setCaretRectNeedsUpdate(bool flag)
void SelectionController::updateCaretRect()
{
- if (isNone() || !m_selection.start().node()->inDocument() || !m_selection.end().node()->inDocument()) {
+ if (isNone() || !m_selection.start().anchorNode()->inDocument() || !m_selection.end().anchorNode()->inDocument()) {
m_caretRect = IntRect();
return;
}
- m_selection.start().node()->document()->updateStyleIfNeeded();
+ m_selection.start().anchorNode()->document()->updateStyleIfNeeded();
m_caretRect = IntRect();
if (isCaret()) {
VisiblePosition pos(m_selection.start(), m_selection.affinity());
if (pos.isNotNull()) {
- ASSERT(pos.deepEquivalent().node()->renderer());
+ ASSERT(pos.deepEquivalent().deprecatedNode()->renderer());
// First compute a rect local to the renderer at the selection start
RenderObject* renderer;
@@ -1016,7 +1067,7 @@ void SelectionController::updateCaretRect()
RenderObject* SelectionController::caretRenderer() const
{
- Node* node = m_selection.start().node();
+ Node* node = m_selection.start().deprecatedNode();
if (!node)
return 0;
@@ -1123,7 +1174,7 @@ void SelectionController::invalidateCaretRect()
if (!isCaret())
return;
- Document* d = m_selection.start().node()->document();
+ Document* d = m_selection.start().anchorNode()->document();
// recomputeCaretRect will always return false for the drag caret,
// because its m_frame is always 0.
@@ -1205,9 +1256,9 @@ void SelectionController::debugRenderer(RenderObject *r, bool selected) const
int textLength = text.length();
if (selected) {
int offset = 0;
- if (r->node() == m_selection.start().node())
+ if (r->node() == m_selection.start().deprecatedNode())
offset = m_selection.start().deprecatedEditingOffset();
- else if (r->node() == m_selection.end().node())
+ else if (r->node() == m_selection.end().deprecatedNode())
offset = m_selection.end().deprecatedEditingOffset();
int pos;
@@ -1309,7 +1360,7 @@ void SelectionController::selectFrameElementInParentIfFullySelected()
return;
// Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
- Element* ownerElement = m_frame->document()->ownerElement();
+ Element* ownerElement = m_frame->ownerElement();
if (!ownerElement)
return;
ContainerNode* ownerElementParent = ownerElement->parentNode();
@@ -1322,8 +1373,8 @@ void SelectionController::selectFrameElementInParentIfFullySelected()
// Create compute positions before and after the element.
unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
- VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
- VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
+ VisiblePosition beforeOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex, Position::PositionIsOffsetInAnchor)));
+ VisiblePosition afterOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex + 1, Position::PositionIsOffsetInAnchor), VP_UPSTREAM_IF_POSSIBLE));
// Focus on the parent frame, and then select from before this element to after.
VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
@@ -1394,15 +1445,18 @@ bool SelectionController::setSelectedRange(Range* range, EAffinity affinity, boo
return false;
// FIXME: Can we provide extentAffinity?
- VisiblePosition visibleStart(startContainer, startOffset, collapsed ? affinity : DOWNSTREAM);
- VisiblePosition visibleEnd(endContainer, endOffset, SEL_DEFAULT_AFFINITY);
- setSelection(VisibleSelection(visibleStart, visibleEnd), closeTyping);
+ VisiblePosition visibleStart(Position(startContainer, startOffset, Position::PositionIsOffsetInAnchor), collapsed ? affinity : DOWNSTREAM);
+ VisiblePosition visibleEnd(Position(endContainer, endOffset, Position::PositionIsOffsetInAnchor), SEL_DEFAULT_AFFINITY);
+ SetSelectionOptions options = ClearTypingStyle;
+ if (closeTyping)
+ options |= CloseTyping;
+ setSelection(VisibleSelection(visibleStart, visibleEnd), options);
return true;
}
bool SelectionController::isInPasswordField() const
{
- Node* startNode = start().node();
+ Node* startNode = start().deprecatedNode();
if (!startNode)
return false;
@@ -1548,8 +1602,8 @@ void SelectionController::updateAppearance()
// We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
// because we don't yet notify the SelectionController of text removal.
if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
- RenderObject* startRenderer = startPos.node()->renderer();
- RenderObject* endRenderer = endPos.node()->renderer();
+ RenderObject* startRenderer = startPos.deprecatedNode()->renderer();
+ RenderObject* endRenderer = endPos.deprecatedNode()->renderer();
view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
}
}
@@ -1650,7 +1704,7 @@ void SelectionController::paintDragCaret(GraphicsContext* p, int tx, int ty, con
#if ENABLE(TEXT_CARET)
SelectionController* dragCaretController = m_frame->page()->dragCaretController();
ASSERT(dragCaretController->selection().isCaret());
- if (dragCaretController->selection().start().node()->document()->frame() == m_frame)
+ if (dragCaretController->selection().start().anchorNode()->document()->frame() == m_frame)
dragCaretController->paintCaret(p, tx, ty, clipRect);
#else
UNUSED_PARAM(p);
@@ -1724,7 +1778,7 @@ HTMLFormElement* SelectionController::currentForm() const
// Start looking either at the active (first responder) node, or where the selection is.
Node* start = m_frame->document()->focusedNode();
if (!start)
- start = this->start().node();
+ start = this->start().deprecatedNode();
// Try walking up the node tree to find a form element.
Node* node;
@@ -1755,12 +1809,12 @@ void SelectionController::revealSelection(const ScrollAlignment& alignment, bool
}
Position start = this->start();
- ASSERT(start.node());
- if (start.node() && start.node()->renderer()) {
+ ASSERT(start.deprecatedNode());
+ if (start.deprecatedNode() && start.deprecatedNode()->renderer()) {
// FIXME: This code only handles scrolling the startContainer's layer, but
// the selection rect could intersect more than just that.
// See <rdar://problem/4799899>.
- if (RenderLayer* layer = start.node()->renderer()->enclosingLayer()) {
+ if (RenderLayer* layer = start.deprecatedNode()->renderer()->enclosingLayer()) {
layer->scrollRectToVisible(rect, false, alignment, alignment);
updateAppearance();
}
@@ -1774,7 +1828,7 @@ void SelectionController::setSelectionFromNone()
Document* document = m_frame->document();
bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
- if (!isNone() || !(m_frame->isContentEditable() || caretBrowsing))
+ if (!isNone() || !(document->inDesignMode() || caretBrowsing))
return;
Node* node = document->documentElement();
diff --git a/Source/WebCore/editing/SelectionController.h b/Source/WebCore/editing/SelectionController.h
index 3f805d3..d6a9dff 100644
--- a/Source/WebCore/editing/SelectionController.h
+++ b/Source/WebCore/editing/SelectionController.h
@@ -54,6 +54,13 @@ public:
enum EAlteration { AlterationMove, AlterationExtend };
enum CursorAlignOnScroll { AlignCursorOnScrollIfNeeded,
AlignCursorOnScrollAlways };
+ enum SetSelectionOption {
+ CloseTyping = 1 << 0,
+ ClearTypingStyle = 1 << 1,
+ UserTriggered = 1 << 2,
+ SpellCorrectionTriggered = 1 << 3,
+ };
+ typedef unsigned SetSelectionOptions;
SelectionController(Frame* = 0, bool isDragCaretController = false);
@@ -69,8 +76,8 @@ public:
void moveTo(const Position&, const Position&, EAffinity, bool userTriggered = false);
const VisibleSelection& selection() const { return m_selection; }
- void setSelection(const VisibleSelection&, bool closeTyping = true, bool clearTypingStyle = true, bool userTriggered = false, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded, TextGranularity = CharacterGranularity, DirectionalityPolicy = MakeDirectionalSelection);
- void setSelection(const VisibleSelection& selection, TextGranularity granularity, DirectionalityPolicy directionality = MakeDirectionalSelection) { setSelection(selection, true, true, false, AlignCursorOnScrollIfNeeded, granularity, directionality); }
+ void setSelection(const VisibleSelection&, SetSelectionOptions = CloseTyping | ClearTypingStyle, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded, TextGranularity = CharacterGranularity, DirectionalityPolicy = MakeDirectionalSelection);
+ void setSelection(const VisibleSelection& selection, TextGranularity granularity, DirectionalityPolicy directionality = MakeDirectionalSelection) { setSelection(selection, CloseTyping | ClearTypingStyle, AlignCursorOnScrollIfNeeded, granularity, directionality); }
bool setSelectedRange(Range*, EAffinity, bool closeTyping);
void selectAll();
void clear();
diff --git a/Source/WebCore/editing/SetSelectionCommand.cpp b/Source/WebCore/editing/SetSelectionCommand.cpp
new file mode 100644
index 0000000..a96e0ad
--- /dev/null
+++ b/Source/WebCore/editing/SetSelectionCommand.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SetSelectionCommand.h"
+
+#include "Frame.h"
+
+namespace WebCore {
+
+SetSelectionCommand::SetSelectionCommand(const VisibleSelection& selection, SelectionController::SetSelectionOptions options)
+ : SimpleEditCommand(selection.base().anchorNode()->document())
+ , m_options(options)
+ , m_selectionToSet(selection)
+{
+}
+
+void SetSelectionCommand::doApply()
+{
+ SelectionController* selectionController = document()->frame()->selection();
+ ASSERT(selectionController);
+
+ if (selectionController->shouldChangeSelection(m_selectionToSet) && m_selectionToSet.isNonOrphanedCaretOrRange()) {
+ selectionController->setSelection(m_selectionToSet, m_options);
+ setEndingSelection(m_selectionToSet);
+ }
+}
+
+void SetSelectionCommand::doUnapply()
+{
+ SelectionController* selectionController = document()->frame()->selection();
+ ASSERT(selectionController);
+
+ if (selectionController->shouldChangeSelection(startingSelection()) && startingSelection().isNonOrphanedCaretOrRange())
+ selectionController->setSelection(startingSelection(), m_options);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/editing/SetSelectionCommand.h b/Source/WebCore/editing/SetSelectionCommand.h
new file mode 100644
index 0000000..3d6609c
--- /dev/null
+++ b/Source/WebCore/editing/SetSelectionCommand.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SetSelectionCommand_h
+#define SetSelectionCommand_h
+
+#include "EditCommand.h"
+#include "SelectionController.h"
+
+namespace WebCore {
+
+class SetSelectionCommand : public SimpleEditCommand {
+public:
+ static PassRefPtr<SetSelectionCommand> create(const VisibleSelection& selection, SelectionController::SetSelectionOptions options)
+ {
+ return adoptRef(new SetSelectionCommand(selection, options));
+ }
+
+private:
+ SetSelectionCommand(const VisibleSelection&, SelectionController::SetSelectionOptions);
+ virtual void doApply();
+ virtual void doUnapply();
+
+ SelectionController::SetSelectionOptions m_options;
+ VisibleSelection m_selectionToSet;
+};
+
+} // namespace WebCore
+
+#endif // SetSelectionCommand_h
diff --git a/Source/WebCore/editing/SmartReplace.cpp b/Source/WebCore/editing/SmartReplace.cpp
index c5f5240..7b8ca45 100644
--- a/Source/WebCore/editing/SmartReplace.cpp
+++ b/Source/WebCore/editing/SmartReplace.cpp
@@ -29,7 +29,7 @@
#include "config.h"
#include "SmartReplace.h"
-#if !PLATFORM(CF) && !USE(ICU_UNICODE)
+#if !USE(CF) && !USE(ICU_UNICODE)
namespace WebCore {
@@ -40,4 +40,4 @@ bool isCharacterSmartReplaceExempt(UChar32 c, bool isPreviousCharacter)
}
-#endif // !PLATFORM(CF)
+#endif // !USE(CF)
diff --git a/Source/WebCore/editing/SmartReplaceICU.cpp b/Source/WebCore/editing/SmartReplaceICU.cpp
index 9acd350..c3507ad 100644
--- a/Source/WebCore/editing/SmartReplaceICU.cpp
+++ b/Source/WebCore/editing/SmartReplaceICU.cpp
@@ -30,7 +30,7 @@
#include "config.h"
#include "SmartReplace.h"
-#if !PLATFORM(CF) && USE(ICU_UNICODE)
+#if !USE(CF) && USE(ICU_UNICODE)
#include "PlatformString.h"
#include <unicode/uset.h>
#include <wtf/Assertions.h>
@@ -97,4 +97,4 @@ bool isCharacterSmartReplaceExempt(UChar32 c, bool isPreviousCharacter)
}
-#endif // !PLATFORM(CF) && USE(ICU_UNICODE)
+#endif // !USE(CF) && USE(ICU_UNICODE)
diff --git a/Source/WebCore/editing/SpellChecker.cpp b/Source/WebCore/editing/SpellChecker.cpp
index f14a74d..7988e41 100644
--- a/Source/WebCore/editing/SpellChecker.cpp
+++ b/Source/WebCore/editing/SpellChecker.cpp
@@ -37,12 +37,13 @@
#include "Range.h"
#include "RenderObject.h"
#include "Settings.h"
+#include "TextCheckerClient.h"
#include "TextIterator.h"
#include "htmlediting.h"
namespace WebCore {
-SpellChecker::SpellChecker(Frame* frame, EditorClient* client)
+SpellChecker::SpellChecker(Frame* frame, TextCheckerClient* client)
: m_frame(frame)
, m_client(client)
, m_requestSequence(0)
diff --git a/Source/WebCore/editing/SpellChecker.h b/Source/WebCore/editing/SpellChecker.h
index 81bb519..d3940e5 100644
--- a/Source/WebCore/editing/SpellChecker.h
+++ b/Source/WebCore/editing/SpellChecker.h
@@ -31,7 +31,7 @@
namespace WebCore {
-class EditorClient;
+class TextCheckerClient;
class Frame;
class Node;
@@ -57,7 +57,7 @@ private:
class SpellChecker {
WTF_MAKE_NONCOPYABLE(SpellChecker);
public:
- explicit SpellChecker(Frame*, EditorClient*);
+ explicit SpellChecker(Frame*, TextCheckerClient*);
~SpellChecker();
bool isAsynchronousEnabled() const;
@@ -73,7 +73,7 @@ private:
void clearRequest();
Frame* m_frame;
- EditorClient* m_client;
+ TextCheckerClient* m_client;
RefPtr<Node> m_requestNode;
String m_requestText;
diff --git a/Source/WebCore/editing/SpellingCorrectionCommand.cpp b/Source/WebCore/editing/SpellingCorrectionCommand.cpp
new file mode 100644
index 0000000..bad4a99
--- /dev/null
+++ b/Source/WebCore/editing/SpellingCorrectionCommand.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SpellingCorrectionCommand.h"
+
+#include "CorrectionPanelInfo.h"
+#include "DocumentFragment.h"
+#include "Frame.h"
+#include "ReplaceSelectionCommand.h"
+#include "SetSelectionCommand.h"
+#include "TextIterator.h"
+#include "markup.h"
+
+namespace WebCore {
+
+#if SUPPORT_AUTOCORRECTION_PANEL
+// On Mac OS X, we use this command to keep track of user undoing a correction for the first time.
+// This information is needed by spell checking service to update user specific data.
+class SpellingCorrectionRecordUndoCommand : public SimpleEditCommand {
+public:
+ static PassRefPtr<SpellingCorrectionRecordUndoCommand> create(Document* document, const String& corrected, const String& correction)
+ {
+ return adoptRef(new SpellingCorrectionRecordUndoCommand(document, corrected, correction));
+ }
+private:
+ SpellingCorrectionRecordUndoCommand(Document* document, const String& corrected, const String& correction)
+ : SimpleEditCommand(document)
+ , m_corrected(corrected)
+ , m_correction(correction)
+ , m_hasBeenUndone(false)
+ {
+ }
+
+ virtual void doApply()
+ {
+ }
+
+ virtual void doUnapply()
+ {
+ if (!m_hasBeenUndone) {
+ document()->frame()->editor()->unappliedSpellCorrection(startingSelection(), m_corrected, m_correction);
+ m_hasBeenUndone = true;
+ }
+
+ }
+
+ String m_corrected;
+ String m_correction;
+ bool m_hasBeenUndone;
+};
+#endif
+
+SpellingCorrectionCommand::SpellingCorrectionCommand(PassRefPtr<Range> rangeToBeCorrected, const String& correction)
+ : CompositeEditCommand(rangeToBeCorrected->startContainer()->document())
+ , m_rangeToBeCorrected(rangeToBeCorrected)
+ , m_selectionToBeCorrected(m_rangeToBeCorrected.get())
+ , m_correction(correction)
+{
+}
+
+void SpellingCorrectionCommand::doApply()
+{
+ m_corrected = plainText(m_rangeToBeCorrected.get());
+ if (!m_corrected.length())
+ return;
+
+ if (!document()->frame()->selection()->shouldChangeSelection(m_selectionToBeCorrected))
+ return;
+
+ RefPtr<DocumentFragment> fragment = createFragmentFromText(m_rangeToBeCorrected.get(), m_correction);
+ if (!fragment)
+ return;
+
+ applyCommandToComposite(SetSelectionCommand::create(m_selectionToBeCorrected, SelectionController::CloseTyping | SelectionController::ClearTypingStyle));
+#if SUPPORT_AUTOCORRECTION_PANEL
+ applyCommandToComposite(SpellingCorrectionRecordUndoCommand::create(document(), m_corrected, m_correction));
+#endif
+ applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting, EditActionPaste));
+}
+
+bool SpellingCorrectionCommand::shouldRetainAutocorrectionIndicator() const
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/editing/SpellingCorrectionCommand.h b/Source/WebCore/editing/SpellingCorrectionCommand.h
new file mode 100644
index 0000000..6136366
--- /dev/null
+++ b/Source/WebCore/editing/SpellingCorrectionCommand.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SpellingCorrectionCommand_h
+#define SpellingCorrectionCommand_h
+
+#include "CompositeEditCommand.h"
+#include "Range.h"
+
+namespace WebCore {
+
+class SpellingCorrectionCommand : public CompositeEditCommand {
+public:
+ static PassRefPtr<SpellingCorrectionCommand> create(PassRefPtr<Range> rangeToBeCorrected, const String& correction)
+ {
+ return adoptRef(new SpellingCorrectionCommand(rangeToBeCorrected, correction));
+ }
+private:
+ SpellingCorrectionCommand(PassRefPtr<Range> rangeToBeCorrected, const String& correction);
+ virtual void doApply();
+ virtual bool shouldRetainAutocorrectionIndicator() const;
+
+ RefPtr<Range> m_rangeToBeCorrected;
+ VisibleSelection m_selectionToBeCorrected;
+ String m_corrected;
+ String m_correction;
+};
+
+} // namespace WebCore
+
+#endif // SpellingCorrectionCommand_h
diff --git a/Source/WebCore/editing/TextCheckingHelper.cpp b/Source/WebCore/editing/TextCheckingHelper.cpp
index b4429a6..e5553fd 100644
--- a/Source/WebCore/editing/TextCheckingHelper.cpp
+++ b/Source/WebCore/editing/TextCheckingHelper.cpp
@@ -29,6 +29,7 @@
#include "DocumentMarkerController.h"
#include "Range.h"
+#include "TextCheckerClient.h"
#include "TextIterator.h"
#include "VisiblePosition.h"
#include "visible_units.h"
@@ -179,7 +180,7 @@ String TextCheckingHelper::findFirstMisspelling(int& firstMisspellingOffset, boo
int misspellingLocation = -1;
int misspellingLength = 0;
- m_client->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);
+ m_client->textChecker()->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);
// 5490627 shows that there was some code path here where the String constructor below crashes.
// We don't know exactly what combination of bad input caused this, so we're making this much
@@ -274,7 +275,7 @@ String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b
Vector<TextCheckingResult> results;
uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
- m_client->checkTextOfParagraph(paragraphString.characters(), paragraphString.length(), checkingTypes, results);
+ m_client->textChecker()->checkTextOfParagraph(paragraphString.characters(), paragraphString.length(), checkingTypes, results);
for (unsigned i = 0; i < results.size(); i++) {
const TextCheckingResult* result = &results[i];
@@ -422,7 +423,7 @@ String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail,
Vector<GrammarDetail> grammarDetails;
int badGrammarPhraseLocation = -1;
int badGrammarPhraseLength = 0;
- m_client->checkGrammarOfString(paragraph.textCharacters() + startOffset, paragraph.textLength() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
+ m_client->textChecker()->checkGrammarOfString(paragraph.textCharacters() + startOffset, paragraph.textLength() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
if (!badGrammarPhraseLength) {
ASSERT(badGrammarPhraseLocation == -1);
@@ -535,14 +536,14 @@ Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool
Vector<TextCheckingResult> results;
uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
- m_client->checkTextOfParagraph(paragraph.textCharacters(), paragraph.textLength(), checkingTypes, results);
+ m_client->textChecker()->checkTextOfParagraph(paragraph.textCharacters(), paragraph.textLength(), checkingTypes, results);
for (unsigned i = 0; i < results.size(); i++) {
const TextCheckingResult* result = &results[i];
if (result->type == TextCheckingTypeSpelling && paragraph.checkingRangeMatches(result->location, result->length)) {
String misspelledWord = paragraph.checkingSubstring();
ASSERT(misspelledWord.length());
- m_client->getGuessesForWord(misspelledWord, String(), guesses);
+ m_client->textChecker()->getGuessesForWord(misspelledWord, String(), guesses);
m_client->updateSpellingUIWithMisspelledWord(misspelledWord);
misspelled = true;
return guesses;
diff --git a/Source/WebCore/editing/TextIterator.cpp b/Source/WebCore/editing/TextIterator.cpp
index b621dc2..a9546b8 100644
--- a/Source/WebCore/editing/TextIterator.cpp
+++ b/Source/WebCore/editing/TextIterator.cpp
@@ -194,21 +194,6 @@ static Node* nextInPreOrderCrossingShadowBoundaries(Node* rangeEndContainer, int
return 0;
}
-static Node* previousInPostOrderCrossingShadowBoundaries(Node* rangeStartContainer, int rangeStartOffset)
-{
- if (!rangeStartContainer)
- return 0;
- if (rangeStartOffset > 0 && !rangeStartContainer->offsetInCharacters()) {
- if (Node* previous = rangeStartContainer->childNode(rangeStartOffset - 1))
- return previous;
- }
- for (Node* node = rangeStartContainer; node; node = node->parentOrHostNode()) {
- if (Node* previous = node->previousSibling())
- return previous;
- }
- return 0;
-}
-
// --------
static inline bool fullyClipsContents(Node* node)
@@ -290,9 +275,6 @@ TextIterator::TextIterator(const Range* r, TextIteratorBehavior behavior)
, m_handledFirstLetter(false)
, m_ignoresStyleVisibility(behavior & TextIteratorIgnoresStyleVisibility)
{
- // FIXME: should support TextIteratorEndsAtEditingBoundary http://webkit.org/b/43609
- ASSERT(behavior != TextIteratorEndsAtEditingBoundary);
-
if (!r)
return;
@@ -878,8 +860,8 @@ bool TextIterator::shouldRepresentNodeOffsetZero()
// and in that case we'll get null. We don't want to put in newlines at the start in that case.
// The currPos.isNotNull() check is needed because positions in non-HTML content
// (like SVG) do not have visible positions, and we don't want to emit for them either.
- VisiblePosition startPos = VisiblePosition(m_startContainer, m_startOffset, DOWNSTREAM);
- VisiblePosition currPos = VisiblePosition(m_node, 0, DOWNSTREAM);
+ VisiblePosition startPos = VisiblePosition(Position(m_startContainer, m_startOffset, Position::PositionIsOffsetInAnchor), DOWNSTREAM);
+ VisiblePosition currPos = VisiblePosition(positionBeforeNode(m_node), DOWNSTREAM);
return startPos.isNotNull() && currPos.isNotNull() && !inSameLine(startPos, currPos);
}
@@ -1052,7 +1034,7 @@ SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range* r,
, m_node(0)
, m_positionNode(0)
{
- ASSERT(m_behavior == TextIteratorDefaultBehavior || m_behavior == TextIteratorEndsAtEditingBoundary);
+ ASSERT(m_behavior == TextIteratorDefaultBehavior);
if (!r)
return;
@@ -1077,7 +1059,7 @@ SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range* r,
}
}
- setCurrentNode(endNode);
+ m_node = endNode;
setUpFullyClippedStack(m_fullyClippedStack, m_node);
m_offset = endOffset;
m_handledNode = false;
@@ -1096,7 +1078,7 @@ SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range* r,
m_lastTextNode = 0;
m_lastCharacter = '\n';
- m_pastStartNode = previousInPostOrderCrossingShadowBoundaries(startNode, startOffset);
+ m_havePassedStartNode = false;
advance();
}
@@ -1108,7 +1090,7 @@ void SimplifiedBackwardsTextIterator::advance()
m_positionNode = 0;
m_textLength = 0;
- while (m_node && m_node != m_pastStartNode) {
+ while (m_node && !m_havePassedStartNode) {
// Don't handle node if we start iterating at [node, 0].
if (!m_handledNode && !(m_node == m_endNode && m_endOffset == 0)) {
RenderObject* renderer = m_node->renderer();
@@ -1125,8 +1107,10 @@ void SimplifiedBackwardsTextIterator::advance()
return;
}
- Node* next = m_handledChildren ? 0 : m_node->lastChild();
- if (!next) {
+ if (!m_handledChildren && m_node->hasChildNodes()) {
+ m_node = m_node->lastChild();
+ pushFullyClippedState(m_fullyClippedStack, m_node);
+ } else {
// Exit empty containers as we pass over them or containers
// where [container, 0] is where we started iterating.
if (!m_handledNode
@@ -1138,11 +1122,12 @@ void SimplifiedBackwardsTextIterator::advance()
m_handledNode = true;
m_handledChildren = true;
return;
- }
+ }
}
+
// Exit all other containers.
while (!m_node->previousSibling()) {
- if (!setCurrentNode(m_node->parentOrHostNode()))
+ if (!advanceRespectingRange(m_node->parentOrHostNode()))
break;
m_fullyClippedStack.pop();
exitNode();
@@ -1153,14 +1138,12 @@ void SimplifiedBackwardsTextIterator::advance()
}
}
- next = m_node->previousSibling();
m_fullyClippedStack.pop();
+ if (advanceRespectingRange(m_node->previousSibling()))
+ pushFullyClippedState(m_fullyClippedStack, m_node);
+ else
+ m_node = 0;
}
-
- if (m_node && setCurrentNode(next))
- pushFullyClippedState(m_fullyClippedStack, m_node);
- else
- clearCurrentNode();
// For the purpose of word boundary detection,
// we should iterate all visible text and trailing (collapsed) whitespaces.
@@ -1240,26 +1223,17 @@ void SimplifiedBackwardsTextIterator::emitCharacter(UChar c, Node* node, int sta
m_lastCharacter = c;
}
-bool SimplifiedBackwardsTextIterator::crossesEditingBoundary(Node* node) const
+bool SimplifiedBackwardsTextIterator::advanceRespectingRange(Node* next)
{
- return m_node && m_node->isContentEditable() != node->isContentEditable();
-}
-
-bool SimplifiedBackwardsTextIterator::setCurrentNode(Node* node)
-{
- if (!node)
+ if (!next)
return false;
- if (m_behavior == TextIteratorEndsAtEditingBoundary && crossesEditingBoundary(node))
+ m_havePassedStartNode |= m_node == m_startNode;
+ if (m_havePassedStartNode)
return false;
- m_node = node;
+ m_node = next;
return true;
}
-void SimplifiedBackwardsTextIterator::clearCurrentNode()
-{
- m_node = 0;
-}
-
PassRefPtr<Range> SimplifiedBackwardsTextIterator::range() const
{
if (m_positionNode)
@@ -2346,7 +2320,7 @@ PassRefPtr<Range> TextIterator::rangeFromLocationAndLength(Element* scope, int r
Position runEnd = VisiblePosition(runStart).next().deepEquivalent();
if (runEnd.isNotNull()) {
ExceptionCode ec = 0;
- textRunRange->setEnd(runEnd.node(), runEnd.deprecatedEditingOffset(), ec);
+ textRunRange->setEnd(runEnd.deprecatedNode(), runEnd.deprecatedEditingOffset(), ec);
ASSERT(!ec);
}
}
diff --git a/Source/WebCore/editing/TextIterator.h b/Source/WebCore/editing/TextIterator.h
index 8b61afe..b0c310a 100644
--- a/Source/WebCore/editing/TextIterator.h
+++ b/Source/WebCore/editing/TextIterator.h
@@ -41,8 +41,7 @@ enum TextIteratorBehavior {
TextIteratorEmitsCharactersBetweenAllVisiblePositions = 1 << 0,
TextIteratorEntersTextControls = 1 << 1,
TextIteratorEmitsTextsWithoutTranscoding = 1 << 2,
- TextIteratorEndsAtEditingBoundary = 1 << 3,
- TextIteratorIgnoresStyleVisibility = 1 << 4
+ TextIteratorIgnoresStyleVisibility = 1 << 3
};
// FIXME: Can't really answer this question correctly without knowing the white-space mode.
@@ -205,9 +204,7 @@ private:
bool handleReplacedElement();
bool handleNonTextNode();
void emitCharacter(UChar, Node*, int startOffset, int endOffset);
- bool crossesEditingBoundary(Node*) const;
- bool setCurrentNode(Node*);
- void clearCurrentNode();
+ bool advanceRespectingRange(Node*);
TextIteratorBehavior m_behavior;
// Current position, not necessarily of the text being returned, but position
@@ -238,9 +235,9 @@ private:
// Used for whitespace characters that aren't in the DOM, so we can point at them.
UChar m_singleCharacterBuffer;
-
- // The node after the last node this iterator should process.
- Node* m_pastStartNode;
+
+ // Whether m_node has advanced beyond the iteration range (i.e. m_startNode).
+ bool m_havePassedStartNode;
};
// Builds on the text iterator, adding a character position so we can walk one
diff --git a/Source/WebCore/editing/TypingCommand.cpp b/Source/WebCore/editing/TypingCommand.cpp
index 9723c2d..3b42915 100644
--- a/Source/WebCore/editing/TypingCommand.cpp
+++ b/Source/WebCore/editing/TypingCommand.cpp
@@ -47,18 +47,18 @@ namespace WebCore {
using namespace HTMLNames;
-TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, const String &textToInsert, bool selectInsertedText, TextGranularity granularity, TextCompositionType compositionType,
- bool killRing)
- : CompositeEditCommand(document),
- m_commandType(commandType),
- m_textToInsert(textToInsert),
- m_openForMoreTyping(true),
- m_selectInsertedText(selectInsertedText),
- m_smartDelete(false),
- m_granularity(granularity),
- m_compositionType(compositionType),
- m_killRing(killRing),
- m_openedByBackwardDelete(false)
+TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, const String &textToInsert, TypingCommandOptions options, TextGranularity granularity, TextCompositionType compositionType)
+ : CompositeEditCommand(document)
+ , m_commandType(commandType)
+ , m_textToInsert(textToInsert)
+ , m_openForMoreTyping(true)
+ , m_selectInsertedText(options & SelectInsertedText)
+ , m_smartDelete(false)
+ , m_granularity(granularity)
+ , m_compositionType(compositionType)
+ , m_killRing(options & KillRing)
+ , m_openedByBackwardDelete(false)
+ , m_shouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator)
{
updatePreservesTypingStyle(m_commandType);
}
@@ -78,8 +78,8 @@ void TypingCommand::deleteSelection(Document* document, bool smartDelete)
static_cast<TypingCommand*>(lastEditCommand)->deleteSelection(smartDelete);
return;
}
-
- RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteSelection, "", false);
+
+ RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteSelection, "", 0);
typingCommand->setSmartDelete(smartDelete);
typingCommand->apply();
}
@@ -97,8 +97,9 @@ void TypingCommand::deleteKeyPressed(Document *document, bool smartDelete, TextG
static_cast<TypingCommand*>(lastEditCommand)->deleteKeyPressed(granularity, killRing);
return;
}
-
- RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteKey, "", false, granularity, killRing);
+
+ TypingCommandOptions options = killRing ? KillRing : 0;
+ RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteKey, "", options, granularity);
typingCommand->setSmartDelete(smartDelete);
typingCommand->apply();
}
@@ -118,7 +119,8 @@ void TypingCommand::forwardDeleteKeyPressed(Document *document, bool smartDelete
return;
}
- RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, ForwardDeleteKey, "", false, granularity, killRing);
+ TypingCommandOptions options = killRing ? KillRing : 0;
+ RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, ForwardDeleteKey, "", options, granularity);
typingCommand->setSmartDelete(smartDelete);
typingCommand->apply();
}
@@ -129,30 +131,29 @@ void TypingCommand::updateSelectionIfDifferentFromCurrentSelection(TypingCommand
VisibleSelection currentSelection = frame->selection()->selection();
if (currentSelection == typingCommand->endingSelection())
return;
-
+
typingCommand->setStartingSelection(currentSelection);
typingCommand->setEndingSelection(currentSelection);
}
-
-void TypingCommand::insertText(Document* document, const String& text, bool selectInsertedText, TextCompositionType composition)
+void TypingCommand::insertText(Document* document, const String& text, TypingCommandOptions options, TextCompositionType composition)
{
ASSERT(document);
-
+
Frame* frame = document->frame();
ASSERT(frame);
- insertText(document, text, frame->selection()->selection(), selectInsertedText, composition);
-}
-
-// FIXME: We shouldn't need to take selectionForInsertion. It should be identical to SelectionController's current selection.
-void TypingCommand::insertText(Document* document, const String& text, const VisibleSelection& selectionForInsertion, bool selectInsertedText, TextCompositionType compositionType)
-{
#if REMOVE_MARKERS_UPON_EDITING
if (!text.isEmpty())
document->frame()->editor()->removeSpellAndCorrectionMarkersFromWordsToBeEdited(isSpaceOrNewline(text.characters()[0]));
#endif
+ insertText(document, text, frame->selection()->selection(), options, composition);
+}
+
+// FIXME: We shouldn't need to take selectionForInsertion. It should be identical to SelectionController's current selection.
+void TypingCommand::insertText(Document* document, const String& text, const VisibleSelection& selectionForInsertion, TypingCommandOptions options, TextCompositionType compositionType)
+{
ASSERT(document);
RefPtr<Frame> frame = document->frame();
@@ -161,7 +162,7 @@ void TypingCommand::insertText(Document* document, const String& text, const Vis
VisibleSelection currentSelection = frame->selection()->selection();
bool changeSelection = currentSelection != selectionForInsertion;
String newText = text;
- Node* startNode = selectionForInsertion.start().node();
+ Node* startNode = selectionForInsertion.start().deprecatedNode();
if (startNode && startNode->rootEditableElement() && compositionType != TextCompositionUpdate) {
// Send BeforeTextInsertedEvent. The event handler will update text if necessary.
@@ -184,13 +185,14 @@ void TypingCommand::insertText(Document* document, const String& text, const Vis
lastTypingCommand->setStartingSelection(selectionForInsertion);
lastTypingCommand->setEndingSelection(selectionForInsertion);
}
-
+
lastTypingCommand->setCompositionType(compositionType);
- lastTypingCommand->insertText(newText, selectInsertedText);
+ lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
+ lastTypingCommand->insertText(newText, options & SelectInsertedText);
return;
}
- RefPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, selectInsertedText, compositionType);
+ RefPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, options, compositionType);
if (changeSelection) {
cmd->setStartingSelection(selectionForInsertion);
cmd->setEndingSelection(selectionForInsertion);
@@ -202,29 +204,31 @@ void TypingCommand::insertText(Document* document, const String& text, const Vis
}
}
-void TypingCommand::insertLineBreak(Document *document)
+void TypingCommand::insertLineBreak(Document *document, TypingCommandOptions options)
{
ASSERT(document);
-
+
Frame* frame = document->frame();
ASSERT(frame);
-
+
EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand*>(lastEditCommand)->insertLineBreak();
+ TypingCommand* lastTypingCommand = static_cast<TypingCommand*>(lastEditCommand);
+ lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
+ lastTypingCommand->insertLineBreak();
return;
}
- applyCommand(TypingCommand::create(document, InsertLineBreak));
+ applyCommand(TypingCommand::create(document, InsertLineBreak, "", options));
}
void TypingCommand::insertParagraphSeparatorInQuotedContent(Document *document)
{
ASSERT(document);
-
+
Frame* frame = document->frame();
ASSERT(frame);
-
+
EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
if (isOpenForMoreTypingCommand(lastEditCommand)) {
static_cast<TypingCommand*>(lastEditCommand)->insertParagraphSeparatorInQuotedContent();
@@ -234,20 +238,22 @@ void TypingCommand::insertParagraphSeparatorInQuotedContent(Document *document)
applyCommand(TypingCommand::create(document, InsertParagraphSeparatorInQuotedContent));
}
-void TypingCommand::insertParagraphSeparator(Document *document)
+void TypingCommand::insertParagraphSeparator(Document *document, TypingCommandOptions options)
{
ASSERT(document);
-
+
Frame* frame = document->frame();
ASSERT(frame);
-
+
EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand*>(lastEditCommand)->insertParagraphSeparator();
+ TypingCommand* lastTypingCommand = static_cast<TypingCommand*>(lastEditCommand);
+ lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
+ lastTypingCommand->insertParagraphSeparator();
return;
}
- applyCommand(TypingCommand::create(document, InsertParagraphSeparator));
+ applyCommand(TypingCommand::create(document, InsertParagraphSeparator, "", options));
}
bool TypingCommand::isOpenForMoreTypingCommand(const EditCommand* cmd)
@@ -483,7 +489,7 @@ void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool killRing)
VisiblePosition visibleStart(endingSelection().visibleStart());
// If we have a caret selection on an empty cell, we have nothing to do.
- if (isEmptyTableCell(visibleStart.deepEquivalent().node()))
+ if (isEmptyTableCell(visibleStart.deepEquivalent().deprecatedNode()))
return;
// If the caret is at the start of a paragraph after a table, move content into the last table cell.
@@ -495,14 +501,14 @@ void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool killRing)
selection.modify(SelectionController::AlterationExtend, DirectionBackward, granularity);
// If the caret is just after a table, select the table and don't delete anything.
} else if (Node* table = isFirstPositionAfterTable(visibleStart)) {
- setEndingSelection(VisibleSelection(positionAfterNode(table), endingSelection().start(), DOWNSTREAM));
+ setEndingSelection(VisibleSelection(positionBeforeNode(table), endingSelection().start(), DOWNSTREAM));
typingAddedToOpenCommand(DeleteKey);
return;
}
selectionToDelete = selection.selection();
- if (granularity == CharacterGranularity && selectionToDelete.end().node() == selectionToDelete.start().node() && selectionToDelete.end().deprecatedEditingOffset() - selectionToDelete.start().deprecatedEditingOffset() > 1) {
+ if (granularity == CharacterGranularity && selectionToDelete.end().deprecatedNode() == selectionToDelete.start().deprecatedNode() && selectionToDelete.end().deprecatedEditingOffset() - selectionToDelete.start().deprecatedEditingOffset() > 1) {
// If there are multiple Unicode code points to be deleted, adjust the range to match platform conventions.
selectionToDelete.setWithoutValidation(selectionToDelete.end(), selectionToDelete.end().previous(BackwardDeletion));
}
@@ -570,8 +576,8 @@ void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool ki
if (visibleEnd == endOfParagraph(visibleEnd))
downstreamEnd = visibleEnd.next(true).deepEquivalent().downstream();
// When deleting tables: Select the table first, then perform the deletion
- if (downstreamEnd.node() && downstreamEnd.node()->renderer() && downstreamEnd.node()->renderer()->isTable() && !downstreamEnd.deprecatedEditingOffset()) {
- setEndingSelection(VisibleSelection(endingSelection().end(), lastDeepEditingPositionForNode(downstreamEnd.node()), DOWNSTREAM));
+ if (downstreamEnd.deprecatedNode() && downstreamEnd.deprecatedNode()->renderer() && downstreamEnd.deprecatedNode()->renderer()->isTable() && !downstreamEnd.deprecatedEditingOffset()) {
+ setEndingSelection(VisibleSelection(endingSelection().end(), lastDeepEditingPositionForNode(downstreamEnd.deprecatedNode()), DOWNSTREAM));
typingAddedToOpenCommand(ForwardDeleteKey);
return;
}
@@ -588,15 +594,15 @@ void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool ki
// We can't let the VisibleSelection class's validation kick in or it'll adjust for us based on
// the current state of the document and we'll get the wrong result.
Position extent = startingSelection().end();
- if (extent.node() != selectionToDelete.end().node())
+ if (extent.deprecatedNode() != selectionToDelete.end().deprecatedNode())
extent = selectionToDelete.extent();
else {
int extraCharacters;
- if (selectionToDelete.start().node() == selectionToDelete.end().node())
+ if (selectionToDelete.start().deprecatedNode() == selectionToDelete.end().deprecatedNode())
extraCharacters = selectionToDelete.end().deprecatedEditingOffset() - selectionToDelete.start().deprecatedEditingOffset();
else
extraCharacters = selectionToDelete.end().deprecatedEditingOffset();
- extent = Position(extent.node(), extent.deprecatedEditingOffset() + extraCharacters, Position::PositionIsOffsetInAnchor);
+ extent = Position(extent.deprecatedNode(), extent.deprecatedEditingOffset() + extraCharacters, Position::PositionIsOffsetInAnchor);
}
selectionAfterUndo.setWithoutValidation(startingSelection().start(), extent);
}
diff --git a/Source/WebCore/editing/TypingCommand.h b/Source/WebCore/editing/TypingCommand.h
index b34bdc1..beb4d02 100644
--- a/Source/WebCore/editing/TypingCommand.h
+++ b/Source/WebCore/editing/TypingCommand.h
@@ -48,13 +48,20 @@ public:
TextCompositionConfirm
};
+ enum TypingCommandOption {
+ SelectInsertedText = 1 << 0,
+ KillRing = 1 << 1,
+ RetainAutocorrectionIndicator = 1 << 2
+ };
+ typedef unsigned TypingCommandOptions;
+
static void deleteSelection(Document*, bool smartDelete = false);
static void deleteKeyPressed(Document*, bool smartDelete = false, TextGranularity = CharacterGranularity, bool killRing = false);
static void forwardDeleteKeyPressed(Document*, bool smartDelete = false, TextGranularity = CharacterGranularity, bool killRing = false);
- static void insertText(Document*, const String&, bool selectInsertedText = false, TextCompositionType = TextCompositionNone);
- static void insertText(Document*, const String&, const VisibleSelection&, bool selectInsertedText = false, TextCompositionType = TextCompositionNone);
- static void insertLineBreak(Document*);
- static void insertParagraphSeparator(Document*);
+ static void insertText(Document*, const String&, TypingCommandOptions, TextCompositionType = TextCompositionNone);
+ static void insertText(Document*, const String&, const VisibleSelection&, TypingCommandOptions, TextCompositionType = TextCompositionNone);
+ static void insertLineBreak(Document*, TypingCommandOptions);
+ static void insertParagraphSeparator(Document*, TypingCommandOptions);
static void insertParagraphSeparatorInQuotedContent(Document*);
static bool isOpenForMoreTypingCommand(const EditCommand*);
static void closeTyping(EditCommand*);
@@ -73,17 +80,17 @@ public:
void setCompositionType(TextCompositionType type) { m_compositionType = type; }
private:
- static PassRefPtr<TypingCommand> create(Document* document, ETypingCommand command, const String& text = "", bool selectInsertedText = false, TextGranularity granularity = CharacterGranularity, bool killRing = false)
+ static PassRefPtr<TypingCommand> create(Document* document, ETypingCommand command, const String& text = "", TypingCommandOptions options = 0, TextGranularity granularity = CharacterGranularity)
{
- return adoptRef(new TypingCommand(document, command, text, selectInsertedText, granularity, TextCompositionNone, killRing));
+ return adoptRef(new TypingCommand(document, command, text, options, granularity, TextCompositionNone));
}
- static PassRefPtr<TypingCommand> create(Document* document, ETypingCommand command, const String& text, bool selectInsertedText, TextCompositionType compositionType)
+ static PassRefPtr<TypingCommand> create(Document* document, ETypingCommand command, const String& text, TypingCommandOptions options, TextCompositionType compositionType)
{
- return adoptRef(new TypingCommand(document, command, text, selectInsertedText, CharacterGranularity, compositionType, false));
+ return adoptRef(new TypingCommand(document, command, text, options, CharacterGranularity, compositionType));
}
- TypingCommand(Document*, ETypingCommand, const String& text, bool selectInsertedText, TextGranularity, TextCompositionType, bool killRing);
+ TypingCommand(Document*, ETypingCommand, const String& text, TypingCommandOptions, TextGranularity, TextCompositionType);
bool smartDelete() const { return m_smartDelete; }
void setSmartDelete(bool smartDelete) { m_smartDelete = smartDelete; }
@@ -92,6 +99,8 @@ private:
virtual EditAction editingAction() const;
virtual bool isTypingCommand() const;
virtual bool preservesTypingStyle() const { return m_preservesTypingStyle; }
+ virtual bool shouldRetainAutocorrectionIndicator() const { return m_shouldRetainAutocorrectionIndicator; }
+ virtual void setShouldRetainAutocorrectionIndicator(bool retain) { m_shouldRetainAutocorrectionIndicator = retain; }
static void updateSelectionIfDifferentFromCurrentSelection(TypingCommand*, Frame*);
@@ -114,6 +123,8 @@ private:
// characters that were deleted, but only if the typing command being undone
// was opened with a backward delete.
bool m_openedByBackwardDelete;
+
+ bool m_shouldRetainAutocorrectionIndicator;
};
} // namespace WebCore
diff --git a/Source/WebCore/editing/VisiblePosition.cpp b/Source/WebCore/editing/VisiblePosition.cpp
index 5999fa6..10798ad 100644
--- a/Source/WebCore/editing/VisiblePosition.cpp
+++ b/Source/WebCore/editing/VisiblePosition.cpp
@@ -48,12 +48,6 @@ VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
init(pos, affinity);
}
-VisiblePosition::VisiblePosition(Node *node, int offset, EAffinity affinity)
-{
- ASSERT(offset >= 0);
- init(Position(node, offset), affinity);
-}
-
void VisiblePosition::init(const Position& position, EAffinity affinity)
{
m_affinity = affinity;
@@ -106,7 +100,7 @@ VisiblePosition VisiblePosition::previous(bool stayInEditableContent) const
Position VisiblePosition::leftVisuallyDistinctCandidate() const
{
Position p = m_deepPosition;
- if (!p.node())
+ if (p.isNull())
return Position();
Position downstreamStart = p.downstream();
@@ -242,7 +236,7 @@ VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
Position VisiblePosition::rightVisuallyDistinctCandidate() const
{
Position p = m_deepPosition;
- if (!p.node())
+ if (p.isNull())
return Position();
Position downstreamStart = p.downstream();
@@ -384,7 +378,7 @@ VisiblePosition VisiblePosition::honorEditableBoundaryAtOrBefore(const VisiblePo
Node* highestRoot = highestEditableRoot(deepEquivalent());
// Return empty position if pos is not somewhere inside the editable region containing this position
- if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot))
+ if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
return VisiblePosition();
// Return pos itself if the two are from the very same editable region, or both are non-editable
@@ -410,7 +404,7 @@ VisiblePosition VisiblePosition::honorEditableBoundaryAtOrAfter(const VisiblePos
Node* highestRoot = highestEditableRoot(deepEquivalent());
// Return empty position if pos is not somewhere inside the editable region containing this position
- if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot))
+ if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
return VisiblePosition();
// Return pos itself if the two are from the very same editable region, or both are non-editable
@@ -451,12 +445,13 @@ Position VisiblePosition::canonicalPosition(const Position& passedPosition)
// To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
// the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
// unless the affinity is upstream.
- Node* node = position.node();
- if (!node)
+ if (position.isNull())
return Position();
- ASSERT(node->document());
- node->document()->updateLayoutIgnorePendingStylesheets();
+ Node* node = position.containerNode();
+
+ ASSERT(position.document());
+ position.document()->updateLayoutIgnorePendingStylesheets();
Position candidate = position.upstream();
if (candidate.isCandidate())
@@ -469,19 +464,19 @@ Position VisiblePosition::canonicalPosition(const Position& passedPosition)
// blocks or enter new ones), we search forward and backward until we find one.
Position next = canonicalizeCandidate(nextCandidate(position));
Position prev = canonicalizeCandidate(previousCandidate(position));
- Node* nextNode = next.node();
- Node* prevNode = prev.node();
+ Node* nextNode = next.deprecatedNode();
+ Node* prevNode = prev.deprecatedNode();
// The new position must be in the same editable element. Enforce that first.
// Unless the descent is from a non-editable html element to an editable body.
- if (node->hasTagName(htmlTag) && !node->isContentEditable() && node->document()->body() && node->document()->body()->isContentEditable())
+ if (node && node->hasTagName(htmlTag) && !node->isContentEditable() && node->document()->body() && node->document()->body()->isContentEditable())
return next.isNotNull() ? next : prev;
Node* editingRoot = editableRootForPosition(position);
// If the html element is editable, descending into its body will look like a descent
// from non-editable to editable content since rootEditableElement() always stops at the body.
- if ((editingRoot && editingRoot->hasTagName(htmlTag)) || position.node()->isDocumentNode())
+ if ((editingRoot && editingRoot->hasTagName(htmlTag)) || position.deprecatedNode()->isDocumentNode())
return next.isNotNull() ? next : prev;
bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
@@ -496,7 +491,7 @@ Position VisiblePosition::canonicalPosition(const Position& passedPosition)
return Position();
// The new position should be in the same block flow element. Favor that.
- Node *originalBlock = node->enclosingBlockFlowElement();
+ Node* originalBlock = node ? node->enclosingBlockFlowElement() : 0;
bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
@@ -510,11 +505,12 @@ UChar32 VisiblePosition::characterAfter() const
// 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.node();
- if (!node || !node->isTextNode())
+ Node* node = pos.containerNode();
+ if (!node || !node->isTextNode() || pos.anchorType() == Position::PositionIsAfterAnchor)
return 0;
- Text* textNode = static_cast<Text*>(pos.node());
- unsigned offset = pos.deprecatedEditingOffset();
+ ASSERT(pos.anchorType() == Position::PositionIsBeforeAnchor || pos.anchorType() == Position::PositionIsOffsetInAnchor);
+ Text* textNode = static_cast<Text*>(pos.containerNode());
+ unsigned offset = pos.anchorType() == Position::PositionIsOffsetInAnchor ? pos.offsetInContainerNode() : 0;
unsigned length = textNode->length();
if (offset >= length)
return 0;
@@ -527,11 +523,11 @@ UChar32 VisiblePosition::characterAfter() const
IntRect VisiblePosition::localCaretRect(RenderObject*& renderer) const
{
- Node* node = m_deepPosition.node();
- if (!node) {
+ if (m_deepPosition.isNull()) {
renderer = 0;
return IntRect();
}
+ Node* node = m_deepPosition.anchorNode();
renderer = node->renderer();
if (!renderer)
@@ -570,16 +566,18 @@ int VisiblePosition::xOffsetForVerticalNavigation() const
return renderer->localToAbsolute(localRect.location()).x();
}
+#ifndef NDEBUG
+
void VisiblePosition::debugPosition(const char* msg) const
{
if (isNull())
fprintf(stderr, "Position [%s]: null\n", msg);
- else
- fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, m_deepPosition.node()->nodeName().utf8().data(), m_deepPosition.node(), m_deepPosition.deprecatedEditingOffset());
+ else {
+ fprintf(stderr, "Position [%s]: %s, ", msg, m_deepPosition.deprecatedNode()->nodeName().utf8().data());
+ m_deepPosition.showAnchorTypeAndOffset();
+ }
}
-#ifndef NDEBUG
-
void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
{
m_deepPosition.formatForDebugger(buffer, length);
@@ -599,19 +597,19 @@ PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition
Position s = start.deepEquivalent().parentAnchoredEquivalent();
Position e = end.deepEquivalent().parentAnchoredEquivalent();
- return Range::create(s.node()->document(), s.node(), s.deprecatedEditingOffset(), e.node(), e.deprecatedEditingOffset());
+ return Range::create(s.containerNode()->document(), s.containerNode(), s.offsetInContainerNode(), e.containerNode(), e.offsetInContainerNode());
}
VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
{
int exception = 0;
- return VisiblePosition(r->startContainer(exception), r->startOffset(exception), affinity);
+ return VisiblePosition(Position(r->startContainer(exception), r->startOffset(exception), Position::PositionIsOffsetInAnchor), affinity);
}
VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
{
int exception = 0;
- return VisiblePosition(r->endContainer(exception), r->endOffset(exception), affinity);
+ return VisiblePosition(Position(r->endContainer(exception), r->endOffset(exception), Position::PositionIsOffsetInAnchor), affinity);
}
bool setStart(Range *r, const VisiblePosition &visiblePosition)
@@ -620,7 +618,7 @@ bool setStart(Range *r, const VisiblePosition &visiblePosition)
return false;
Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
int code = 0;
- r->setStart(p.node(), p.deprecatedEditingOffset(), code);
+ r->setStart(p.containerNode(), p.offsetInContainerNode(), code);
return code == 0;
}
@@ -630,7 +628,7 @@ bool setEnd(Range *r, const VisiblePosition &visiblePosition)
return false;
Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
int code = 0;
- r->setEnd(p.node(), p.deprecatedEditingOffset(), code);
+ r->setEnd(p.containerNode(), p.offsetInContainerNode(), code);
return code == 0;
}
@@ -639,31 +637,31 @@ Element* enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
if (visiblePosition.isNull())
return NULL;
- return visiblePosition.deepEquivalent().node()->enclosingBlockFlowElement();
+ return visiblePosition.deepEquivalent().deprecatedNode()->enclosingBlockFlowElement();
}
bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
{
if (visiblePosition.isNull())
return false;
-
- if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
+
+ if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
return false;
-
+
VisiblePosition previous = visiblePosition.previous();
- return previous.isNull() || !previous.deepEquivalent().node()->isDescendantOf(node);
+ return previous.isNull() || !previous.deepEquivalent().deprecatedNode()->isDescendantOf(node);
}
bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
{
if (visiblePosition.isNull())
return false;
-
- if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
+
+ if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
return false;
-
+
VisiblePosition next = visiblePosition.next();
- return next.isNull() || !next.deepEquivalent().node()->isDescendantOf(node);
+ return next.isNull() || !next.deepEquivalent().deprecatedNode()->isDescendantOf(node);
}
} // namespace WebCore
diff --git a/Source/WebCore/editing/VisiblePosition.h b/Source/WebCore/editing/VisiblePosition.h
index e649b68..008d676 100644
--- a/Source/WebCore/editing/VisiblePosition.h
+++ b/Source/WebCore/editing/VisiblePosition.h
@@ -54,7 +54,6 @@ public:
// NOTE: UPSTREAM affinity will be used only if pos is at end of a wrapped line,
// otherwise it will be converted to DOWNSTREAM
VisiblePosition() : m_affinity(VP_DEFAULT_AFFINITY) { }
- VisiblePosition(Node*, int offset, EAffinity);
VisiblePosition(const Position&, EAffinity = VP_DEFAULT_AFFINITY);
void clear() { m_deepPosition.clear(); }
@@ -80,10 +79,8 @@ public:
UChar32 characterAfter() const;
UChar32 characterBefore() const { return previous().characterAfter(); }
-
- void debugPosition(const char* msg = "") const;
-
- Element* rootEditableElement() const { return m_deepPosition.isNotNull() ? m_deepPosition.node()->rootEditableElement() : 0; }
+
+ Element* rootEditableElement() const { return m_deepPosition.isNotNull() ? m_deepPosition.deprecatedNode()->rootEditableElement() : 0; }
void getInlineBoxAndOffset(InlineBox*& inlineBox, int& caretOffset) const
{
@@ -104,6 +101,7 @@ public:
int xOffsetForVerticalNavigation() const;
#ifndef NDEBUG
+ void debugPosition(const char* msg = "") const;
void formatForDebugger(char* buffer, unsigned length) const;
void showTreeForThis() const;
#endif
diff --git a/Source/WebCore/editing/VisibleSelection.cpp b/Source/WebCore/editing/VisibleSelection.cpp
index 9096dc5..75531ca 100644
--- a/Source/WebCore/editing/VisibleSelection.cpp
+++ b/Source/WebCore/editing/VisibleSelection.cpp
@@ -122,7 +122,7 @@ PassRefPtr<Range> VisibleSelection::firstRange() const
return 0;
Position start = m_start.parentAnchoredEquivalent();
Position end = m_end.parentAnchoredEquivalent();
- return Range::create(start.node()->document(), start, end);
+ return Range::create(start.anchorNode()->document(), start, end);
}
PassRefPtr<Range> VisibleSelection::toNormalizedRange() const
@@ -134,7 +134,7 @@ PassRefPtr<Range> VisibleSelection::toNormalizedRange() const
// in the course of running edit commands which modify the DOM.
// Failing to call this can result in equivalentXXXPosition calls returning
// incorrect results.
- m_start.node()->document()->updateLayout();
+ m_start.anchorNode()->document()->updateLayout();
// Check again, because updating layout can clear the selection.
if (isNone())
@@ -178,7 +178,7 @@ PassRefPtr<Range> VisibleSelection::toNormalizedRange() const
// VisibleSelections are supposed to always be valid. This constructor will ASSERT
// if a valid range could not be created, which is fine for this callsite.
- return Range::create(s.node()->document(), s, e);
+ return Range::create(s.anchorNode()->document(), s, e);
}
bool VisibleSelection::expandUsingGranularity(TextGranularity granularity)
@@ -192,7 +192,7 @@ bool VisibleSelection::expandUsingGranularity(TextGranularity granularity)
static PassRefPtr<Range> makeSearchRange(const Position& pos)
{
- Node* n = pos.node();
+ Node* n = pos.deprecatedNode();
if (!n)
return 0;
Document* d = n->document();
@@ -208,7 +208,7 @@ static PassRefPtr<Range> makeSearchRange(const Position& pos)
Position start(pos.parentAnchoredEquivalent());
searchRange->selectNodeContents(boundary, ec);
- searchRange->setStart(start.node(), start.deprecatedEditingOffset(), ec);
+ searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
ASSERT(!ec);
if (ec)
@@ -296,7 +296,7 @@ void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(Text
VisiblePosition wordEnd(endOfWord(originalEnd, side));
VisiblePosition end(wordEnd);
- if (isEndOfParagraph(originalEnd) && !isEmptyTableCell(m_start.node())) {
+ if (isEndOfParagraph(originalEnd) && !isEmptyTableCell(m_start.deprecatedNode())) {
// Select the paragraph break (the space from the end of a paragraph to the start of
// the next one) to match TextEdit.
end = wordEnd.next();
@@ -457,7 +457,7 @@ void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
Node* startRoot = highestEditableRoot(m_start);
Node* endRoot = highestEditableRoot(m_end);
- Node* baseEditableAncestor = lowestEditableAncestor(m_base.node());
+ Node* baseEditableAncestor = lowestEditableAncestor(m_base.deprecatedNode());
// The base, start and end are all in the same region. No adjustment necessary.
if (baseRoot == startRoot && baseRoot == endRoot)
@@ -492,17 +492,17 @@ void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
// The selection ends in editable content or non-editable content inside a different editable ancestor,
// move backward until non-editable content inside the same lowest editable ancestor is reached.
- Node* endEditableAncestor = lowestEditableAncestor(m_end.node());
+ Node* endEditableAncestor = lowestEditableAncestor(m_end.deprecatedNode());
if (endRoot || endEditableAncestor != baseEditableAncestor) {
Position p = previousVisuallyDistinctCandidate(m_end);
Node* shadowAncestor = endRoot ? endRoot->shadowAncestorNode() : 0;
if (p.isNull() && endRoot && (shadowAncestor != endRoot))
p = lastDeepEditingPositionForNode(shadowAncestor);
- while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
+ while (p.isNotNull() && !(lowestEditableAncestor(p.deprecatedNode()) == baseEditableAncestor && !isEditablePosition(p))) {
Node* root = editableRootForPosition(p);
shadowAncestor = root ? root->shadowAncestorNode() : 0;
- p = isAtomicNode(p.node()) ? positionInParentBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
+ p = isAtomicNode(p.deprecatedNode()) ? positionInParentBeforeNode(p.deprecatedNode()) : previousVisuallyDistinctCandidate(p);
if (p.isNull() && (shadowAncestor != root))
p = lastDeepEditingPositionForNode(shadowAncestor);
}
@@ -522,16 +522,16 @@ void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
// The selection starts in editable content or non-editable content inside a different editable ancestor,
// move forward until non-editable content inside the same lowest editable ancestor is reached.
- Node* startEditableAncestor = lowestEditableAncestor(m_start.node());
+ Node* startEditableAncestor = lowestEditableAncestor(m_start.deprecatedNode());
if (startRoot || startEditableAncestor != baseEditableAncestor) {
Position p = nextVisuallyDistinctCandidate(m_start);
Node* shadowAncestor = startRoot ? startRoot->shadowAncestorNode() : 0;
if (p.isNull() && startRoot && (shadowAncestor != startRoot))
p = positionBeforeNode(shadowAncestor);
- while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
+ while (p.isNotNull() && !(lowestEditableAncestor(p.deprecatedNode()) == baseEditableAncestor && !isEditablePosition(p))) {
Node* root = editableRootForPosition(p);
shadowAncestor = root ? root->shadowAncestorNode() : 0;
- p = isAtomicNode(p.node()) ? positionInParentAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
+ p = isAtomicNode(p.deprecatedNode()) ? positionInParentAfterNode(p.deprecatedNode()) : nextVisuallyDistinctCandidate(p);
if (p.isNull() && (shadowAncestor != root))
p = positionBeforeNode(shadowAncestor);
}
@@ -551,7 +551,7 @@ void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
}
// Correct the extent if necessary.
- if (baseEditableAncestor != lowestEditableAncestor(m_extent.node()))
+ if (baseEditableAncestor != lowestEditableAncestor(m_extent.deprecatedNode()))
m_extent = m_baseIsFirst ? m_end : m_start;
}
@@ -572,33 +572,30 @@ Element* VisibleSelection::rootEditableElement() const
Node* VisibleSelection::shadowTreeRootNode() const
{
- return start().node() ? start().node()->shadowTreeRootNode() : 0;
+ return start().deprecatedNode() ? start().deprecatedNode()->shadowTreeRootNode() : 0;
}
+#ifndef NDEBUG
+
void VisibleSelection::debugPosition() const
{
- if (!m_start.node())
- return;
+ fprintf(stderr, "VisibleSelection ===============\n");
- fprintf(stderr, "VisibleSelection =================\n");
-
- if (m_start == m_end) {
- Position pos = m_start;
- fprintf(stderr, "pos: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.deprecatedEditingOffset());
+ if (!m_start.anchorNode())
+ fputs("pos: null", stderr);
+ else if (m_start == m_end) {
+ fprintf(stderr, "pos: %s ", m_start.anchorNode()->nodeName().utf8().data());
+ m_start.showAnchorTypeAndOffset();
} else {
- Position pos = m_start;
- fprintf(stderr, "start: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.deprecatedEditingOffset());
- fprintf(stderr, "-----------------------------------\n");
- pos = m_end;
- fprintf(stderr, "end: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.deprecatedEditingOffset());
- fprintf(stderr, "-----------------------------------\n");
+ fprintf(stderr, "start: %s ", m_start.anchorNode()->nodeName().utf8().data());
+ m_start.showAnchorTypeAndOffset();
+ fprintf(stderr, "end: %s ", m_end.anchorNode()->nodeName().utf8().data());
+ m_end.showAnchorTypeAndOffset();
}
fprintf(stderr, "================================\n");
}
-#ifndef NDEBUG
-
void VisibleSelection::formatForDebugger(char* buffer, unsigned length) const
{
String result;
@@ -622,9 +619,12 @@ void VisibleSelection::formatForDebugger(char* buffer, unsigned length) const
void VisibleSelection::showTreeForThis() const
{
- if (start().node()) {
- start().node()->showTreeAndMark(start().node(), "S", end().node(), "E");
- fprintf(stderr, "start offset: %d, end offset: %d\n", start().deprecatedEditingOffset(), end().deprecatedEditingOffset());
+ if (start().anchorNode()) {
+ start().anchorNode()->showTreeAndMark(start().anchorNode(), "S", end().anchorNode(), "E");
+ fputs("start: ", stderr);
+ start().showAnchorTypeAndOffset();
+ fputs("end: ", stderr);
+ end().showAnchorTypeAndOffset();
}
}
diff --git a/Source/WebCore/editing/VisibleSelection.h b/Source/WebCore/editing/VisibleSelection.h
index 10b5c8f..5d52a08 100644
--- a/Source/WebCore/editing/VisibleSelection.h
+++ b/Source/WebCore/editing/VisibleSelection.h
@@ -97,10 +97,9 @@ public:
bool isContentEditable() const;
bool isContentRichlyEditable() const;
Node* shadowTreeRootNode() const;
-
- void debugPosition() const;
#ifndef NDEBUG
+ void debugPosition() const;
void formatForDebugger(char* buffer, unsigned length) const;
void showTreeForThis() const;
#endif
diff --git a/Source/WebCore/editing/chromium/EditorChromium.cpp b/Source/WebCore/editing/chromium/EditorChromium.cpp
index ca7f41a..2bfb5af 100644
--- a/Source/WebCore/editing/chromium/EditorChromium.cpp
+++ b/Source/WebCore/editing/chromium/EditorChromium.cpp
@@ -39,7 +39,7 @@ namespace WebCore {
PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, Frame* frame)
{
- return ClipboardChromium::create(Clipboard::CopyAndPaste, policy, frame);
+ return ClipboardChromium::create(Clipboard::CopyAndPaste, ChromiumDataObject::create(Clipboard::CopyAndPaste), policy, frame);
}
} // namespace WebCore
diff --git a/Source/WebCore/editing/chromium/SelectionControllerChromium.cpp b/Source/WebCore/editing/chromium/SelectionControllerChromium.cpp
index d627d9b..f40134b 100644
--- a/Source/WebCore/editing/chromium/SelectionControllerChromium.cpp
+++ b/Source/WebCore/editing/chromium/SelectionControllerChromium.cpp
@@ -41,7 +41,7 @@ void SelectionController::notifyAccessibilityForSelectionChange()
// FIXME: Support editable text in chromium.
if (AXObjectCache::accessibilityEnabled() && m_selection.start().isNotNull() && m_selection.end().isNotNull()) {
Document* document = m_frame->document();
- document->axObjectCache()->postNotification(m_selection.start().node()->renderer(), AXObjectCache::AXSelectedTextChanged, false);
+ document->axObjectCache()->postNotification(m_selection.start().deprecatedNode()->renderer(), AXObjectCache::AXSelectedTextChanged, false);
}
}
diff --git a/Source/WebCore/editing/gtk/SelectionControllerGtk.cpp b/Source/WebCore/editing/gtk/SelectionControllerGtk.cpp
index 19097b2..264bdc3 100644
--- a/Source/WebCore/editing/gtk/SelectionControllerGtk.cpp
+++ b/Source/WebCore/editing/gtk/SelectionControllerGtk.cpp
@@ -84,7 +84,7 @@ void SelectionController::notifyAccessibilityForSelectionChange()
if (!m_selection.start().isNotNull() || !m_selection.end().isNotNull())
return;
- RenderObject* focusedNode = m_selection.end().node()->renderer();
+ RenderObject* focusedNode = m_selection.end().deprecatedNode()->renderer();
AccessibilityObject* accessibilityObject = m_frame->document()->axObjectCache()->getOrCreate(focusedNode);
// Need to check this as getOrCreate could return 0,
diff --git a/Source/WebCore/editing/htmlediting.cpp b/Source/WebCore/editing/htmlediting.cpp
index cb157d2..a078d91 100644
--- a/Source/WebCore/editing/htmlediting.cpp
+++ b/Source/WebCore/editing/htmlediting.cpp
@@ -95,9 +95,9 @@ bool canHaveChildrenForEditing(const Node* node)
// could be inside a shadow tree. Only works for non-null values.
int comparePositions(const Position& a, const Position& b)
{
- Node* nodeA = a.node();
+ Node* nodeA = a.deprecatedNode();
ASSERT(nodeA);
- Node* nodeB = b.node();
+ Node* nodeB = b.deprecatedNode();
ASSERT(nodeB);
int offsetA = a.deprecatedEditingOffset();
int offsetB = b.deprecatedEditingOffset();
@@ -134,7 +134,7 @@ int comparePositions(const VisiblePosition& a, const VisiblePosition& b)
Node* highestEditableRoot(const Position& position)
{
- Node* node = position.node();
+ Node* node = position.deprecatedNode();
if (!node)
return 0;
@@ -173,7 +173,7 @@ Node* lowestEditableAncestor(Node* node)
bool isEditablePosition(const Position& p)
{
- Node* node = p.node();
+ Node* node = p.deprecatedNode();
if (!node)
return false;
@@ -185,14 +185,14 @@ bool isEditablePosition(const Position& p)
bool isAtUnsplittableElement(const Position& pos)
{
- Node* node = pos.node();
+ Node* node = pos.deprecatedNode();
return (node == editableRootForPosition(pos) || node == enclosingNodeOfType(pos, &isTableCell));
}
bool isRichlyEditablePosition(const Position& p)
{
- Node* node = p.node();
+ Node* node = p.deprecatedNode();
if (!node)
return false;
@@ -204,7 +204,7 @@ bool isRichlyEditablePosition(const Position& p)
Element* editableRootForPosition(const Position& p)
{
- Node* node = p.node();
+ Node* node = p.deprecatedNode();
if (!node)
return 0;
@@ -282,14 +282,14 @@ VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& positio
Position p = position;
- if (Node* shadowAncestor = p.node()->shadowAncestorNode())
- if (shadowAncestor != p.node())
+ if (Node* shadowAncestor = p.deprecatedNode()->shadowAncestorNode())
+ if (shadowAncestor != p.deprecatedNode())
p = lastDeepEditingPositionForNode(shadowAncestor);
- while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
- p = isAtomicNode(p.node()) ? positionInParentAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
+ while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot))
+ p = isAtomicNode(p.deprecatedNode()) ? positionInParentAfterNode(p.deprecatedNode()) : nextVisuallyDistinctCandidate(p);
- if (p.node() && p.node() != highestRoot && !p.node()->isDescendantOf(highestRoot))
+ if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecatedNode()->isDescendantOf(highestRoot))
return VisiblePosition();
return VisiblePosition(p);
@@ -303,14 +303,14 @@ VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& positio
Position p = position;
- if (Node* shadowAncestor = p.node()->shadowAncestorNode())
- if (shadowAncestor != p.node())
+ if (Node* shadowAncestor = p.deprecatedNode()->shadowAncestorNode())
+ if (shadowAncestor != p.deprecatedNode())
p = firstDeepEditingPositionForNode(shadowAncestor);
- while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
- p = isAtomicNode(p.node()) ? positionInParentBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
+ while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot))
+ p = isAtomicNode(p.deprecatedNode()) ? positionInParentBeforeNode(p.deprecatedNode()) : previousVisuallyDistinctCandidate(p);
- if (p.node() && p.node() != highestRoot && !p.node()->isDescendantOf(highestRoot))
+ if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecatedNode()->isDescendantOf(highestRoot))
return VisiblePosition();
return VisiblePosition(p);
@@ -421,12 +421,12 @@ bool isSpecialElement(const Node *n)
static Node* firstInSpecialElement(const Position& pos)
{
- // FIXME: This begins at pos.node(), which doesn't necessarily contain pos (suppose pos was [img, 0]). See <rdar://problem/5027702>.
- Node* rootEditableElement = pos.node()->rootEditableElement();
- for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
+ // FIXME: This begins at pos.deprecatedNode(), which doesn't necessarily contain pos (suppose pos was [img, 0]). See <rdar://problem/5027702>.
+ Node* rootEditableElement = pos.deprecatedNode()->rootEditableElement();
+ for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
if (isSpecialElement(n)) {
VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
- VisiblePosition firstInElement = VisiblePosition(n, 0, DOWNSTREAM);
+ VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBeforeNode(n), DOWNSTREAM);
if (isTableElement(n) && vPos == firstInElement.next())
return n;
if (vPos == firstInElement)
@@ -437,12 +437,12 @@ static Node* firstInSpecialElement(const Position& pos)
static Node* lastInSpecialElement(const Position& pos)
{
- // FIXME: This begins at pos.node(), which doesn't necessarily contain pos (suppose pos was [img, 0]). See <rdar://problem/5027702>.
- Node* rootEditableElement = pos.node()->rootEditableElement();
- for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
+ // FIXME: This begins at pos.deprecatedNode(), which doesn't necessarily contain pos (suppose pos was [img, 0]). See <rdar://problem/5027702>.
+ Node* rootEditableElement = pos.deprecatedNode()->rootEditableElement();
+ for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
if (isSpecialElement(n)) {
VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
- VisiblePosition lastInElement = VisiblePosition(n, n->childNodeCount(), DOWNSTREAM);
+ VisiblePosition lastInElement = VisiblePosition(Position(n, n->childNodeCount(), Position::PositionIsOffsetInAnchor), DOWNSTREAM);
if (isTableElement(n) && vPos == lastInElement.previous())
return n;
if (vPos == lastInElement)
@@ -462,7 +462,7 @@ Position positionBeforeContainingSpecialElement(const Position& pos, Node** cont
if (!n)
return pos;
Position result = positionInParentBeforeNode(n);
- if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
+ if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement())
return pos;
if (containingSpecialElement)
*containingSpecialElement = n;
@@ -480,7 +480,7 @@ Position positionAfterContainingSpecialElement(const Position& pos, Node **conta
if (!n)
return pos;
Position result = positionInParentAfterNode(n);
- if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
+ if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement())
return pos;
if (containingSpecialElement)
*containingSpecialElement = n;
@@ -499,8 +499,8 @@ Position positionOutsideContainingSpecialElement(const Position &pos, Node **con
Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
{
Position upstream(visiblePosition.deepEquivalent().upstream());
- if (upstream.node() && upstream.node()->renderer() && upstream.node()->renderer()->isTable() && upstream.atLastEditingPositionForNode())
- return upstream.node();
+ if (upstream.deprecatedNode() && upstream.deprecatedNode()->renderer() && upstream.deprecatedNode()->renderer()->isTable() && upstream.atLastEditingPositionForNode())
+ return upstream.deprecatedNode();
return 0;
}
@@ -508,8 +508,8 @@ Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition)
{
Position downstream(visiblePosition.deepEquivalent().downstream());
- if (downstream.node() && downstream.node()->renderer() && downstream.node()->renderer()->isTable() && downstream.atFirstEditingPositionForNode())
- return downstream.node();
+ if (downstream.deprecatedNode() && downstream.deprecatedNode()->renderer() && downstream.deprecatedNode()->renderer()->isTable() && downstream.atFirstEditingPositionForNode())
+ return downstream.deprecatedNode();
return 0;
}
@@ -519,7 +519,7 @@ VisiblePosition visiblePositionBeforeNode(Node* node)
{
ASSERT(node);
if (node->childNodeCount())
- return VisiblePosition(node, 0, DOWNSTREAM);
+ return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
ASSERT(node->parentNode());
return positionInParentBeforeNode(node);
}
@@ -529,7 +529,7 @@ VisiblePosition visiblePositionAfterNode(Node* node)
{
ASSERT(node);
if (node->childNodeCount())
- return VisiblePosition(node, node->childNodeCount(), DOWNSTREAM);
+ return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM);
ASSERT(node->parentNode());
return positionInParentAfterNode(node);
}
@@ -591,7 +591,7 @@ Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
return 0;
Node* root = highestEditableRoot(p);
- for (Node* n = p.node(); n; n = n->parentNode()) {
+ for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
if (root && !n->isContentEditable())
continue;
if (n->hasTagName(tagName))
@@ -609,7 +609,7 @@ Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*),
return 0;
Node* root = highestEditableRoot(p);
- for (Node* n = p.node(); n; n = n->parentNode()) {
+ for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
// Don't return a non-editable node if the input position was editable, since
// the callers from editing will no doubt want to perform editing inside the returned node.
if (root && !n->isContentEditable() && onlyReturnEditableNodes)
@@ -627,7 +627,7 @@ Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const N
{
Node* highest = 0;
Node* root = highestEditableRoot(p);
- for (Node* n = p.node(); n; n = n->parentNode()) {
+ for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
if ((*nodeIsOfType)(n))
highest = n;
if (n == root)
@@ -647,7 +647,7 @@ Node* enclosingAnchorElement(const Position& p)
if (p.isNull())
return 0;
- Node* node = p.node();
+ Node* node = p.deprecatedNode();
while (node && !(node->isElementNode() && node->isLink()))
node = node->parentNode();
return node;
@@ -717,7 +717,7 @@ static Node* appendedSublist(Node* listItem)
Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
{
// Check that position is on a line by itself inside a list item
- Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().node());
+ Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().deprecatedNode());
if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
return 0;
@@ -883,7 +883,7 @@ bool isNodeInTextFormControl(Node* node)
Position positionBeforeTabSpan(const Position& pos)
{
- Node *node = pos.node();
+ Node* node = pos.deprecatedNode();
if (isTabSpanTextNode(node))
node = tabSpanNode(node);
else if (!isTabSpanNode(node))
@@ -944,7 +944,7 @@ Node *nearestMailBlockquote(const Node *node)
unsigned numEnclosingMailBlockquotes(const Position& p)
{
unsigned num = 0;
- for (Node* n = p.node(); n; n = n->parentNode())
+ for (Node* n = p.deprecatedNode(); n; n = n->parentNode())
if (isMailBlockquote(n))
num++;
@@ -1015,7 +1015,7 @@ VisibleSelection selectionForParagraphIteration(const VisibleSelection& original
// that we'll want modify is the last one inside the table, not the table itself
// (a table is itself a paragraph).
if (Node* table = isFirstPositionAfterTable(endOfSelection))
- if (startOfSelection.deepEquivalent().node()->isDescendantOf(table))
+ if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
newSelection = VisibleSelection(startOfSelection, endOfSelection.previous(true));
// If the start of the selection to modify is just before a table,
@@ -1023,7 +1023,7 @@ VisibleSelection selectionForParagraphIteration(const VisibleSelection& original
// we'll want to modify is the first one inside the table, not the paragraph
// containing the table itself.
if (Node* table = isLastPositionBeforeTable(startOfSelection))
- if (endOfSelection.deepEquivalent().node()->isDescendantOf(table))
+ if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
newSelection = VisibleSelection(startOfSelection.next(true), endOfSelection);
return newSelection;
@@ -1035,7 +1035,7 @@ int indexForVisiblePosition(const VisiblePosition& visiblePosition)
if (visiblePosition.isNull())
return 0;
Position p(visiblePosition.deepEquivalent());
- RefPtr<Range> range = Range::create(p.node()->document(), firstPositionInNode(p.anchorNode()->document()->documentElement()),
+ RefPtr<Range> range = Range::create(p.anchorNode()->document(), firstPositionInNode(p.anchorNode()->document()->documentElement()),
p.parentAnchoredEquivalent());
return TextIterator::rangeLength(range.get(), true);
}
@@ -1114,8 +1114,8 @@ VisibleSelection avoidIntersectionWithNode(const VisibleSelection& selection, No
return VisibleSelection(selection);
VisibleSelection updatedSelection(selection);
- Node* base = selection.base().node();
- Node* extent = selection.extent().node();
+ Node* base = selection.base().deprecatedNode();
+ Node* extent = selection.extent().deprecatedNode();
ASSERT(base);
ASSERT(extent);
diff --git a/Source/WebCore/editing/mac/EditorMac.mm b/Source/WebCore/editing/mac/EditorMac.mm
index 56b9f71..4c617c0 100644
--- a/Source/WebCore/editing/mac/EditorMac.mm
+++ b/Source/WebCore/editing/mac/EditorMac.mm
@@ -158,7 +158,7 @@ NSWritingDirection Editor::baseWritingDirectionForSelectionStart() const
NSWritingDirection result = NSWritingDirectionLeftToRight;
Position pos = m_frame->selection()->selection().visibleStart().deepEquivalent();
- Node* node = pos.node();
+ Node* node = pos.deprecatedNode();
if (!node)
return result;
@@ -208,4 +208,12 @@ void Editor::takeFindStringFromSelection()
[findPasteboard setString:nsSelectedText forType:NSStringPboardType];
}
+void Editor::writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes)
+{
+ RetainPtr<NSMutableArray> types(AdoptNS, [[NSMutableArray alloc] init]);
+ for (size_t i = 0; i < pasteboardTypes.size(); ++i)
+ [types.get() addObject:pasteboardTypes[i]];
+ Pasteboard::writeSelection([NSPasteboard pasteboardWithName:pasteboardName], types.get(), selectedRange().get(), true, m_frame);
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/editing/mac/SelectionControllerMac.mm b/Source/WebCore/editing/mac/SelectionControllerMac.mm
index 119d406..94199c4 100644
--- a/Source/WebCore/editing/mac/SelectionControllerMac.mm
+++ b/Source/WebCore/editing/mac/SelectionControllerMac.mm
@@ -51,7 +51,7 @@ void SelectionController::notifyAccessibilityForSelectionChange()
Document* document = m_frame->document();
if (AXObjectCache::accessibilityEnabled() && m_selection.start().isNotNull() && m_selection.end().isNotNull())
- document->axObjectCache()->postNotification(m_selection.start().node()->renderer(), AXObjectCache::AXSelectedTextChanged, false);
+ document->axObjectCache()->postNotification(m_selection.start().deprecatedNode()->renderer(), AXObjectCache::AXSelectedTextChanged, false);
// if zoom feature is enabled, insertion point changes should update the zoom
if (!UAZoomEnabled() || !m_selection.isCaret())
diff --git a/Source/WebCore/editing/markup.cpp b/Source/WebCore/editing/markup.cpp
index 34c3ec7..9d97b3f 100644
--- a/Source/WebCore/editing/markup.cpp
+++ b/Source/WebCore/editing/markup.cpp
@@ -437,8 +437,8 @@ static bool propertyMissingOrEqualToNone(CSSStyleDeclaration* style, int propert
static bool needInterchangeNewlineAfter(const VisiblePosition& v)
{
VisiblePosition next = v.next();
- Node* upstreamNode = next.deepEquivalent().upstream().node();
- Node* downstreamNode = v.deepEquivalent().downstream().node();
+ Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode();
+ Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode();
// Add an interchange newline if a paragraph break is selected and a br won't already be added to the markup to represent it.
return isEndOfParagraph(v) && isStartOfParagraph(next) && !(upstreamNode->hasTagName(brTag) && upstreamNode == downstreamNode);
}
@@ -571,7 +571,7 @@ String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterc
}
accumulator.appendString(interchangeNewlineString);
- startNode = visibleStart.next().deepEquivalent().node();
+ startNode = visibleStart.next().deepEquivalent().deprecatedNode();
if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0) >= 0) {
if (deleteButton)
@@ -764,7 +764,7 @@ PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String
Node* styleNode = context->firstNode();
if (!styleNode) {
- styleNode = context->startPosition().node();
+ styleNode = context->startPosition().deprecatedNode();
if (!styleNode)
return 0;
}
diff --git a/Source/WebCore/editing/visible_units.cpp b/Source/WebCore/editing/visible_units.cpp
index 391d6e6..0baacf2 100644
--- a/Source/WebCore/editing/visible_units.cpp
+++ b/Source/WebCore/editing/visible_units.cpp
@@ -68,7 +68,7 @@ static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearch
if (requiresContextForWordBoundary(c.characterBefore())) {
RefPtr<Range> forwardsScanRange(d->createRange());
forwardsScanRange->setEndAfter(boundary, ec);
- forwardsScanRange->setStart(end.node(), end.deprecatedEditingOffset(), ec);
+ forwardsScanRange->setStart(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
TextIterator forwardsIterator(forwardsScanRange.get());
while (!forwardsIterator.atEnd()) {
const UChar* characters = forwardsIterator.characters();
@@ -82,16 +82,16 @@ static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearch
}
}
- searchRange->setStart(start.node(), start.deprecatedEditingOffset(), ec);
- searchRange->setEnd(end.node(), end.deprecatedEditingOffset(), ec);
+ searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
+ searchRange->setEnd(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
ASSERT(!ec);
if (ec)
return VisiblePosition();
- SimplifiedBackwardsTextIterator it(searchRange.get(), TextIteratorEndsAtEditingBoundary);
+ SimplifiedBackwardsTextIterator it(searchRange.get());
unsigned next = 0;
- bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
+ bool inTextSecurityMode = start.deprecatedNode() && start.deprecatedNode()->renderer() && start.deprecatedNode()->renderer()->style()->textSecurity() != TSNONE;
bool needMoreContext = false;
while (!it.atEnd()) {
// iterate to get chunks until the searchFunction returns a non-zero value.
@@ -124,7 +124,7 @@ static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearch
return VisiblePosition(Position(node, next), DOWNSTREAM);
// Use the character iterator to translate the next value into a DOM position.
- BackwardsCharacterIterator charIt(searchRange.get(), TextIteratorEndsAtEditingBoundary);
+ BackwardsCharacterIterator charIt(searchRange.get());
charIt.advance(string.size() - suffixLength - next);
return VisiblePosition(charIt.range()->endPosition(), DOWNSTREAM);
}
@@ -146,7 +146,7 @@ static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunc
ExceptionCode ec = 0;
if (requiresContextForWordBoundary(c.characterAfter())) {
RefPtr<Range> backwardsScanRange(d->createRange());
- backwardsScanRange->setEnd(start.node(), start.deprecatedEditingOffset(), ec);
+ backwardsScanRange->setEnd(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
SimplifiedBackwardsTextIterator backwardsIterator(backwardsScanRange.get());
while (!backwardsIterator.atEnd()) {
const UChar* characters = backwardsIterator.characters();
@@ -161,10 +161,10 @@ static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunc
}
searchRange->selectNodeContents(boundary, ec);
- searchRange->setStart(start.node(), start.deprecatedEditingOffset(), ec);
+ searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
unsigned next = 0;
- bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
+ bool inTextSecurityMode = start.deprecatedNode() && start.deprecatedNode()->renderer() && start.deprecatedNode()->renderer()->style()->textSecurity() != TSNONE;
bool needMoreContext = false;
while (!it.atEnd()) {
// Keep asking the iterator for chunks until the search function
@@ -316,7 +316,7 @@ VisiblePosition nextWordPosition(const VisiblePosition &c)
static RootInlineBox *rootBoxForLine(const VisiblePosition &c)
{
Position p = c.deepEquivalent();
- Node *node = p.node();
+ Node* node = p.deprecatedNode();
if (!node)
return 0;
@@ -351,7 +351,7 @@ static VisiblePosition startPositionForLine(const VisiblePosition& c)
// There are VisiblePositions at offset 0 in blocks without
// RootInlineBoxes, like empty editable blocks and bordered blocks.
Position p = c.deepEquivalent();
- if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.deprecatedEditingOffset() == 0)
+ if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
return positionAvoidingFirstPositionInTable(c);
return VisiblePosition();
@@ -377,13 +377,8 @@ static VisiblePosition startPositionForLine(const VisiblePosition& c)
startBox = startBox->nextLeafChild();
}
- int startOffset = 0;
- if (startBox->isInlineTextBox()) {
- InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
- startOffset = startTextBox->start();
- }
-
- VisiblePosition visPos = VisiblePosition(startNode, startOffset, DOWNSTREAM);
+ VisiblePosition visPos = startBox->isInlineTextBox() ? VisiblePosition(Position(startNode, static_cast<InlineTextBox *>(startBox)->start(), Position::PositionIsOffsetInAnchor), DOWNSTREAM)
+ : VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM);
return positionAvoidingFirstPositionInTable(visPos);
}
@@ -404,7 +399,7 @@ static VisiblePosition endPositionForLine(const VisiblePosition& c)
// There are VisiblePositions at offset 0 in blocks without
// RootInlineBoxes, like empty editable blocks and bordered blocks.
Position p = c.deepEquivalent();
- if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.deprecatedEditingOffset() == 0)
+ if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
return c;
return VisiblePosition();
}
@@ -429,17 +424,19 @@ static VisiblePosition endPositionForLine(const VisiblePosition& c)
endBox = endBox->prevLeafChild();
}
- int endOffset = 1;
+ Position pos;
if (endNode->hasTagName(brTag)) {
- endOffset = 0;
+ pos = positionBeforeNode(endNode);
} else if (endBox->isInlineTextBox()) {
InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
- endOffset = endTextBox->start();
+ int endOffset = endTextBox->start();
if (!endTextBox->isLineBreak())
endOffset += endTextBox->len();
- }
+ pos = Position(endNode, endOffset, Position::PositionIsOffsetInAnchor);
+ } else
+ pos = positionAfterNode(endNode);
- return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
+ return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
}
VisiblePosition endOfLine(const VisiblePosition& c)
@@ -501,7 +498,7 @@ static Node* enclosingNodeWithNonInlineRenderer(Node* n)
VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
{
Position p = visiblePosition.deepEquivalent();
- Node *node = p.node();
+ Node* node = p.deprecatedNode();
Node* highestRoot = highestEditableRoot(p);
if (!node)
return VisiblePosition();
@@ -575,7 +572,7 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
// Move to the start of the content in this block, which effectively moves us
// to the start of the line we're on.
Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
- return VisiblePosition(rootElement, 0, DOWNSTREAM);
+ return VisiblePosition(firstPositionInNode(rootElement), DOWNSTREAM);
}
static Node* nextLeafWithSameEditability(Node* node, int offset)
@@ -610,7 +607,7 @@ static Node* nextLeafWithSameEditability(Node* node)
VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
{
Position p = visiblePosition.deepEquivalent();
- Node *node = p.node();
+ Node* node = p.deprecatedNode();
Node* highestRoot = highestEditableRoot(p);
if (!node)
return VisiblePosition();
@@ -680,7 +677,7 @@ VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
// Move to the end of the content in this block, which effectively moves us
// to the end of the line we're on.
Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
- return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
+ return VisiblePosition(lastPositionInNode(rootElement), DOWNSTREAM);
}
// ---------
@@ -740,7 +737,7 @@ VisiblePosition nextSentencePosition(const VisiblePosition &c)
VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
{
Position p = c.deepEquivalent();
- Node *startNode = p.node();
+ Node* startNode = p.deprecatedNode();
if (!startNode)
return VisiblePosition();
@@ -752,6 +749,7 @@ VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossi
Node *node = startNode;
int offset = p.deprecatedEditingOffset();
+ Position::AnchorType type = p.anchorType();
Node *n = startNode;
while (n) {
@@ -772,6 +770,7 @@ VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossi
break;
if (r->isText() && r->caretMaxRenderedOffset() > 0) {
+ type = Position::PositionIsOffsetInAnchor;
if (style->preserveNewline()) {
const UChar* chars = toRenderText(r)->characters();
int i = toRenderText(r)->textLength();
@@ -780,20 +779,23 @@ VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossi
i = max(0, o);
while (--i >= 0)
if (chars[i] == '\n')
- return VisiblePosition(n, i + 1, DOWNSTREAM);
+ return VisiblePosition(Position(n, i + 1, Position::PositionIsOffsetInAnchor), DOWNSTREAM);
}
node = n;
offset = 0;
n = n->traversePreviousNodePostOrder(startBlock);
} else if (editingIgnoresContent(n) || isTableElement(n)) {
node = n;
- offset = 0;
+ type = Position::PositionIsBeforeAnchor;
n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
} else
n = n->traversePreviousNodePostOrder(startBlock);
}
- return VisiblePosition(node, offset, DOWNSTREAM);
+ if (type == Position::PositionIsOffsetInAnchor)
+ return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
+
+ return VisiblePosition(Position(node, type), DOWNSTREAM);
}
VisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossingRule boundaryCrossingRule)
@@ -802,7 +804,7 @@ VisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossing
return VisiblePosition();
Position p = c.deepEquivalent();
- Node* startNode = p.node();
+ Node* startNode = p.deprecatedNode();
if (isRenderedAsNonInlineTableImageOrHR(startNode))
return lastDeepEditingPositionForNode(startNode);
@@ -812,6 +814,7 @@ VisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossing
Node *node = startNode;
int offset = p.deprecatedEditingOffset();
+ Position::AnchorType type = p.anchorType();
Node *n = startNode;
while (n) {
@@ -834,25 +837,29 @@ VisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossing
// FIXME: We avoid returning a position where the renderer can't accept the caret.
if (r->isText() && r->caretMaxRenderedOffset() > 0) {
int length = toRenderText(r)->textLength();
+ type = Position::PositionIsOffsetInAnchor;
if (style->preserveNewline()) {
const UChar* chars = toRenderText(r)->characters();
int o = n == startNode ? offset : 0;
for (int i = o; i < length; ++i)
if (chars[i] == '\n')
- return VisiblePosition(n, i, DOWNSTREAM);
+ return VisiblePosition(Position(n, i, Position::PositionIsOffsetInAnchor), DOWNSTREAM);
}
node = n;
offset = r->caretMaxOffset();
n = n->traverseNextNode(stayInsideBlock);
} else if (editingIgnoresContent(n) || isTableElement(n)) {
node = n;
- offset = lastOffsetForEditing(n);
+ type = Position::PositionIsAfterAnchor;
n = n->traverseNextSibling(stayInsideBlock);
} else
n = n->traverseNextNode(stayInsideBlock);
}
- return VisiblePosition(node, offset, DOWNSTREAM);
+ if (type == Position::PositionIsOffsetInAnchor)
+ return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
+
+ return VisiblePosition(Position(node, type), DOWNSTREAM);
}
VisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition)
@@ -910,7 +917,7 @@ VisiblePosition nextParagraphPosition(const VisiblePosition& p, int x)
VisiblePosition startOfBlock(const VisiblePosition &c)
{
Position p = c.deepEquivalent();
- Node *startNode = p.node();
+ Node* startNode = p.deprecatedNode();
if (!startNode)
return VisiblePosition();
return VisiblePosition(firstPositionInNode(startNode->enclosingBlockFlowElement()), DOWNSTREAM);
@@ -920,13 +927,13 @@ VisiblePosition endOfBlock(const VisiblePosition &c)
{
Position p = c.deepEquivalent();
- Node *startNode = p.node();
+ Node* startNode = p.deprecatedNode();
if (!startNode)
return VisiblePosition();
Node *startBlock = startNode->enclosingBlockFlowElement();
- return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);
+ return VisiblePosition(lastPositionInNode(startBlock), VP_DEFAULT_AFFINITY);
}
bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
@@ -951,12 +958,12 @@ VisiblePosition startOfDocument(const Node* node)
if (!node)
return VisiblePosition();
- return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
+ return VisiblePosition(firstPositionInNode(node->document()->documentElement()), DOWNSTREAM);
}
VisiblePosition startOfDocument(const VisiblePosition &c)
{
- return startOfDocument(c.deepEquivalent().node());
+ return startOfDocument(c.deepEquivalent().deprecatedNode());
}
VisiblePosition endOfDocument(const Node* node)
@@ -965,22 +972,22 @@ VisiblePosition endOfDocument(const Node* node)
return VisiblePosition();
Element* doc = node->document()->documentElement();
- return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
+ return VisiblePosition(lastPositionInNode(doc), DOWNSTREAM);
}
VisiblePosition endOfDocument(const VisiblePosition &c)
{
- return endOfDocument(c.deepEquivalent().node());
+ return endOfDocument(c.deepEquivalent().deprecatedNode());
}
bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
{
Position ap = a.deepEquivalent();
- Node *an = ap.node();
+ Node* an = ap.deprecatedNode();
if (!an)
return false;
Position bp = b.deepEquivalent();
- Node *bn = bp.node();
+ Node* bn = bp.deprecatedNode();
if (an == bn)
return true;
@@ -1108,7 +1115,7 @@ static VisiblePosition logicalStartPositionForLine(const VisiblePosition& c)
// There are VisiblePositions at offset 0 in blocks without
// RootInlineBoxes, like empty editable blocks and bordered blocks.
Position p = c.deepEquivalent();
- if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
+ if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
return positionAvoidingFirstPositionInTable(c);
return VisiblePosition();
@@ -1121,9 +1128,8 @@ static VisiblePosition logicalStartPositionForLine(const VisiblePosition& c)
if (!logicalStartNode)
return VisiblePosition();
- int startOffset = logicalStartBox->caretMinOffset();
-
- VisiblePosition visPos = VisiblePosition(logicalStartNode, startOffset, DOWNSTREAM);
+ VisiblePosition visPos = logicalStartNode->isTextNode() ? VisiblePosition(Position(logicalStartNode, logicalStartBox->caretMinOffset(), Position::PositionIsOffsetInAnchor), DOWNSTREAM)
+ : VisiblePosition(positionBeforeNode(logicalStartNode), DOWNSTREAM);
return positionAvoidingFirstPositionInTable(visPos);
}
@@ -1146,7 +1152,7 @@ static VisiblePosition logicalEndPositionForLine(const VisiblePosition& c)
// There are VisiblePositions at offset 0 in blocks without
// RootInlineBoxes, like empty editable blocks and bordered blocks.
Position p = c.deepEquivalent();
- if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
+ if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
return c;
return VisiblePosition();
}
@@ -1157,17 +1163,19 @@ static VisiblePosition logicalEndPositionForLine(const VisiblePosition& c)
if (!logicalEndNode)
return VisiblePosition();
- int endOffset = 1;
+ Position pos;
if (logicalEndNode->hasTagName(brTag))
- endOffset = 0;
+ pos = positionBeforeNode(logicalEndNode);
else if (logicalEndBox->isInlineTextBox()) {
InlineTextBox* endTextBox = static_cast<InlineTextBox*>(logicalEndBox);
- endOffset = endTextBox->start();
+ int endOffset = endTextBox->start();
if (!endTextBox->isLineBreak())
endOffset += endTextBox->len();
- }
+ pos = Position(logicalEndNode, endOffset, Position::PositionIsOffsetInAnchor);
+ } else
+ pos = positionAfterNode(logicalEndNode);
- return VisiblePosition(logicalEndNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
+ return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
}
bool inSameLogicalLine(const VisiblePosition& a, const VisiblePosition& b)