summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/editing
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-25 19:08:45 +0100
committerSteve Block <steveblock@google.com>2011-06-08 13:51:31 +0100
commit2bde8e466a4451c7319e3a072d118917957d6554 (patch)
tree28f4a1b869a513e565c7760d0e6a06e7cf1fe95a /Source/WebCore/editing
parent6939c99b71d9372d14a0c74a772108052e8c48c8 (diff)
downloadexternal_webkit-2bde8e466a4451c7319e3a072d118917957d6554.zip
external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.gz
external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.bz2
Merge WebKit at r82507: Initial merge by git
Change-Id: I60ce9d780725b58b45e54165733a8ffee23b683e
Diffstat (limited to 'Source/WebCore/editing')
-rw-r--r--Source/WebCore/editing/AppendNodeCommand.cpp8
-rw-r--r--Source/WebCore/editing/AppendNodeCommand.h6
-rw-r--r--Source/WebCore/editing/ApplyBlockElementCommand.cpp6
-rw-r--r--Source/WebCore/editing/ApplyStyleCommand.cpp65
-rw-r--r--Source/WebCore/editing/ApplyStyleCommand.h2
-rw-r--r--Source/WebCore/editing/BreakBlockquoteCommand.cpp14
-rw-r--r--Source/WebCore/editing/CompositeEditCommand.cpp23
-rw-r--r--Source/WebCore/editing/CompositeEditCommand.h5
-rw-r--r--Source/WebCore/editing/DeleteButtonController.cpp10
-rw-r--r--Source/WebCore/editing/DeleteFromTextNodeCommand.cpp4
-rw-r--r--Source/WebCore/editing/DeleteSelectionCommand.cpp24
-rw-r--r--Source/WebCore/editing/EditingStyle.cpp18
-rw-r--r--Source/WebCore/editing/EditingStyle.h1
-rw-r--r--Source/WebCore/editing/Editor.cpp158
-rw-r--r--Source/WebCore/editing/Editor.h13
-rw-r--r--Source/WebCore/editing/EditorCommand.cpp58
-rw-r--r--Source/WebCore/editing/EditorInsertAction.h2
-rw-r--r--Source/WebCore/editing/FormatBlockCommand.cpp9
-rw-r--r--Source/WebCore/editing/IndentOutdentCommand.cpp4
-rw-r--r--Source/WebCore/editing/InsertIntoTextNodeCommand.cpp4
-rw-r--r--Source/WebCore/editing/InsertLineBreakCommand.cpp2
-rw-r--r--Source/WebCore/editing/InsertListCommand.cpp35
-rw-r--r--Source/WebCore/editing/InsertNodeBeforeCommand.cpp6
-rw-r--r--Source/WebCore/editing/JoinTextNodesCommand.cpp4
-rw-r--r--Source/WebCore/editing/MergeIdenticalElementsCommand.cpp4
-rw-r--r--Source/WebCore/editing/RemoveNodeCommand.cpp4
-rw-r--r--Source/WebCore/editing/ReplaceSelectionCommand.cpp80
-rw-r--r--Source/WebCore/editing/SelectionController.cpp79
-rw-r--r--Source/WebCore/editing/SelectionController.h2
-rw-r--r--Source/WebCore/editing/SplitElementCommand.cpp4
-rw-r--r--Source/WebCore/editing/SplitTextNodeCommand.cpp6
-rw-r--r--Source/WebCore/editing/SplitTextNodeContainingElementCommand.cpp2
-rw-r--r--Source/WebCore/editing/TextCheckingHelper.cpp32
-rw-r--r--Source/WebCore/editing/TextIterator.cpp7
-rw-r--r--Source/WebCore/editing/TextIterator.h2
-rw-r--r--Source/WebCore/editing/TypingCommand.cpp26
-rw-r--r--Source/WebCore/editing/VisiblePosition.cpp18
-rw-r--r--Source/WebCore/editing/VisiblePosition.h7
-rw-r--r--Source/WebCore/editing/VisibleSelection.cpp37
-rw-r--r--Source/WebCore/editing/VisibleSelection.h2
-rw-r--r--Source/WebCore/editing/WrapContentsInDummySpanCommand.cpp4
-rw-r--r--Source/WebCore/editing/htmlediting.cpp108
-rw-r--r--Source/WebCore/editing/htmlediting.h37
-rw-r--r--Source/WebCore/editing/mac/EditorMac.mm9
-rw-r--r--Source/WebCore/editing/markup.cpp8
-rw-r--r--Source/WebCore/editing/visible_units.cpp191
-rw-r--r--Source/WebCore/editing/visible_units.h7
47 files changed, 563 insertions, 594 deletions
diff --git a/Source/WebCore/editing/AppendNodeCommand.cpp b/Source/WebCore/editing/AppendNodeCommand.cpp
index 58f7fa6..9395968 100644
--- a/Source/WebCore/editing/AppendNodeCommand.cpp
+++ b/Source/WebCore/editing/AppendNodeCommand.cpp
@@ -31,7 +31,7 @@
namespace WebCore {
-AppendNodeCommand::AppendNodeCommand(PassRefPtr<Element> parent, PassRefPtr<Node> node)
+AppendNodeCommand::AppendNodeCommand(PassRefPtr<ContainerNode> parent, PassRefPtr<Node> node)
: SimpleEditCommand(parent->document())
, m_parent(parent)
, m_node(node)
@@ -40,7 +40,7 @@ AppendNodeCommand::AppendNodeCommand(PassRefPtr<Element> parent, PassRefPtr<Node
ASSERT(m_node);
ASSERT(!m_node->parentNode());
- ASSERT(m_parent->isContentEditable() || !m_parent->attached());
+ ASSERT(m_parent->rendererIsEditable() || !m_parent->attached());
}
static void sendAXTextChangedIgnoringLineBreaks(Node* node, AXObjectCache::AXTextChange textChange)
@@ -56,7 +56,7 @@ static void sendAXTextChangedIgnoringLineBreaks(Node* node, AXObjectCache::AXTex
void AppendNodeCommand::doApply()
{
- if (!m_parent->isContentEditable() && m_parent->attached())
+ if (!m_parent->rendererIsEditable() && m_parent->attached())
return;
ExceptionCode ec;
@@ -68,7 +68,7 @@ void AppendNodeCommand::doApply()
void AppendNodeCommand::doUnapply()
{
- if (!m_parent->isContentEditable())
+ if (!m_parent->rendererIsEditable())
return;
// Need to notify this before actually deleting the text
diff --git a/Source/WebCore/editing/AppendNodeCommand.h b/Source/WebCore/editing/AppendNodeCommand.h
index 5ffb881..87a8cd2 100644
--- a/Source/WebCore/editing/AppendNodeCommand.h
+++ b/Source/WebCore/editing/AppendNodeCommand.h
@@ -32,18 +32,18 @@ namespace WebCore {
class AppendNodeCommand : public SimpleEditCommand {
public:
- static PassRefPtr<AppendNodeCommand> create(PassRefPtr<Element> parent, PassRefPtr<Node> node)
+ static PassRefPtr<AppendNodeCommand> create(PassRefPtr<ContainerNode> parent, PassRefPtr<Node> node)
{
return adoptRef(new AppendNodeCommand(parent, node));
}
private:
- AppendNodeCommand(PassRefPtr<Element> parent, PassRefPtr<Node> node);
+ AppendNodeCommand(PassRefPtr<ContainerNode> parent, PassRefPtr<Node>);
virtual void doApply();
virtual void doUnapply();
- RefPtr<Element> m_parent;
+ RefPtr<ContainerNode> m_parent;
RefPtr<Node> m_node;
};
diff --git a/Source/WebCore/editing/ApplyBlockElementCommand.cpp b/Source/WebCore/editing/ApplyBlockElementCommand.cpp
index 7e20acc..c8f2161 100644
--- a/Source/WebCore/editing/ApplyBlockElementCommand.cpp
+++ b/Source/WebCore/editing/ApplyBlockElementCommand.cpp
@@ -72,7 +72,7 @@ void ApplyBlockElementCommand::doApply()
// margin/padding, but not others. We should make the gap painting more consistent and
// then use a left margin/padding rule here.
if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
- setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(true)));
+ setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(CannotCrossEditingBoundary)));
VisibleSelection selection = selectionForParagraphIteration(endingSelection());
VisiblePosition startOfSelection = selection.visibleStart();
@@ -193,7 +193,7 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const
if (!startStyle->collapseWhiteSpace() && start.offsetInContainerNode() > 0) {
int startOffset = start.offsetInContainerNode();
splitTextNode(static_cast<Text*>(start.deprecatedNode()), startOffset);
- start = positionBeforeNode(start.deprecatedNode());
+ start = firstPositionInOrBeforeNode(start.deprecatedNode());
if (isStartAndEndOnSameNode) {
ASSERT(end.offsetInContainerNode() >= startOffset);
end = Position(end.deprecatedNode(), end.offsetInContainerNode() - startOffset, Position::PositionIsOffsetInAnchor);
@@ -224,7 +224,7 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const
&& end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
splitTextNode(static_cast<Text*>(end.deprecatedNode()), end.offsetInContainerNode());
if (isStartAndEndOnSameNode)
- start = positionBeforeNode(end.deprecatedNode()->previousSibling());
+ start = firstPositionInOrBeforeNode(end.deprecatedNode()->previousSibling());
if (isEndAndEndOfLastParagraphOnSameNode) {
if (m_endOfLastParagraph.offsetInContainerNode() == end.offsetInContainerNode())
m_endOfLastParagraph = lastPositionInNode(end.deprecatedNode()->previousSibling());
diff --git a/Source/WebCore/editing/ApplyStyleCommand.cpp b/Source/WebCore/editing/ApplyStyleCommand.cpp
index f9ed18e..59540ec 100644
--- a/Source/WebCore/editing/ApplyStyleCommand.cpp
+++ b/Source/WebCore/editing/ApplyStyleCommand.cpp
@@ -57,11 +57,9 @@ using namespace HTMLNames;
static RGBA32 getRGBAFontColor(CSSStyleDeclaration* style)
{
RefPtr<CSSValue> colorValue = style->getPropertyCSSValue(CSSPropertyColor);
- if (!colorValue)
+ if (!colorValue || !colorValue->isPrimitiveValue())
return Color::transparent;
- ASSERT(colorValue->isPrimitiveValue());
-
CSSPrimitiveValue* primitiveColor = static_cast<CSSPrimitiveValue*>(colorValue.get());
RGBA32 rgba = 0;
if (primitiveColor->primitiveType() != CSSPrimitiveValue::CSS_RGBCOLOR) {
@@ -76,7 +74,7 @@ static RGBA32 getRGBAFontColor(CSSStyleDeclaration* style)
class StyleChange {
public:
- explicit StyleChange(CSSStyleDeclaration*, const Position&);
+ StyleChange(EditingStyle*, const Position&);
String cssStyle() const { return m_cssStyle; }
bool applyBold() const { return m_applyBold; }
@@ -111,7 +109,7 @@ public:
return !(*this == other);
}
private:
- void init(PassRefPtr<CSSStyleDeclaration>, const Position&);
+ void init(EditingStyle*, const Position&);
void reconcileTextDecorationProperties(CSSMutableStyleDeclaration*);
void extractTextStyles(Document*, CSSMutableStyleDeclaration*, bool shouldUseFixedFontDefaultSize);
@@ -128,7 +126,7 @@ private:
};
-StyleChange::StyleChange(CSSStyleDeclaration* style, const Position& position)
+StyleChange::StyleChange(EditingStyle* style, const Position& position)
: m_applyBold(false)
, m_applyItalic(false)
, m_applyUnderline(false)
@@ -139,14 +137,14 @@ StyleChange::StyleChange(CSSStyleDeclaration* style, const Position& position)
init(style, position);
}
-void StyleChange::init(PassRefPtr<CSSStyleDeclaration> style, const Position& position)
+void StyleChange::init(EditingStyle* style, const Position& position)
{
Document* document = position.anchorNode() ? position.anchorNode()->document() : 0;
- if (!style || !document || !document->frame())
+ if (!style || !style->style() || !document || !document->frame())
return;
RefPtr<CSSComputedStyleDeclaration> computedStyle = position.computedStyle();
- RefPtr<CSSMutableStyleDeclaration> mutableStyle = getPropertiesNotIn(style.get(), computedStyle.get());
+ RefPtr<CSSMutableStyleDeclaration> mutableStyle = getPropertiesNotIn(style->style(), computedStyle.get());
reconcileTextDecorationProperties(mutableStyle.get());
if (!document->frame()->editor()->shouldStyleWithCSS())
@@ -158,8 +156,8 @@ void StyleChange::init(PassRefPtr<CSSStyleDeclaration> style, const Position& po
// If unicode-bidi is present in mutableStyle and direction is not, then add direction to mutableStyle.
// FIXME: Shouldn't this be done in getPropertiesNotIn?
- if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->getPropertyCSSValue(CSSPropertyDirection))
- mutableStyle->setProperty(CSSPropertyDirection, style->getPropertyValue(CSSPropertyDirection));
+ if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->style()->getPropertyCSSValue(CSSPropertyDirection))
+ mutableStyle->setProperty(CSSPropertyDirection, style->style()->getPropertyValue(CSSPropertyDirection));
// Save the result for later
m_cssStyle = mutableStyle->cssText().stripWhiteSpace();
@@ -591,7 +589,7 @@ void ApplyStyleCommand::applyBlockStyle(EditingStyle *style)
VisiblePosition nextParagraphStart(endOfParagraph(paragraphStart).next());
VisiblePosition beyondEnd(endOfParagraph(visibleEnd).next());
while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) {
- StyleChange styleChange(style->style(), paragraphStart.deepEquivalent());
+ StyleChange styleChange(style, paragraphStart.deepEquivalent());
if (styleChange.cssStyle().length() || m_removeOnly) {
RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().deprecatedNode());
if (!m_removeOnly) {
@@ -1017,12 +1015,12 @@ void ApplyStyleCommand::fixRangeAndApplyInlineStyle(EditingStyle* style, const P
static bool containsNonEditableRegion(Node* node)
{
- if (!node->isContentEditable())
+ if (!node->rendererIsEditable())
return true;
Node* sibling = node->traverseNextSibling();
for (Node* descendent = node->firstChild(); descendent && descendent != sibling; descendent = descendent->traverseNextNode()) {
- if (!descendent->isContentEditable())
+ if (!descendent->rendererIsEditable())
return true;
}
@@ -1037,10 +1035,10 @@ void ApplyStyleCommand::applyInlineStyleToNodeRange(EditingStyle* style, Node* n
for (RefPtr<Node> next; node && node != pastEndNode; node = next.get()) {
next = node->traverseNextNode();
- if (!node->renderer() || !node->isContentEditable())
+ if (!node->renderer() || !node->rendererIsEditable())
continue;
- if (!node->isContentRichlyEditable() && node->isHTMLElement()) {
+ if (!node->rendererIsRichlyEditable() && node->isHTMLElement()) {
// This is a plaintext-only region. Only proceed if it's fully selected.
// pastEndNode is the node after the last fully selected node, so if it's inside node then
// node isn't fully selected.
@@ -1059,7 +1057,7 @@ void ApplyStyleCommand::applyInlineStyleToNodeRange(EditingStyle* style, Node* n
continue;
if (node->childNodeCount()) {
- if (node->contains(pastEndNode) || containsNonEditableRegion(node) || !node->parentNode()->isContentEditable())
+ if (node->contains(pastEndNode) || containsNonEditableRegion(node) || !node->parentNode()->rendererIsEditable())
continue;
if (editingIgnoresContent(node)) {
next = node->traverseNextSibling();
@@ -1080,7 +1078,7 @@ void ApplyStyleCommand::applyInlineStyleToNodeRange(EditingStyle* style, Node* n
if (!removeStyleFromRunBeforeApplyingStyle(style, runStart, runEnd))
continue;
- addInlineStyleIfNeeded(style->style(), runStart.get(), runEnd.get(), AddStyledElement);
+ addInlineStyleIfNeeded(style, runStart.get(), runEnd.get(), AddStyledElement);
}
}
@@ -1099,7 +1097,7 @@ bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(EditingStyle* styl
if (node->childNodeCount())
continue;
// We don't consider m_isInlineElementToRemoveFunction here because we never apply style when m_isInlineElementToRemoveFunction is specified
- if ((!style->isEmpty() && getPropertiesNotIn(style->style(), computedStyle(node).get())->length())
+ if (!style->styleIsPresentInComputedStyleOfNode(node)
|| (m_styledInlineElement && !enclosingNodeWithTag(positionBeforeNode(node), m_styledInlineElement->tagQName()))) {
needToApplyStyle = true;
break;
@@ -1134,26 +1132,18 @@ bool ApplyStyleCommand::removeInlineStyleFromElement(EditingStyle* style, PassRe
{
ASSERT(element);
- if (!element->parentNode() || !element->parentNode()->isContentEditable())
+ if (!element->parentNode() || !element->parentNode()->rendererIsEditable())
return false;
if (isStyledInlineElementToRemove(element.get())) {
if (mode == RemoveNone)
return true;
ASSERT(extractedStyle);
- if (element->inlineStyleDecl()) {
- if (extractedStyle->style())
- extractedStyle->style()->merge(element->inlineStyleDecl());
- else
- extractedStyle->setStyle(element->inlineStyleDecl()->copy());
- }
+ extractedStyle->mergeInlineStyleOfElement(element.get());
removeNodePreservingChildren(element);
return true;
}
- if (!style->style())
- return false;
-
bool removed = false;
if (removeImplicitlyStyledElement(style, element.get(), mode, extractedStyle))
removed = true;
@@ -1296,7 +1286,7 @@ void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, EditingStyle* sty
// 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->style(), node, node, DoNotAddStyledElement);
+ addInlineStyleIfNeeded(newInlineStyle.get(), node, node, DoNotAddStyledElement);
}
void ApplyStyleCommand::pushDownInlineStyleAroundNode(EditingStyle* style, Node* targetNode)
@@ -1312,7 +1302,6 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(EditingStyle* style, Node*
Vector<RefPtr<Element> > elementsToPushDown;
while (current != targetNode) {
ASSERT(current);
- ASSERT(current->isHTMLElement());
ASSERT(current->contains(targetNode));
Node* child = current->firstChild();
Node* lastChild = current->lastChild();
@@ -1321,8 +1310,10 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(EditingStyle* style, Node*
styledElement = static_cast<StyledElement*>(current);
elementsToPushDown.append(styledElement);
}
+
RefPtr<EditingStyle> styleToPushDown = EditingStyle::create();
- removeInlineStyleFromElement(style, toHTMLElement(current), RemoveIfNeeded, styleToPushDown.get());
+ if (current->isHTMLElement())
+ removeInlineStyleFromElement(style, toHTMLElement(current), RemoveIfNeeded, styleToPushDown.get());
// The inner loop will go through children on each level
// FIXME: we should aggregate inline child elements together so that we don't wrap each child separately.
@@ -1659,13 +1650,13 @@ void ApplyStyleCommand::surroundNodeRangeWithElement(PassRefPtr<Node> passedStar
RefPtr<Node> nextSibling = element->nextSibling();
RefPtr<Node> previousSibling = element->previousSibling();
- if (nextSibling && nextSibling->isElementNode() && nextSibling->isContentEditable()
+ if (nextSibling && nextSibling->isElementNode() && nextSibling->rendererIsEditable()
&& areIdenticalElements(element.get(), static_cast<Element*>(nextSibling.get())))
mergeIdenticalElements(element.get(), static_cast<Element*>(nextSibling.get()));
- if (previousSibling && previousSibling->isElementNode() && previousSibling->isContentEditable()) {
+ if (previousSibling && previousSibling->isElementNode() && previousSibling->rendererIsEditable()) {
Node* mergedElement = previousSibling->nextSibling();
- if (mergedElement->isElementNode() && mergedElement->isContentEditable()
+ if (mergedElement->isElementNode() && mergedElement->rendererIsEditable()
&& areIdenticalElements(static_cast<Element*>(previousSibling.get()), static_cast<Element*>(mergedElement)))
mergeIdenticalElements(static_cast<Element*>(previousSibling.get()), static_cast<Element*>(mergedElement));
}
@@ -1689,7 +1680,7 @@ void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElemen
setNodeAttribute(block, styleAttr, cssText);
}
-void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style, PassRefPtr<Node> passedStart, PassRefPtr<Node> passedEnd, EAddStyledElement addStyledElement)
+void ApplyStyleCommand::addInlineStyleIfNeeded(EditingStyle* style, PassRefPtr<Node> passedStart, PassRefPtr<Node> passedEnd, EAddStyledElement addStyledElement)
{
if (!passedStart || !passedEnd || !passedStart->inDocument() || !passedEnd->inDocument())
return;
@@ -1704,7 +1695,7 @@ void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style
insertNodeAt(dummyElement, positionBeforeNode(startNode.get()));
positionForStyleComparison = positionBeforeNode(dummyElement.get());
} else
- positionForStyleComparison = firstPositionInNode(startNode.get());
+ positionForStyleComparison = firstPositionInOrBeforeNode(startNode.get());
StyleChange styleChange(style, positionForStyleComparison);
diff --git a/Source/WebCore/editing/ApplyStyleCommand.h b/Source/WebCore/editing/ApplyStyleCommand.h
index d4444e4..dc2217e 100644
--- a/Source/WebCore/editing/ApplyStyleCommand.h
+++ b/Source/WebCore/editing/ApplyStyleCommand.h
@@ -97,7 +97,7 @@ private:
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 addInlineStyleIfNeeded(EditingStyle*, PassRefPtr<Node> start, PassRefPtr<Node> end, EAddStyledElement = 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);
diff --git a/Source/WebCore/editing/BreakBlockquoteCommand.cpp b/Source/WebCore/editing/BreakBlockquoteCommand.cpp
index 011a787..91f496c 100644
--- a/Source/WebCore/editing/BreakBlockquoteCommand.cpp
+++ b/Source/WebCore/editing/BreakBlockquoteCommand.cpp
@@ -66,12 +66,8 @@ void BreakBlockquoteCommand::doApply()
Position pos = endingSelection().start().downstream();
// Find the top-most blockquote from the start.
- Element* topBlockquote = 0;
- for (ContainerNode* node = pos.deprecatedNode()->parentNode(); node; node = node->parentNode()) {
- if (isMailBlockquote(node))
- topBlockquote = static_cast<Element*>(node);
- }
- if (!topBlockquote || !topBlockquote->parentNode())
+ Node* topBlockquote = highestEnclosingNodeOfType(pos, isMailBlockquote);
+ if (!topBlockquote || !topBlockquote->parentNode() || !topBlockquote->isElementNode())
return;
RefPtr<Element> breakNode = createBreakElement(document());
@@ -103,7 +99,7 @@ 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.deprecatedNode())))
+ while (isFirstVisiblePositionInNode(VisiblePosition(pos), enclosingNodeOfType(pos, isMailBlockquote)))
pos = pos.previous();
// startNode is the first node that we need to move to the new blockquote.
@@ -135,7 +131,7 @@ void BreakBlockquoteCommand::doApply()
ancestors.append(node);
// Insert a clone of the top blockquote after the break.
- RefPtr<Element> clonedBlockquote = topBlockquote->cloneElementWithoutChildren();
+ RefPtr<Element> clonedBlockquote = static_cast<Element*>(topBlockquote)->cloneElementWithoutChildren();
insertNodeAfter(clonedBlockquote.get(), breakNode.get());
// Clone startNode's ancestors into the cloned blockquote.
@@ -152,7 +148,7 @@ void BreakBlockquoteCommand::doApply()
// find the first one so that we know where to start numbering.
while (listChildNode && !listChildNode->hasTagName(liTag))
listChildNode = listChildNode->nextSibling();
- if (listChildNode && listChildNode->renderer())
+ if (listChildNode && listChildNode->renderer() && listChildNode->renderer()->isListItem())
setNodeAttribute(static_cast<Element*>(clonedChild.get()), startAttr, String::number(toRenderListItem(listChildNode->renderer())->value()));
}
diff --git a/Source/WebCore/editing/CompositeEditCommand.cpp b/Source/WebCore/editing/CompositeEditCommand.cpp
index b7672ee..2a69fb7 100644
--- a/Source/WebCore/editing/CompositeEditCommand.cpp
+++ b/Source/WebCore/editing/CompositeEditCommand.cpp
@@ -144,7 +144,7 @@ void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRef
ASSERT(insertChild);
ASSERT(refChild);
ASSERT(!refChild->hasTagName(bodyTag));
- Element* parent = refChild->parentElement();
+ ContainerNode* parent = refChild->parentNode();
ASSERT(parent);
if (parent->lastChild() == refChild)
appendNode(insertChild, parent);
@@ -184,7 +184,7 @@ void CompositeEditCommand::insertNodeAt(PassRefPtr<Node> insertChild, const Posi
insertNodeAfter(insertChild, refChild);
}
-void CompositeEditCommand::appendNode(PassRefPtr<Node> node, PassRefPtr<Element> parent)
+void CompositeEditCommand::appendNode(PassRefPtr<Node> node, PassRefPtr<ContainerNode> parent)
{
ASSERT(canHaveChildrenForEditing(parent.get()));
applyCommandToComposite(AppendNodeCommand::create(parent, node));
@@ -830,10 +830,10 @@ void CompositeEditCommand::cloneParagraphUnderNewElement(Position& start, Positi
// Deleting a paragraph will leave a placeholder. Remove it (and prune
// empty or unrendered parents).
-void CompositeEditCommand::cleanupAfterDeletion()
+void CompositeEditCommand::cleanupAfterDeletion(VisiblePosition destination)
{
VisiblePosition caretAfterDelete = endingSelection().visibleStart();
- if (isStartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {
+ if (caretAfterDelete != destination && isStartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {
// Note: We want the rightmost candidate.
Position position = caretAfterDelete.deepEquivalent().downstream();
Node* node = position.deprecatedNode();
@@ -947,8 +947,8 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
}
}
- VisiblePosition beforeParagraph = startOfParagraphToMove.previous();
- VisiblePosition afterParagraph(endOfParagraphToMove.next());
+ VisiblePosition beforeParagraph = startOfParagraphToMove.previous(CannotCrossEditingBoundary);
+ VisiblePosition afterParagraph(endOfParagraphToMove.next(CannotCrossEditingBoundary));
// We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
// When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
@@ -985,8 +985,7 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
deleteSelection(false, false, false, false);
ASSERT(destination.deepEquivalent().anchorNode()->inDocument());
-
- cleanupAfterDeletion();
+ cleanupAfterDeletion(destination);
ASSERT(destination.deepEquivalent().anchorNode()->inDocument());
// Add a br if pruning an empty block level element caused a collapse. For example:
@@ -1049,7 +1048,7 @@ bool CompositeEditCommand::breakOutOfEmptyListItem()
// FIXME: Can't we do something better when the immediate parent wasn't a list node?
if (!listNode
|| (!listNode->hasTagName(ulTag) && !listNode->hasTagName(olTag))
- || !listNode->isContentEditable()
+ || !listNode->rendererIsEditable()
|| listNode == emptyListItem->rootEditableElement())
return false;
@@ -1114,7 +1113,7 @@ bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph()
if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret))
return false;
- VisiblePosition previous(caret.previous(true));
+ VisiblePosition previous(caret.previous(CannotCrossEditingBoundary));
// Only move forward if there's nothing before the caret, or if there's unquoted content before it.
if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote))
return false;
@@ -1173,8 +1172,8 @@ Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
// Don't avoid block level anchors, because that would insert content into the wrong paragraph.
if (enclosingAnchor && !isBlock(enclosingAnchor)) {
- VisiblePosition firstInAnchor(firstDeepEditingPositionForNode(enclosingAnchor));
- VisiblePosition lastInAnchor(lastDeepEditingPositionForNode(enclosingAnchor));
+ VisiblePosition firstInAnchor(firstPositionInNode(enclosingAnchor));
+ VisiblePosition lastInAnchor(lastPositionInNode(enclosingAnchor));
// If visually just after the anchor, insert *inside* the anchor unless it's the last
// VisiblePosition in the document, to match NSTextView.
if (visiblePos == lastInAnchor) {
diff --git a/Source/WebCore/editing/CompositeEditCommand.h b/Source/WebCore/editing/CompositeEditCommand.h
index 9066b65..4b96d8f 100644
--- a/Source/WebCore/editing/CompositeEditCommand.h
+++ b/Source/WebCore/editing/CompositeEditCommand.h
@@ -32,7 +32,6 @@
namespace WebCore {
-class CSSStyleDeclaration;
class EditingStyle;
class HTMLElement;
class StyledElement;
@@ -50,7 +49,7 @@ protected:
//
// sugary-sweet convenience functions to help create and apply edit commands in composite commands
//
- void appendNode(PassRefPtr<Node>, PassRefPtr<Element> parent);
+ void appendNode(PassRefPtr<Node>, PassRefPtr<ContainerNode> parent);
void applyCommandToComposite(PassRefPtr<EditCommand>);
void applyStyle(const EditingStyle*, EditAction = EditActionChangeAttributes);
void applyStyle(const EditingStyle*, const Position& start, const Position& end, EditAction = EditActionChangeAttributes);
@@ -110,7 +109,7 @@ protected:
void moveParagraphs(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false, bool preserveStyle = true);
void moveParagraphWithClones(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, Element* blockElement, Node* outerNode);
void cloneParagraphUnderNewElement(Position& start, Position& end, Node* outerNode, Element* blockElement);
- void cleanupAfterDeletion();
+ void cleanupAfterDeletion(VisiblePosition destination = VisiblePosition());
bool breakOutOfEmptyListItem();
bool breakOutOfEmptyMailBlockquotedParagraph();
diff --git a/Source/WebCore/editing/DeleteButtonController.cpp b/Source/WebCore/editing/DeleteButtonController.cpp
index 75b9a96..332e68f 100644
--- a/Source/WebCore/editing/DeleteButtonController.cpp
+++ b/Source/WebCore/editing/DeleteButtonController.cpp
@@ -63,7 +63,7 @@ DeleteButtonController::DeleteButtonController(Frame* frame)
static bool isDeletableElement(const Node* node)
{
- if (!node || !node->isHTMLElement() || !node->inDocument() || !node->isContentEditable())
+ if (!node || !node->isHTMLElement() || !node->inDocument() || !node->rendererIsEditable())
return false;
// In general we want to only draw the UI around object of a certain area, but we still keep the min width/height to
@@ -156,15 +156,11 @@ static HTMLElement* enclosingDeletableElement(const VisibleSelection& selection)
// The enclosingNodeOfType function only works on nodes that are editable
// (which is strange, given its name).
- if (!container->isContentEditable())
+ if (!container->rendererIsEditable())
return 0;
Node* element = enclosingNodeOfType(firstPositionInNode(container), &isDeletableElement);
- if (!element)
- return 0;
-
- ASSERT(element->isHTMLElement());
- return toHTMLElement(element);
+ return element && element->isHTMLElement() ? toHTMLElement(element) : 0;
}
void DeleteButtonController::respondToChangedSelection(const VisibleSelection& oldSelection)
diff --git a/Source/WebCore/editing/DeleteFromTextNodeCommand.cpp b/Source/WebCore/editing/DeleteFromTextNodeCommand.cpp
index fe572e1..8ee28a1 100644
--- a/Source/WebCore/editing/DeleteFromTextNodeCommand.cpp
+++ b/Source/WebCore/editing/DeleteFromTextNodeCommand.cpp
@@ -46,7 +46,7 @@ void DeleteFromTextNodeCommand::doApply()
{
ASSERT(m_node);
- if (!m_node->isContentEditable())
+ if (!m_node->rendererIsEditable())
return;
ExceptionCode ec = 0;
@@ -65,7 +65,7 @@ void DeleteFromTextNodeCommand::doUnapply()
{
ASSERT(m_node);
- if (!m_node->isContentEditable())
+ if (!m_node->rendererIsEditable())
return;
ExceptionCode ec;
diff --git a/Source/WebCore/editing/DeleteSelectionCommand.cpp b/Source/WebCore/editing/DeleteSelectionCommand.cpp
index 897c305..cbebe54 100644
--- a/Source/WebCore/editing/DeleteSelectionCommand.cpp
+++ b/Source/WebCore/editing/DeleteSelectionCommand.cpp
@@ -52,7 +52,7 @@ static bool isTableRow(const Node* node)
static bool isTableCellEmpty(Node* cell)
{
ASSERT(isTableCell(cell));
- return VisiblePosition(firstDeepEditingPositionForNode(cell)) == VisiblePosition(lastDeepEditingPositionForNode(cell));
+ return VisiblePosition(firstPositionInNode(cell)) == VisiblePosition(lastPositionInNode(cell));
}
static bool isTableRowEmpty(Node* row)
@@ -72,6 +72,7 @@ DeleteSelectionCommand::DeleteSelectionCommand(Document *document, bool smartDel
m_hasSelectionToDelete(false),
m_smartDelete(smartDelete),
m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
+ m_needPlaceholder(false),
m_replace(replace),
m_expandForSpecialElements(expandForSpecialElements),
m_pruneStartBlockIfNecessary(false),
@@ -88,6 +89,7 @@ DeleteSelectionCommand::DeleteSelectionCommand(const VisibleSelection& selection
m_hasSelectionToDelete(true),
m_smartDelete(smartDelete),
m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
+ m_needPlaceholder(false),
m_replace(replace),
m_expandForSpecialElements(expandForSpecialElements),
m_pruneStartBlockIfNecessary(false),
@@ -188,8 +190,8 @@ void DeleteSelectionCommand::initializePositionData()
// Don't move content out of a table cell.
// If the cell is non-editable, enclosingNodeOfType won't return it by default, so
// tell that function that we don't care if it returns non-editable nodes.
- Node* startCell = enclosingNodeOfType(m_upstreamStart, &isTableCell, false);
- Node* endCell = enclosingNodeOfType(m_downstreamEnd, &isTableCell, false);
+ Node* startCell = enclosingNodeOfType(m_upstreamStart, &isTableCell, CanCrossEditingBoundary);
+ Node* endCell = enclosingNodeOfType(m_downstreamEnd, &isTableCell, CanCrossEditingBoundary);
// FIXME: This isn't right. A borderless table with two rows and a single column would appear as two paragraphs.
if (endCell && endCell != startCell)
m_mergeBlocksAfterDelete = false;
@@ -262,8 +264,8 @@ void DeleteSelectionCommand::initializePositionData()
// like the one below, since editing functions should obviously accept editing positions.
// FIXME: Passing false to enclosingNodeOfType tells it that it's OK to return a non-editable
// node. This was done to match existing behavior, but it seems wrong.
- m_startBlock = enclosingNodeOfType(m_downstreamStart.parentAnchoredEquivalent(), &isBlock, false);
- m_endBlock = enclosingNodeOfType(m_upstreamEnd.parentAnchoredEquivalent(), &isBlock, false);
+ m_startBlock = enclosingNodeOfType(m_downstreamStart.parentAnchoredEquivalent(), &isBlock, CanCrossEditingBoundary);
+ m_endBlock = enclosingNodeOfType(m_upstreamEnd.parentAnchoredEquivalent(), &isBlock, CanCrossEditingBoundary);
}
void DeleteSelectionCommand::saveTypingStyleState()
@@ -284,7 +286,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().deprecatedNode()))
+ if (enclosingNodeOfType(m_selectionToDelete.start(), isMailBlockquote))
m_deleteIntoBlockquoteStyle = EditingStyle::create(m_selectionToDelete.end());
else
m_deleteIntoBlockquoteStyle = 0;
@@ -340,7 +342,7 @@ void DeleteSelectionCommand::removeNode(PassRefPtr<Node> node)
if (m_startRoot != m_endRoot && !(node->isDescendantOf(m_startRoot.get()) && node->isDescendantOf(m_endRoot.get()))) {
// If a node is not in both the start and end editable roots, remove it only if its inside an editable region.
- if (!node->parentNode()->isContentEditable()) {
+ if (!node->parentNode()->rendererIsEditable()) {
// Don't remove non-editable atomic nodes.
if (!node->firstChild())
return;
@@ -378,9 +380,9 @@ void DeleteSelectionCommand::removeNode(PassRefPtr<Node> node)
return;
}
- if (node == m_startBlock && !isEndOfBlock(VisiblePosition(firstDeepEditingPositionForNode(m_startBlock.get())).previous()))
+ if (node == m_startBlock && !isEndOfBlock(VisiblePosition(firstPositionInNode(m_startBlock.get())).previous()))
m_needPlaceholder = true;
- else if (node == m_endBlock && !isStartOfBlock(VisiblePosition(lastDeepEditingPositionForNode(m_startBlock.get())).next()))
+ else if (node == m_endBlock && !isStartOfBlock(VisiblePosition(lastPositionInNode(m_startBlock.get())).next()))
m_needPlaceholder = true;
// FIXME: Update the endpoints of the range being deleted.
@@ -592,7 +594,7 @@ void DeleteSelectionCommand::mergeParagraphs()
}
// We need to merge into m_upstreamStart's block, but it's been emptied out and collapsed by deletion.
- if (!mergeDestination.deepEquivalent().deprecatedNode() || !mergeDestination.deepEquivalent().deprecatedNode()->isDescendantOf(m_upstreamStart.deprecatedNode()->enclosingBlockFlowElement()) || m_startsAtEmptyLine) {
+ if (!mergeDestination.deepEquivalent().deprecatedNode() || !mergeDestination.deepEquivalent().deprecatedNode()->isDescendantOf(enclosingBlock(m_upstreamStart.containerNode())) || m_startsAtEmptyLine) {
insertNodeAt(createBreakElement(document()).get(), m_upstreamStart);
mergeDestination = VisiblePosition(m_upstreamStart);
}
@@ -687,7 +689,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.deprecatedNode()))
+ if (m_deleteIntoBlockquoteStyle && !enclosingNodeOfType(m_endingPosition, isMailBlockquote, CanCrossEditingBoundary))
m_typingStyle = m_deleteIntoBlockquoteStyle;
m_deleteIntoBlockquoteStyle = 0;
diff --git a/Source/WebCore/editing/EditingStyle.cpp b/Source/WebCore/editing/EditingStyle.cpp
index de71fb7..668c943 100644
--- a/Source/WebCore/editing/EditingStyle.cpp
+++ b/Source/WebCore/editing/EditingStyle.cpp
@@ -377,15 +377,13 @@ bool EditingStyle::textDirection(WritingDirection& writingDirection) const
return false;
RefPtr<CSSValue> unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
- if (!unicodeBidi)
+ if (!unicodeBidi || !unicodeBidi->isPrimitiveValue())
return false;
- ASSERT(unicodeBidi->isPrimitiveValue());
int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
if (unicodeBidiValue == CSSValueEmbed) {
RefPtr<CSSValue> direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
- ASSERT(!direction || direction->isPrimitiveValue());
- if (!direction)
+ if (!direction || !direction->isPrimitiveValue())
return false;
writingDirection = static_cast<CSSPrimitiveValue*>(direction.get())->getIdent() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
@@ -675,6 +673,11 @@ bool EditingStyle::extractConflictingImplicitStyleOfAttributes(HTMLElement* elem
return removed;
}
+bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const
+{
+ return !m_mutableStyle || !getPropertiesNotIn(m_mutableStyle.get(), computedStyle(node).get())->length();
+}
+
void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWritingDirection shouldPreserveWritingDirection)
{
if (!m_mutableStyle)
@@ -702,13 +705,10 @@ void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWrit
m_mutableStyle->removeProperty(CSSPropertyBackgroundColor, ec);
}
- if (unicodeBidi) {
- ASSERT(unicodeBidi->isPrimitiveValue());
+ if (unicodeBidi && unicodeBidi->isPrimitiveValue()) {
m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent());
- if (direction) {
- ASSERT(direction->isPrimitiveValue());
+ if (direction && direction->isPrimitiveValue())
m_mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSPrimitiveValue*>(direction.get())->getIdent());
- }
}
}
diff --git a/Source/WebCore/editing/EditingStyle.h b/Source/WebCore/editing/EditingStyle.h
index aa310ac..37bfea7 100644
--- a/Source/WebCore/editing/EditingStyle.h
+++ b/Source/WebCore/editing/EditingStyle.h
@@ -113,6 +113,7 @@ public:
bool conflictsWithImplicitStyleOfAttributes(HTMLElement*) const;
bool extractConflictingImplicitStyleOfAttributes(HTMLElement*, ShouldPreserveWritingDirection, EditingStyle* extractedStyle,
Vector<QualifiedName>& conflictingAttributes, ShouldExtractMatchingStyle) const;
+ bool styleIsPresentInComputedStyleOfNode(Node*) const;
void prepareToApplyAt(const Position&, ShouldPreserveWritingDirection = DoNotPreserveWritingDirection);
void mergeTypingStyle(Document*);
void mergeInlineStyleOfElement(StyledElement*);
diff --git a/Source/WebCore/editing/Editor.cpp b/Source/WebCore/editing/Editor.cpp
index 8807965..a793e0b 100644
--- a/Source/WebCore/editing/Editor.cpp
+++ b/Source/WebCore/editing/Editor.cpp
@@ -289,7 +289,7 @@ bool Editor::canDeleteRange(Range* range) const
if (!startContainer || !endContainer)
return false;
- if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
+ if (!startContainer->rendererIsEditable() || !endContainer->rendererIsEditable())
return false;
if (range->collapsed(ec)) {
@@ -653,10 +653,9 @@ WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbe
RefPtr<CSSComputedStyleDeclaration> style = computedStyle(n);
RefPtr<CSSValue> unicodeBidi = style->getPropertyCSSValue(CSSPropertyUnicodeBidi);
- if (!unicodeBidi)
+ if (!unicodeBidi || !unicodeBidi->isPrimitiveValue())
continue;
- ASSERT(unicodeBidi->isPrimitiveValue());
int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
if (unicodeBidiValue == CSSValueEmbed || unicodeBidiValue == CSSValueBidiOverride)
return NaturalWritingDirection;
@@ -684,10 +683,9 @@ WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbe
RefPtr<CSSComputedStyleDeclaration> style = computedStyle(node);
RefPtr<CSSValue> unicodeBidi = style->getPropertyCSSValue(CSSPropertyUnicodeBidi);
- if (!unicodeBidi)
+ if (!unicodeBidi || !unicodeBidi->isPrimitiveValue())
continue;
- ASSERT(unicodeBidi->isPrimitiveValue());
int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
if (unicodeBidiValue == CSSValueNormal)
continue;
@@ -697,10 +695,9 @@ WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbe
ASSERT(unicodeBidiValue == CSSValueEmbed);
RefPtr<CSSValue> direction = style->getPropertyCSSValue(CSSPropertyDirection);
- if (!direction)
+ if (!direction || !direction->isPrimitiveValue())
continue;
- ASSERT(direction->isPrimitiveValue());
int directionValue = static_cast<CSSPrimitiveValue*>(direction.get())->getIdent();
if (directionValue != CSSValueLtr && directionValue != CSSValueRtl)
continue;
@@ -1371,7 +1368,7 @@ int Editor::spellCheckerDocumentTag()
return client() ? client()->spellCheckerDocumentTag() : 0;
}
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if USE(AUTOMATIC_TEXT_REPLACEMENT)
void Editor::uppercaseWord()
{
@@ -1823,14 +1820,16 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec);
int misspellingOffset = 0;
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
- RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
- String misspelledWord;
- String badGrammarPhrase;
+ GrammarDetail grammarDetail;
int grammarPhraseOffset = 0;
+ RefPtr<Range> grammarSearchRange;
+ String badGrammarPhrase;
+ String misspelledWord;
+
+#if USE(UNIFIED_TEXT_CHECKING)
+ grammarSearchRange = spellingSearchRange->cloneRange(ec);
bool isSpelling = true;
int foundOffset = 0;
- GrammarDetail grammarDetail;
String foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
if (isSpelling) {
misspelledWord = foundItem;
@@ -1841,15 +1840,11 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
}
#else
RefPtr<Range> firstMisspellingRange;
- String misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
- String badGrammarPhrase;
-
-#ifndef BUILDING_ON_TIGER
- int grammarPhraseOffset = 0;
- GrammarDetail grammarDetail;
+ misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
+#if USE(GRAMMAR_CHECKING)
// Search for bad grammar that occurs prior to the next misspelled word (if any)
- RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
+ grammarSearchRange = spellingSearchRange->cloneRange(ec);
if (!misspelledWord.isEmpty()) {
// Stop looking at start of next misspelled word
CharacterIterator chars(grammarSearchRange.get());
@@ -1869,7 +1864,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
// going until the end of the very first chunk we tested is far enough
spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, ec);
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if USE(UNIFIED_TEXT_CHECKING)
grammarSearchRange = spellingSearchRange->cloneRange(ec);
foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
if (isSpelling) {
@@ -1882,7 +1877,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
#else
misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
-#ifndef BUILDING_ON_TIGER
+#if USE(GRAMMAR_CHECKING)
grammarSearchRange = spellingSearchRange->cloneRange(ec);
if (!misspelledWord.isEmpty()) {
// Stop looking at start of next misspelled word
@@ -1898,9 +1893,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
}
if (!badGrammarPhrase.isEmpty()) {
-#ifdef BUILDING_ON_TIGER
- ASSERT_NOT_REACHED();
-#else
+ ASSERT(WTF_USE_GRAMMAR_CHECKING);
// We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
// takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
// panel, and store a marker so we draw the green squiggle later.
@@ -1915,7 +1908,6 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
frame()->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
-#endif
} else if (!misspelledWord.isEmpty()) {
// We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
// a marker so we draw the red squiggle later.
@@ -1958,23 +1950,23 @@ bool Editor::isSelectionMisspelled()
bool Editor::isSelectionUngrammatical()
{
-#ifdef BUILDING_ON_TIGER
- return false;
-#else
+#if USE(GRAMMAR_CHECKING)
Vector<String> ignoredGuesses;
return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(ignoredGuesses);
+#else
+ return false;
#endif
}
Vector<String> Editor::guessesForUngrammaticalSelection()
{
-#ifdef BUILDING_ON_TIGER
- return Vector<String>();
-#else
+#if USE(GRAMMAR_CHECKING)
Vector<String> guesses;
// Ignore the result of isUngrammatical; we just want the guesses, whether or not there are any
TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(guesses);
return guesses;
+#else
+ return Vector<String>();
#endif
}
@@ -1991,7 +1983,7 @@ Vector<String> Editor::guessesForMisspelledSelection()
Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical)
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if USE(UNIFIED_TEXT_CHECKING)
return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).guessesForMisspelledOrUngrammaticalRange(isGrammarCheckingEnabled(), misspelled, ungrammatical);
#else
misspelled = isSelectionMisspelled();
@@ -2060,7 +2052,7 @@ void Editor::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelecti
void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping)
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if USE(UNIFIED_TEXT_CHECKING)
#if SUPPORT_AUTOCORRECTION_PANEL
// Apply pending autocorrection before next round of spell checking.
bool doApplyCorrection = true;
@@ -2072,7 +2064,7 @@ void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart,
doApplyCorrection = false;
}
if (doApplyCorrection)
- dismissCorrectionPanel(ReasonForDismissingCorrectionPanelAccepted);
+ handleCorrectionPanelResult(dismissCorrectionPanelSoon(ReasonForDismissingCorrectionPanelAccepted));
else
m_correctionPanelInfo.rangeToBeReplaced.clear();
#else
@@ -2082,12 +2074,14 @@ void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart,
if (isContinuousSpellCheckingEnabled())
textCheckingOptions |= MarkSpelling;
+#if USE(AUTOMATIC_TEXT_REPLACEMENT)
if (isAutomaticQuoteSubstitutionEnabled()
|| isAutomaticLinkDetectionEnabled()
|| isAutomaticDashSubstitutionEnabled()
|| isAutomaticTextReplacementEnabled()
|| ((textCheckingOptions & MarkSpelling) && isAutomaticSpellingCorrectionEnabled()))
textCheckingOptions |= PerformReplacement;
+#endif
if (!textCheckingOptions & (MarkSpelling | PerformReplacement))
return;
@@ -2162,7 +2156,7 @@ void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, boo
// If we're not in an editable node, bail.
Node* editableNode = searchRange->startContainer();
- if (!editableNode || !editableNode->isContentEditable())
+ if (!editableNode || !editableNode->rendererIsEditable())
return;
if (!isSpellCheckingEnabledFor(editableNode))
@@ -2176,12 +2170,9 @@ void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, boo
if (checkSpelling)
checker.markAllMisspellings(firstMisspellingRange);
else {
-#ifdef BUILDING_ON_TIGER
- ASSERT_NOT_REACHED();
-#else
+ ASSERT(WTF_USE_GRAMMAR_CHECKING);
if (isGrammarCheckingEnabled())
checker.markAllBadGrammar();
-#endif
}
}
@@ -2207,17 +2198,14 @@ void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>&
void Editor::markBadGrammar(const VisibleSelection& selection)
{
-#ifndef BUILDING_ON_TIGER
+ ASSERT(WTF_USE_GRAMMAR_CHECKING);
RefPtr<Range> firstMisspellingRange;
markMisspellingsOrBadGrammar(selection, false, firstMisspellingRange);
-#else
- UNUSED_PARAM(selection);
-#endif
}
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCheckingOptions, Range* spellingRange, Range* grammarRange)
{
+#if USE(UNIFIED_TEXT_CHECKING)
// There shouldn't be pending autocorrection at this moment.
ASSERT(!m_correctionPanelInfo.rangeToBeReplaced);
@@ -2233,7 +2221,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
// If we're not in an editable node, bail.
Node* editableNode = spellingRange->startContainer();
- if (!editableNode || !editableNode->isContentEditable())
+ if (!editableNode || !editableNode->rendererIsEditable())
return;
if (!isSpellCheckingEnabledFor(editableNode))
@@ -2248,7 +2236,6 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
TextCheckingParagraph spellingParagraph(spellingRange);
TextCheckingParagraph grammarParagraph(shouldMarkGrammar ? grammarRange : 0);
- TextCheckingParagraph& paragraph = shouldMarkGrammar ? grammarParagraph : spellingParagraph;
if (shouldMarkGrammar ? (spellingParagraph.isRangeEmpty() && grammarParagraph.isEmpty()) : spellingParagraph.isEmpty())
return;
@@ -2257,13 +2244,13 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
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();
- int offset = paragraph.offsetTo(caretPosition, ec);
+ int offset = spellingParagraph.offsetTo(caretPosition, ec);
if (!ec) {
selectionOffset = offset;
restoreSelectionAfterChange = true;
- if (selectionOffset > 0 && (selectionOffset > paragraph.textLength() || paragraph.textCharAt(selectionOffset - 1) == newlineCharacter))
+ if (selectionOffset > 0 && (selectionOffset > spellingParagraph.textLength() || spellingParagraph.textCharAt(selectionOffset - 1) == newlineCharacter))
adjustSelectionForParagraphBoundaries = true;
- if (selectionOffset > 0 && selectionOffset <= paragraph.textLength() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(selectionOffset - 1)))
+ if (selectionOffset > 0 && selectionOffset <= spellingParagraph.textLength() && isAmbiguousBoundaryCharacter(spellingParagraph.textCharAt(selectionOffset - 1)))
ambiguousBoundaryOffset = selectionOffset - 1;
}
}
@@ -2278,6 +2265,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (shouldShowCorrectionPanel)
checkingTypes |= TextCheckingTypeCorrection;
if (shouldPerformReplacement) {
+#if USE(AUTOMATIC_TEXT_REPLACEMENT)
if (isAutomaticLinkDetectionEnabled())
checkingTypes |= TextCheckingTypeLink;
if (isAutomaticQuoteSubstitutionEnabled())
@@ -2288,8 +2276,13 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
checkingTypes |= TextCheckingTypeReplacement;
if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
checkingTypes |= TextCheckingTypeCorrection;
+#endif
}
- textChecker()->checkTextOfParagraph(paragraph.textCharacters(), paragraph.textLength(), checkingTypes, results);
+ if (shouldMarkGrammar)
+ textChecker()->checkTextOfParagraph(grammarParagraph.textCharacters(), grammarParagraph.textLength(), checkingTypes, results);
+ else
+ textChecker()->checkTextOfParagraph(spellingParagraph.textCharacters(), spellingParagraph.textLength(), checkingTypes, results);
+
#if SUPPORT_AUTOCORRECTION_PANEL
// If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.
@@ -2348,7 +2341,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
// 2. The result doesn't end at an ambiguous boundary.
// (FIXME: this is required until 6853027 is fixed and text checking can do this for us
bool doReplacement = replacementLength > 0 && !resultEndsAtAmbiguousBoundary;
- RefPtr<Range> rangeToReplace = paragraph.subrange(resultLocation, resultLength);
+ RefPtr<Range> rangeToReplace = spellingParagraph.subrange(resultLocation, resultLength);
VisibleSelection selectionToReplace(rangeToReplace.get(), DOWNSTREAM);
// adding links should be done only immediately after they are typed
@@ -2387,7 +2380,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
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);
+ client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, result->replacement, Vector<String>());
break;
}
// If this function is called for showing correction panel, we ignore other correction or replacement.
@@ -2433,7 +2426,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
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);
+ RefPtr<Range> replacedRange = spellingParagraph.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);
@@ -2444,9 +2437,9 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (selectionChanged) {
// Restore the caret position if we have made any replacements
- paragraph.expandRangeToNextEnd();
- if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffset <= paragraph.rangeLength()) {
- RefPtr<Range> selectionRange = paragraph.subrange(0, selectionOffset);
+ spellingParagraph.expandRangeToNextEnd();
+ if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffset <= spellingParagraph.rangeLength()) {
+ RefPtr<Range> selectionRange = spellingParagraph.subrange(0, selectionOffset);
m_frame->selection()->moveTo(selectionRange->endPosition(), DOWNSTREAM);
if (adjustSelectionForParagraphBoundaries)
m_frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, CharacterGranularity);
@@ -2456,10 +2449,17 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
m_frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, CharacterGranularity);
}
}
+#else
+ ASSERT_NOT_REACHED();
+ UNUSED_PARAM(textCheckingOptions);
+ UNUSED_PARAM(spellingRange);
+ UNUSED_PARAM(grammarRange);
+#endif // USE(UNIFIED_TEXT_CHECKING)
}
void Editor::changeBackToReplacedString(const String& replacedString)
{
+#if USE(UNIFIED_TEXT_CHECKING)
if (replacedString.isEmpty())
return;
@@ -2478,13 +2478,16 @@ void Editor::changeBackToReplacedString(const String& replacedString)
#if SUPPORT_AUTOCORRECTION_PANEL
changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::SpellCheckingExemption);
#endif
+#else
+ ASSERT_NOT_REACHED();
+ UNUSED_PARAM(replacedString);
+#endif // USE(UNIFIED_TEXT_CHECKING)
}
-#endif
void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection)
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if USE(UNIFIED_TEXT_CHECKING)
if (!isContinuousSpellCheckingEnabled())
return;
TextCheckingOptions textCheckingOptions = MarkSpelling;
@@ -2517,7 +2520,7 @@ void Editor::correctionPanelTimerFired(Timer<Editor>*)
m_correctionPanelInfo.replacedString = plainText(m_correctionPanelInfo.rangeToBeReplaced.get());
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);
+ client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, m_correctionPanelInfo.replacementString, Vector<String>());
}
break;
case CorrectionPanelInfo::PanelTypeSpellingSuggestions: {
@@ -2535,7 +2538,7 @@ void Editor::correctionPanelTimerFired(Timer<Editor>*)
m_correctionPanelInfo.isActive = true;
FloatRect boundingBox = windowRectForRange(m_correctionPanelInfo.rangeToBeReplaced.get());
if (!boundingBox.isEmpty())
- client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, topSuggestion, suggestions, this);
+ client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, topSuggestion, suggestions);
}
break;
}
@@ -2601,39 +2604,36 @@ void Editor::stopCorrectionPanelTimer()
#endif
}
-void Editor::handleCancelOperation()
+void Editor::dismissCorrectionPanel(ReasonForDismissingCorrectionPanel reasonForDismissing)
{
#if SUPPORT_AUTOCORRECTION_PANEL
if (!m_correctionPanelInfo.isActive)
return;
m_correctionPanelInfo.isActive = false;
+ m_correctionPanelIsDismissedByEditor = true;
if (client())
- client()->dismissCorrectionPanel(ReasonForDismissingCorrectionPanelCancelled);
-#endif
-}
-
-bool Editor::isShowingCorrectionPanel()
-{
-#if SUPPORT_AUTOCORRECTION_PANEL
- if (client())
- return client()->isShowingCorrectionPanel();
+ client()->dismissCorrectionPanel(reasonForDismissing);
+#else
+ UNUSED_PARAM(reasonForDismissing);
#endif
- return false;
}
-void Editor::dismissCorrectionPanel(ReasonForDismissingCorrectionPanel reasonForDismissing)
+String Editor::dismissCorrectionPanelSoon(ReasonForDismissingCorrectionPanel reasonForDismissing)
{
#if SUPPORT_AUTOCORRECTION_PANEL
if (!m_correctionPanelInfo.isActive)
- return;
+ return String();
m_correctionPanelInfo.isActive = false;
m_correctionPanelIsDismissedByEditor = true;
- if (client())
- client()->dismissCorrectionPanel(reasonForDismissing);
+ if (!client())
+ return String();
+ return client()->dismissCorrectionPanelSoon(reasonForDismissing);
#else
UNUSED_PARAM(reasonForDismissing);
+ return String();
#endif
}
+
void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemoveIfSelectionAtWordBoundary)
{
// We want to remove the markers from a word if an editing command will change the word. This can happen in one of
@@ -2768,7 +2768,7 @@ bool Editor::applyAutocorrectionBeforeTypingIfAppropriate()
Position caretPosition = m_frame->selection()->selection().start();
if (m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition) {
- dismissCorrectionPanel(ReasonForDismissingCorrectionPanelAccepted);
+ handleCorrectionPanelResult(dismissCorrectionPanelSoon(ReasonForDismissingCorrectionPanelAccepted));
return true;
}
@@ -3572,7 +3572,7 @@ static Node* findFirstMarkable(Node* node)
return 0;
}
-bool Editor::selectionStartHasSpellingMarkerFor(int from, int length) const
+bool Editor::selectionStartHasMarkerFor(DocumentMarker::MarkerType markerType, int from, int length) const
{
Node* node = findFirstMarkable(m_frame->selection()->start().deprecatedNode());
if (!node)
@@ -3583,7 +3583,7 @@ bool Editor::selectionStartHasSpellingMarkerFor(int from, int length) const
Vector<DocumentMarker> markers = m_frame->document()->markers()->markersForNode(node);
for (size_t i = 0; i < markers.size(); ++i) {
DocumentMarker marker = markers[i];
- if (marker.startOffset <= startOffset && endOffset <= marker.endOffset && marker.type == DocumentMarker::Spelling)
+ if (marker.startOffset <= startOffset && endOffset <= marker.endOffset && marker.type == markerType)
return true;
}
diff --git a/Source/WebCore/editing/Editor.h b/Source/WebCore/editing/Editor.h
index e1a7119..c723ddf 100644
--- a/Source/WebCore/editing/Editor.h
+++ b/Source/WebCore/editing/Editor.h
@@ -36,6 +36,7 @@
#include "EditorInsertAction.h"
#include "FindOptions.h"
#include "SelectionController.h"
+#include "TextChecking.h"
#include "Timer.h"
#include "VisibleSelection.h"
#include "WritingDirection.h"
@@ -222,7 +223,7 @@ public:
void markMisspellings(const VisibleSelection&, RefPtr<Range>& firstMisspellingRange);
void markBadGrammar(const VisibleSelection&);
void markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection);
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if USE(AUTOMATIC_TEXT_REPLACEMENT)
void uppercaseWord();
void lowercaseWord();
void capitalizeWord();
@@ -239,6 +240,8 @@ public:
void toggleAutomaticTextReplacement();
bool isAutomaticSpellingCorrectionEnabled();
void toggleAutomaticSpellingCorrection();
+#endif
+
enum TextCheckingOptionFlags {
MarkSpelling = 1 << 0,
MarkGrammar = 1 << 1,
@@ -249,7 +252,7 @@ public:
void markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions, Range* spellingRange, Range* grammarRange);
void changeBackToReplacedString(const String& replacedString);
-#endif
+
void advanceToNextMisspelling(bool startBeforeSelection = false);
void showSpellingGuessPanel();
bool spellingPanelIsShowing();
@@ -320,11 +323,9 @@ public:
void addToKillRing(Range*, bool prepend);
- void handleCancelOperation();
void startCorrectionPanelTimer(CorrectionPanelInfo::PanelType);
// If user confirmed a correction in the correction panel, correction has non-zero length, otherwise it means that user has dismissed the panel.
void handleCorrectionPanelResult(const String& correction);
- bool isShowingCorrectionPanel();
void pasteAsFragment(PassRefPtr<DocumentFragment>, bool smartReplace, bool matchStyle);
void pasteAsPlainText(const String&, bool smartReplace);
@@ -376,9 +377,10 @@ public:
bool canCopyExcludingStandaloneImages();
void takeFindStringFromSelection();
void writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes);
+ void readSelectionFromPasteboard(const String& pasteboardName);
#endif
- bool selectionStartHasSpellingMarkerFor(int from, int length) const;
+ bool selectionStartHasMarkerFor(DocumentMarker::MarkerType, int from, int length) const;
void removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemoveIfSelectionAtWordBoundary);
private:
@@ -425,6 +427,7 @@ private:
Node* findEventTargetFromSelection() const;
void stopCorrectionPanelTimer();
void dismissCorrectionPanel(ReasonForDismissingCorrectionPanel);
+ String dismissCorrectionPanelSoon(ReasonForDismissingCorrectionPanel);
void applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd);
// Return true if correction was applied, false otherwise.
bool applyAutocorrectionBeforeTypingIfAppropriate();
diff --git a/Source/WebCore/editing/EditorCommand.cpp b/Source/WebCore/editing/EditorCommand.cpp
index 6ea9954..8ea37bb 100644
--- a/Source/WebCore/editing/EditorCommand.cpp
+++ b/Source/WebCore/editing/EditorCommand.cpp
@@ -56,6 +56,7 @@
#include "Sound.h"
#include "TypingCommand.h"
#include "UnlinkCommand.h"
+#include "UserTypingGestureIndicator.h"
#include "htmlediting.h"
#include "markup.h"
#include <wtf/text/AtomicString.h>
@@ -254,7 +255,7 @@ static int verticalScrollDistance(Frame* frame)
RenderStyle* style = renderer->style();
if (!style)
return 0;
- if (!(style->overflowY() == OSCROLL || style->overflowY() == OAUTO || focusedNode->isContentEditable()))
+ if (!(style->overflowY() == OSCROLL || style->overflowY() == OAUTO || focusedNode->rendererIsEditable()))
return 0;
int height = std::min<int>(toRenderBox(renderer)->clientHeight(),
frame->view()->visibleHeight());
@@ -294,19 +295,25 @@ static bool executeCreateLink(Frame* frame, Event*, EditorCommandSource, const S
return true;
}
-static bool executeCut(Frame* frame, Event*, EditorCommandSource, const String&)
+static bool executeCut(Frame* frame, Event*, EditorCommandSource source, const String&)
{
- frame->editor()->cut();
+ if (source == CommandFromMenuOrKeyBinding) {
+ UserTypingGestureIndicator typingGestureIndicator(frame);
+ frame->editor()->cut();
+ } else
+ frame->editor()->cut();
return true;
}
static bool executeDelete(Frame* frame, Event*, EditorCommandSource source, const String&)
{
switch (source) {
- case CommandFromMenuOrKeyBinding:
+ case CommandFromMenuOrKeyBinding: {
// Doesn't modify the text if the current selection isn't a range.
+ UserTypingGestureIndicator typingGestureIndicator(frame);
frame->editor()->performDelete();
return true;
+ }
case CommandFromDOM:
case CommandFromDOMWithUserInterface:
// If the current selection is a caret, delete the preceding character. IE performs forwardDelete, but we currently side with Firefox.
@@ -883,21 +890,33 @@ static bool executeOutdent(Frame* frame, Event*, EditorCommandSource, const Stri
return true;
}
-static bool executePaste(Frame* frame, Event*, EditorCommandSource, const String&)
+static bool executePaste(Frame* frame, Event*, EditorCommandSource source, const String&)
{
- frame->editor()->paste();
+ if (source == CommandFromMenuOrKeyBinding) {
+ UserTypingGestureIndicator typingGestureIndicator(frame);
+ frame->editor()->paste();
+ } else
+ frame->editor()->paste();
return true;
}
-static bool executePasteAndMatchStyle(Frame* frame, Event*, EditorCommandSource, const String&)
+static bool executePasteAndMatchStyle(Frame* frame, Event*, EditorCommandSource source, const String&)
{
- frame->editor()->pasteAsPlainText();
+ if (source == CommandFromMenuOrKeyBinding) {
+ UserTypingGestureIndicator typingGestureIndicator(frame);
+ frame->editor()->pasteAsPlainText();
+ } else
+ frame->editor()->pasteAsPlainText();
return true;
}
-static bool executePasteAsPlainText(Frame* frame, Event*, EditorCommandSource, const String&)
+static bool executePasteAsPlainText(Frame* frame, Event*, EditorCommandSource source, const String&)
{
- frame->editor()->pasteAsPlainText();
+ if (source == CommandFromMenuOrKeyBinding) {
+ UserTypingGestureIndicator typingGestureIndicator(frame);
+ frame->editor()->pasteAsPlainText();
+ } else
+ frame->editor()->pasteAsPlainText();
return true;
}
@@ -1091,14 +1110,6 @@ static bool executeYankAndSelect(Frame* frame, Event*, EditorCommandSource, cons
return true;
}
-#if SUPPORT_AUTOCORRECTION_PANEL
-static bool executeCancelOperation(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->handleCancelOperation();
- return true;
-}
-#endif
-
// Supported functions
static bool supported(Frame*)
@@ -1249,13 +1260,6 @@ static bool enabledUndo(Frame* frame, Event*, EditorCommandSource)
return frame->editor()->canUndo();
}
-#if SUPPORT_AUTOCORRECTION_PANEL
-static bool enabledDismissCorrectionPanel(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->editor()->isShowingCorrectionPanel();
-}
-#endif
-
// State functions
static TriState stateNone(Frame*, Event*)
@@ -1532,10 +1536,6 @@ static const CommandMap& createCommandMap()
#if PLATFORM(MAC)
{ "TakeFindStringFromSelection", { executeTakeFindStringFromSelection, supportedFromMenuOrKeyBinding, enabledTakeFindStringFromSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
#endif
-
-#if SUPPORT_AUTOCORRECTION_PANEL
- { "CancelOperation", { executeCancelOperation, supportedFromMenuOrKeyBinding, enabledDismissCorrectionPanel, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
-#endif
};
// These unsupported commands are listed here since they appear in the Microsoft
diff --git a/Source/WebCore/editing/EditorInsertAction.h b/Source/WebCore/editing/EditorInsertAction.h
index 5b732dc..b8b137d 100644
--- a/Source/WebCore/editing/EditorInsertAction.h
+++ b/Source/WebCore/editing/EditorInsertAction.h
@@ -32,7 +32,7 @@ namespace WebCore {
enum EditorInsertAction {
EditorInsertActionTyped,
EditorInsertActionPasted,
- EditorInsertActionDropped,
+ EditorInsertActionDropped
};
} // namespace
diff --git a/Source/WebCore/editing/FormatBlockCommand.cpp b/Source/WebCore/editing/FormatBlockCommand.cpp
index 9d90a1e..759ca31 100644
--- a/Source/WebCore/editing/FormatBlockCommand.cpp
+++ b/Source/WebCore/editing/FormatBlockCommand.cpp
@@ -112,8 +112,7 @@ Element* FormatBlockCommand::elementForFormatBlockCommand(Range* range)
if (!rootEditableElement || commonAncestor->contains(rootEditableElement))
return 0;
- ASSERT(commonAncestor->isElementNode());
- return static_cast<Element*>(commonAncestor);
+ return commonAncestor->isElementNode() ? toElement(commonAncestor) : 0;
}
bool isElementForFormatBlock(const QualifiedName& tagName)
@@ -149,14 +148,14 @@ Node* enclosingBlockToSplitTreeTo(Node* startNode)
{
Node* lastBlock = startNode;
for (Node* n = startNode; n; n = n->parentNode()) {
- if (!n->isContentEditable())
+ if (!n->rendererIsEditable())
return lastBlock;
- if (isTableCell(n) || n->hasTagName(bodyTag) || !n->parentNode() || !n->parentNode()->isContentEditable() || isElementForFormatBlock(n))
+ if (isTableCell(n) || n->hasTagName(bodyTag) || !n->parentNode() || !n->parentNode()->rendererIsEditable() || isElementForFormatBlock(n))
return n;
if (isBlock(n))
lastBlock = n;
if (isListElement(n))
- return n->parentNode()->isContentEditable() ? n->parentNode() : n;
+ return n->parentNode()->rendererIsEditable() ? n->parentNode() : n;
}
return lastBlock;
}
diff --git a/Source/WebCore/editing/IndentOutdentCommand.cpp b/Source/WebCore/editing/IndentOutdentCommand.cpp
index 82bec06..0229e85 100644
--- a/Source/WebCore/editing/IndentOutdentCommand.cpp
+++ b/Source/WebCore/editing/IndentOutdentCommand.cpp
@@ -120,7 +120,7 @@ void IndentOutdentCommand::outdentParagraph()
VisiblePosition visibleEndOfParagraph = endOfParagraph(visibleStartOfParagraph);
Node* enclosingNode = enclosingNodeOfType(visibleStartOfParagraph.deepEquivalent(), &isListOrIndentBlockquote);
- if (!enclosingNode || !enclosingNode->parentNode()->isContentEditable()) // We can't outdent if there is no place to go!
+ if (!enclosingNode || !enclosingNode->parentNode()->rendererIsEditable()) // We can't outdent if there is no place to go!
return;
// Use InsertListCommand to remove the selection from the list
@@ -151,7 +151,7 @@ void IndentOutdentCommand::outdentParagraph()
if (ContainerNode* splitPointParent = splitPoint->parentNode()) {
if (splitPointParent->hasTagName(blockquoteTag)
&& !splitPoint->hasTagName(blockquoteTag)
- && splitPointParent->parentNode()->isContentEditable()) // We can't outdent if there is no place to go!
+ && splitPointParent->parentNode()->rendererIsEditable()) // We can't outdent if there is no place to go!
splitElement(static_cast<Element*>(splitPointParent), splitPoint);
}
}
diff --git a/Source/WebCore/editing/InsertIntoTextNodeCommand.cpp b/Source/WebCore/editing/InsertIntoTextNodeCommand.cpp
index 9b7761c..b1a455b 100644
--- a/Source/WebCore/editing/InsertIntoTextNodeCommand.cpp
+++ b/Source/WebCore/editing/InsertIntoTextNodeCommand.cpp
@@ -44,7 +44,7 @@ InsertIntoTextNodeCommand::InsertIntoTextNodeCommand(PassRefPtr<Text> node, unsi
void InsertIntoTextNodeCommand::doApply()
{
- if (!m_node->isContentEditable())
+ if (!m_node->rendererIsEditable())
return;
ExceptionCode ec;
@@ -56,7 +56,7 @@ void InsertIntoTextNodeCommand::doApply()
void InsertIntoTextNodeCommand::doUnapply()
{
- if (!m_node->isContentEditable())
+ if (!m_node->rendererIsEditable())
return;
// Need to notify this before actually deleting the text
diff --git a/Source/WebCore/editing/InsertLineBreakCommand.cpp b/Source/WebCore/editing/InsertLineBreakCommand.cpp
index 2260a00..76c9052 100644
--- a/Source/WebCore/editing/InsertLineBreakCommand.cpp
+++ b/Source/WebCore/editing/InsertLineBreakCommand.cpp
@@ -171,7 +171,7 @@ void InsertLineBreakCommand::doApply()
// leaves and then comes back, new input will have the right style.
// FIXME: We shouldn't always apply the typing style to the line break here,
// see <rdar://problem/5794462>.
- applyStyle(typingStyle.get(), firstDeepEditingPositionForNode(nodeToInsert.get()), lastDeepEditingPositionForNode(nodeToInsert.get()));
+ applyStyle(typingStyle.get(), firstPositionInOrBeforeNode(nodeToInsert.get()), lastPositionInOrAfterNode(nodeToInsert.get()));
// Even though this applyStyle operates on a Range, it still sets an endingSelection().
// It tries to set a VisibleSelection around the content it operated on. So, that VisibleSelection
// will either (a) select the line break we inserted, or it will (b) be a caret just
diff --git a/Source/WebCore/editing/InsertListCommand.cpp b/Source/WebCore/editing/InsertListCommand.cpp
index 68661b4..4585b2e 100644
--- a/Source/WebCore/editing/InsertListCommand.cpp
+++ b/Source/WebCore/editing/InsertListCommand.cpp
@@ -121,8 +121,8 @@ void InsertListCommand::doApply()
// FIXME: We paint the gap before some paragraphs that are indented with left
// margin/padding, but not others. We should make the gap painting more consistent and
// then use a left margin/padding rule here.
- if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
- setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(true)));
+ if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd, CanSkipOverEditingBoundary))
+ setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(CannotCrossEditingBoundary)));
const QualifiedName& listTag = (m_type == OrderedList) ? olTag : ulTag;
if (endingSelection().isRange()) {
@@ -130,14 +130,14 @@ void InsertListCommand::doApply()
ASSERT(selection.isRange());
VisiblePosition startOfSelection = selection.visibleStart();
VisiblePosition endOfSelection = selection.visibleEnd();
- VisiblePosition startOfLastParagraph = startOfParagraph(endOfSelection);
+ VisiblePosition startOfLastParagraph = startOfParagraph(endOfSelection, CanSkipOverEditingBoundary);
- if (startOfParagraph(startOfSelection) != startOfLastParagraph) {
+ if (startOfParagraph(startOfSelection, CanSkipOverEditingBoundary) != startOfLastParagraph) {
bool forceCreateList = !selectionHasListOfType(selection, listTag);
RefPtr<Range> currentSelection = endingSelection().firstRange();
VisiblePosition startOfCurrentParagraph = startOfSelection;
- while (startOfCurrentParagraph != startOfLastParagraph) {
+ while (!inSameParagraph(startOfCurrentParagraph, startOfLastParagraph, CanCrossEditingBoundary)) {
// doApply() may operate on and remove the last paragraph of the selection from the document
// if it's in the same list item as startOfCurrentParagraph. Return early to avoid an
// infinite loop and because there is no more work to be done.
@@ -162,7 +162,7 @@ void InsertListCommand::doApply()
if (!lastSelectionRange)
return;
endOfSelection = lastSelectionRange->startPosition();
- startOfLastParagraph = startOfParagraph(endOfSelection);
+ startOfLastParagraph = startOfParagraph(endOfSelection, CanSkipOverEditingBoundary);
}
// Fetch the start of the selection after moving the first paragraph,
@@ -257,14 +257,14 @@ void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart,
VisiblePosition start;
VisiblePosition end;
if (listChildNode->hasTagName(liTag)) {
- start = firstDeepEditingPositionForNode(listChildNode);
- end = lastDeepEditingPositionForNode(listChildNode);
+ start = firstPositionInNode(listChildNode);
+ end = lastPositionInNode(listChildNode);
nextListChild = listChildNode->nextSibling();
previousListChild = listChildNode->previousSibling();
} else {
// A paragraph is visually a list item minus a list marker. The paragraph will be moved.
- start = startOfParagraph(originalStart);
- end = endOfParagraph(start);
+ start = startOfParagraph(originalStart, CanSkipOverEditingBoundary);
+ end = endOfParagraph(start, CanSkipOverEditingBoundary);
nextListChild = enclosingListChild(end.next().deepEquivalent().deprecatedNode(), listNode);
ASSERT(nextListChild != listChildNode);
previousListChild = enclosingListChild(start.previous().deepEquivalent().deprecatedNode(), listNode);
@@ -327,8 +327,8 @@ static Element* adjacentEnclosingList(const VisiblePosition& pos, const VisibleP
PassRefPtr<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePosition& originalStart, const QualifiedName& listTag)
{
- VisiblePosition start = startOfParagraph(originalStart);
- VisiblePosition end = endOfParagraph(start);
+ VisiblePosition start = startOfParagraph(originalStart, CanSkipOverEditingBoundary);
+ VisiblePosition end = endOfParagraph(start, CanSkipOverEditingBoundary);
if (start.isNull() || end.isNull())
return 0;
@@ -339,8 +339,8 @@ PassRefPtr<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePositio
appendNode(placeholder, listItemElement);
// Place list item into adjoining lists.
- Element* previousList = adjacentEnclosingList(start.deepEquivalent(), start.previous(true), listTag);
- Element* nextList = adjacentEnclosingList(start.deepEquivalent(), end.next(true), listTag);
+ Element* previousList = adjacentEnclosingList(start.deepEquivalent(), start.previous(CannotCrossEditingBoundary), listTag);
+ Element* nextList = adjacentEnclosingList(start.deepEquivalent(), end.next(CannotCrossEditingBoundary), listTag);
RefPtr<HTMLElement> listElement;
if (previousList)
appendNode(listItemElement, previousList);
@@ -375,8 +375,11 @@ PassRefPtr<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePositio
// We inserted the list at the start of the content we're about to move
// Update the start of content, so we don't try to move the list into itself. bug 19066
- if (insertionPos == start.deepEquivalent())
- start = startOfParagraph(originalStart);
+ // Layout is necessary since start's node's inline renderers may have been destroyed by the insertion
+ if (insertionPos == start.deepEquivalent()) {
+ listElement->document()->updateLayoutIgnorePendingStylesheets();
+ start = startOfParagraph(originalStart, CanSkipOverEditingBoundary);
+ }
}
moveParagraph(start, end, positionBeforeNode(placeholder.get()), true);
diff --git a/Source/WebCore/editing/InsertNodeBeforeCommand.cpp b/Source/WebCore/editing/InsertNodeBeforeCommand.cpp
index 5fae45e..4b028e7 100644
--- a/Source/WebCore/editing/InsertNodeBeforeCommand.cpp
+++ b/Source/WebCore/editing/InsertNodeBeforeCommand.cpp
@@ -41,13 +41,13 @@ InsertNodeBeforeCommand::InsertNodeBeforeCommand(PassRefPtr<Node> insertChild, P
ASSERT(m_refChild);
ASSERT(m_refChild->parentNode());
- ASSERT(m_refChild->parentNode()->isContentEditable() || !m_refChild->parentNode()->attached());
+ ASSERT(m_refChild->parentNode()->rendererIsEditable() || !m_refChild->parentNode()->attached());
}
void InsertNodeBeforeCommand::doApply()
{
ContainerNode* parent = m_refChild->parentNode();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
ExceptionCode ec;
@@ -59,7 +59,7 @@ void InsertNodeBeforeCommand::doApply()
void InsertNodeBeforeCommand::doUnapply()
{
- if (!m_insertChild->isContentEditable())
+ if (!m_insertChild->rendererIsEditable())
return;
// Need to notify this before actually deleting the text
diff --git a/Source/WebCore/editing/JoinTextNodesCommand.cpp b/Source/WebCore/editing/JoinTextNodesCommand.cpp
index 2766b84..86dd381 100644
--- a/Source/WebCore/editing/JoinTextNodesCommand.cpp
+++ b/Source/WebCore/editing/JoinTextNodesCommand.cpp
@@ -46,7 +46,7 @@ void JoinTextNodesCommand::doApply()
return;
ContainerNode* parent = m_text2->parentNode();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
ExceptionCode ec = 0;
@@ -63,7 +63,7 @@ void JoinTextNodesCommand::doUnapply()
return;
ContainerNode* parent = m_text2->parentNode();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
ExceptionCode ec = 0;
diff --git a/Source/WebCore/editing/MergeIdenticalElementsCommand.cpp b/Source/WebCore/editing/MergeIdenticalElementsCommand.cpp
index ff59f49..4ee9436 100644
--- a/Source/WebCore/editing/MergeIdenticalElementsCommand.cpp
+++ b/Source/WebCore/editing/MergeIdenticalElementsCommand.cpp
@@ -42,7 +42,7 @@ MergeIdenticalElementsCommand::MergeIdenticalElementsCommand(PassRefPtr<Element>
void MergeIdenticalElementsCommand::doApply()
{
- if (m_element1->nextSibling() != m_element2 || !m_element1->isContentEditable() || !m_element2->isContentEditable())
+ if (m_element1->nextSibling() != m_element2 || !m_element1->rendererIsEditable() || !m_element2->rendererIsEditable())
return;
m_atChild = m_element2->firstChild();
@@ -68,7 +68,7 @@ void MergeIdenticalElementsCommand::doUnapply()
RefPtr<Node> atChild = m_atChild.release();
ContainerNode* parent = m_element2->parentNode();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
ExceptionCode ec = 0;
diff --git a/Source/WebCore/editing/RemoveNodeCommand.cpp b/Source/WebCore/editing/RemoveNodeCommand.cpp
index 94e3e62..4a52492 100644
--- a/Source/WebCore/editing/RemoveNodeCommand.cpp
+++ b/Source/WebCore/editing/RemoveNodeCommand.cpp
@@ -42,7 +42,7 @@ RemoveNodeCommand::RemoveNodeCommand(PassRefPtr<Node> node)
void RemoveNodeCommand::doApply()
{
ContainerNode* parent = m_node->parentNode();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
m_parent = parent;
@@ -56,7 +56,7 @@ void RemoveNodeCommand::doUnapply()
{
RefPtr<ContainerNode> parent = m_parent.release();
RefPtr<Node> refChild = m_refChild.release();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
ExceptionCode ec;
diff --git a/Source/WebCore/editing/ReplaceSelectionCommand.cpp b/Source/WebCore/editing/ReplaceSelectionCommand.cpp
index b0a2d68..94531a6 100644
--- a/Source/WebCore/editing/ReplaceSelectionCommand.cpp
+++ b/Source/WebCore/editing/ReplaceSelectionCommand.cpp
@@ -43,6 +43,7 @@
#include "HTMLInputElement.h"
#include "HTMLInterchange.h"
#include "HTMLNames.h"
+#include "NodeList.h"
#include "SelectionController.h"
#include "SmartReplace.h"
#include "TextIterator.h"
@@ -110,7 +111,7 @@ 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.deprecatedNode()->hasTagName(brTag))
+ if (editingIgnoresContent(pos.deprecatedNode()))
return pos;
// We also stop when changing block flow elements because even though the visual position is the
@@ -147,7 +148,7 @@ ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* f
if (!editableRoot->getAttributeEventListener(eventNames().webkitBeforeTextInsertedEvent) &&
// FIXME: Remove these checks once textareas and textfields actually register an event handler.
!(shadowAncestorNode && shadowAncestorNode->renderer() && shadowAncestorNode->renderer()->isTextControl()) &&
- editableRoot->isContentRichlyEditable()) {
+ editableRoot->rendererIsRichlyEditable()) {
removeInterchangeNodes(m_fragment.get());
return;
}
@@ -162,7 +163,7 @@ ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* f
ExceptionCode ec = 0;
editableRoot->dispatchEvent(evt, ec);
ASSERT(ec == 0);
- if (text != evt->text() || !editableRoot->isContentRichlyEditable()) {
+ if (text != evt->text() || !editableRoot->rendererIsRichlyEditable()) {
restoreTestRenderingNodesToFragment(holder.get());
removeNode(holder);
@@ -357,7 +358,7 @@ static bool hasMatchingQuoteLevel(VisiblePosition endOfExistingContent, VisibleP
{
Position existing = endOfExistingContent.deepEquivalent();
Position inserted = endOfInsertedContent.deepEquivalent();
- bool isInsideMailBlockquote = nearestMailBlockquote(inserted.deprecatedNode());
+ bool isInsideMailBlockquote = enclosingNodeOfType(inserted, isMailBlockquote, CanCrossEditingBoundary);
return isInsideMailBlockquote && (numEnclosingMailBlockquotes(existing) == numEnclosingMailBlockquotes(inserted));
}
@@ -367,7 +368,7 @@ bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfPara
return false;
VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent());
- VisiblePosition prev = startOfInsertedContent.previous(true);
+ VisiblePosition prev = startOfInsertedContent.previous(CannotCrossEditingBoundary);
if (prev.isNull())
return false;
@@ -389,7 +390,7 @@ bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfPara
bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph)
{
VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent());
- VisiblePosition next = endOfInsertedContent.next(true);
+ VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary);
if (next.isNull())
return false;
@@ -536,10 +537,10 @@ VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent()
{
Node* lastNode = m_lastLeafInserted.get();
// FIXME: Why is this hack here? What's special about <select> tags?
- Node* enclosingSelect = enclosingNodeWithTag(firstDeepEditingPositionForNode(lastNode), selectTag);
+ Node* enclosingSelect = enclosingNodeWithTag(firstPositionInOrBeforeNode(lastNode), selectTag);
if (enclosingSelect)
lastNode = enclosingSelect;
- return lastDeepEditingPositionForNode(lastNode);
+ return lastPositionInOrAfterNode(lastNode);
}
VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent()
@@ -556,7 +557,7 @@ static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const
// Handling the case where we are doing Paste as Quotation or pasting into quoted content is more complicated (see handleStyleSpans)
// and doesn't receive the optimization.
- if (isMailPasteAsQuotationNode(topNode) || nearestMailBlockquote(topNode))
+ if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPositionInOrBeforeNode(topNode), isMailBlockquote, CanCrossEditingBoundary))
return false;
// Either there are no style spans in the fragment or a WebKit client has added content to the fragment
@@ -623,7 +624,7 @@ void ReplaceSelectionCommand::handleStyleSpans()
// If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region,
// styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>.
- Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : nearestMailBlockquote(context);
+ Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailBlockquote, CanCrossEditingBoundary);
if (blockquoteNode) {
sourceDocumentStyle->removeStyleConflictingWithStyleOfNode(blockquoteNode);
context = blockquoteNode->parentNode();
@@ -776,6 +777,34 @@ static Node* enclosingInline(Node* node)
return node;
}
+static bool isInlineNodeWithStyle(const Node* node)
+{
+ // We don't want to skip over any block elements.
+ if (!node->renderer() || !node->renderer()->isInline())
+ return false;
+
+ if (!node->isHTMLElement())
+ return false;
+
+ // We can skip over elements whose class attribute is
+ // one of our internal classes.
+ const HTMLElement* element = static_cast<const HTMLElement*>(node);
+ AtomicString classAttributeValue = element->getAttribute(classAttr);
+ if (classAttributeValue == AppleStyleSpanClass
+ || classAttributeValue == AppleTabSpanClass
+ || classAttributeValue == AppleConvertedSpace
+ || classAttributeValue == ApplePasteAsQuotation)
+ return true;
+
+ // We can skip inline elements that don't have attributes or whose only
+ // attribute is the style attribute.
+ const NamedNodeMap* attributeMap = element->attributeMap();
+ if (!attributeMap || attributeMap->isEmpty() || (attributeMap->length() == 1 && element->hasAttribute(styleAttr)))
+ return true;
+
+ return false;
+}
+
void ReplaceSelectionCommand::doApply()
{
VisibleSelection selection = endingSelection();
@@ -811,8 +840,8 @@ void ReplaceSelectionCommand::doApply()
Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().deprecatedNode());
Position insertionPos = selection.start();
- bool startIsInsideMailBlockquote = nearestMailBlockquote(insertionPos.deprecatedNode());
-
+ bool startIsInsideMailBlockquote = enclosingNodeOfType(insertionPos, isMailBlockquote, CanCrossEditingBoundary);
+
if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !startIsInsideMailBlockquote) ||
startBlock == currentRoot || isListItem(startBlock) || selectionIsPlainText)
m_preventNesting = false;
@@ -840,7 +869,7 @@ void ReplaceSelectionCommand::doApply()
} else {
ASSERT(selection.isCaret());
if (fragment.hasInterchangeNewlineAtStart()) {
- VisiblePosition next = visibleStart.next(true);
+ VisiblePosition next = visibleStart.next(CannotCrossEditingBoundary);
if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart) && next.isNotNull())
setEndingSelection(next);
else
@@ -917,6 +946,29 @@ void ReplaceSelectionCommand::doApply()
// outside of preceding tags.
insertionPos = positionAvoidingPrecedingNodes(insertionPos);
+ // If we are not trying to match the destination style we prefer a position
+ // that is outside inline elements that provide style.
+ // This way we can produce a less verbose markup.
+ // We can skip this optimization for fragments not wrapped in one of
+ // our style spans and for positions inside list items
+ // since insertAsListItems already does the right thing.
+ if (!m_matchStyle && !enclosingList(insertionPos.anchorNode()) && isStyleSpan(fragment.firstChild())) {
+ Node* parentNode = insertionPos.anchorNode()->parentNode();
+ while (parentNode && parentNode->renderer() && isInlineNodeWithStyle(parentNode)) {
+ // If we are in the middle of a text node, we need to split it before we can
+ // move the insertion position.
+ if (insertionPos.anchorNode()->isTextNode() && insertionPos.anchorType() == Position::PositionIsOffsetInAnchor && insertionPos.offsetInContainerNode() && !insertionPos.atLastEditingPositionForNode())
+ splitTextNodeContainingElement(static_cast<Text*>(insertionPos.anchorNode()), insertionPos.offsetInContainerNode());
+
+ // If the style element has more than one child, we need to split it.
+ if (parentNode->firstChild()->nextSibling())
+ splitElement(static_cast<Element*>(parentNode), insertionPos.computeNodeAfterPosition());
+
+ insertionPos = positionInParentBeforeNode(parentNode);
+ parentNode = parentNode->parentNode();
+ }
+ }
+
// FIXME: When pasting rich content we're often prevented from heading down the fast path by style spans. Try
// again here if they've been removed.
@@ -1036,7 +1088,7 @@ void ReplaceSelectionCommand::doApply()
startOfInsertedContent = positionAtStartOfInsertedContent();
if (interchangeNewlineAtEnd) {
- VisiblePosition next = endOfInsertedContent.next(true);
+ VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary);
if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedContent) || next.isNull()) {
if (!isStartOfParagraph(endOfInsertedContent)) {
diff --git a/Source/WebCore/editing/SelectionController.cpp b/Source/WebCore/editing/SelectionController.cpp
index 65f9062..698ba2c 100644
--- a/Source/WebCore/editing/SelectionController.cpp
+++ b/Source/WebCore/editing/SelectionController.cpp
@@ -153,16 +153,14 @@ void SelectionController::setSelection(const VisibleSelection& s, SetSelectionOp
return;
}
- Node* baseNode = s.base().deprecatedNode();
- Document* document = 0;
- if (baseNode)
- document = baseNode->document();
-
// <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, options);
- return;
+ if (s.base().anchorNode()) {
+ Document* document = s.base().anchorNode()->document();
+ if (document && document->frame() && document->frame() != m_frame && document != m_frame->document()) {
+ document->frame()->selection()->setSelection(s, options);
+ return;
+ }
}
if (closeTyping)
@@ -170,10 +168,13 @@ void SelectionController::setSelection(const VisibleSelection& s, SetSelectionOp
if (shouldClearTypingStyle)
clearTypingStyle();
-
- if (m_selection == s)
+
+ if (m_selection == s) {
+ // Even if selection was not changed, selection offsets may have been changed.
+ notifyRendererOfSelectionChange(userTriggered);
return;
-
+ }
+
VisibleSelection oldSelection = m_selection;
m_selection = s;
@@ -208,17 +209,17 @@ void SelectionController::setSelection(const VisibleSelection& s, SetSelectionOp
static bool removingNodeRemovesPosition(Node* node, const Position& position)
{
- if (!position.deprecatedNode())
+ if (!position.anchorNode())
return false;
- if (position.deprecatedNode() == node)
+ if (position.anchorNode() == node)
return true;
if (!node->isElementNode())
return false;
Element* element = static_cast<Element*>(node);
- return element->contains(position.deprecatedNode()) || element->contains(position.deprecatedNode()->shadowAncestorNode());
+ return element->contains(position.anchorNode()) || element->contains(position.anchorNode()->shadowAncestorNode());
}
void SelectionController::nodeWillBeRemoved(Node *node)
@@ -336,6 +337,11 @@ void SelectionController::setIsDirectional(bool isDirectional)
m_isDirectional = !m_frame || m_frame->editor()->behavior().shouldConsiderSelectionAsDirectional() || isDirectional;
}
+TextDirection SelectionController::directionOfEnclosingBlock()
+{
+ return WebCore::directionOfEnclosingBlock(m_selection.extent());
+}
+
void SelectionController::willBeModified(EAlteration alter, SelectionDirection direction)
{
if (alter != AlterationExtend)
@@ -385,17 +391,6 @@ void SelectionController::willBeModified(EAlteration alter, SelectionDirection d
}
}
-TextDirection SelectionController::directionOfEnclosingBlock()
-{
- Node* enclosingBlockNode = enclosingBlock(m_selection.extent().deprecatedNode());
- if (!enclosingBlockNode)
- return LTR;
- RenderObject* renderer = enclosingBlockNode->renderer();
- if (renderer)
- return renderer->style()->direction();
- return LTR;
-}
-
VisiblePosition SelectionController::positionForPlatform(bool isGetStart) const
{
Settings* settings = m_frame ? m_frame->settings() : 0;
@@ -431,9 +426,9 @@ VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granul
switch (granularity) {
case CharacterGranularity:
if (directionOfEnclosingBlock() == LTR)
- pos = pos.next(true);
+ pos = pos.next(CannotCrossEditingBoundary);
else
- pos = pos.previous(true);
+ pos = pos.previous(CannotCrossEditingBoundary);
break;
case WordGranularity:
if (directionOfEnclosingBlock() == LTR)
@@ -464,7 +459,7 @@ VisiblePosition SelectionController::modifyExtendingForward(TextGranularity gran
VisiblePosition pos(m_selection.extent(), m_selection.affinity());
switch (granularity) {
case CharacterGranularity:
- pos = pos.next(true);
+ pos = pos.next(CannotCrossEditingBoundary);
break;
case WordGranularity:
pos = nextWordPosition(pos);
@@ -538,7 +533,7 @@ VisiblePosition SelectionController::modifyMovingForward(TextGranularity granula
if (isRange())
pos = VisiblePosition(m_selection.end(), m_selection.affinity());
else
- pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(true);
+ pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
break;
case WordGranularity:
pos = nextWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
@@ -589,9 +584,9 @@ VisiblePosition SelectionController::modifyExtendingLeft(TextGranularity granula
switch (granularity) {
case CharacterGranularity:
if (directionOfEnclosingBlock() == LTR)
- pos = pos.previous(true);
+ pos = pos.previous(CannotCrossEditingBoundary);
else
- pos = pos.next(true);
+ pos = pos.next(CannotCrossEditingBoundary);
break;
case WordGranularity:
if (directionOfEnclosingBlock() == LTR)
@@ -626,7 +621,7 @@ VisiblePosition SelectionController::modifyExtendingBackward(TextGranularity gra
// over everything.
switch (granularity) {
case CharacterGranularity:
- pos = pos.previous(true);
+ pos = pos.previous(CannotCrossEditingBoundary);
break;
case WordGranularity:
pos = previousWordPosition(pos);
@@ -698,7 +693,7 @@ VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granul
if (isRange())
pos = VisiblePosition(m_selection.start(), m_selection.affinity());
else
- pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(true);
+ pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
break;
case WordGranularity:
pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
@@ -1256,11 +1251,11 @@ void SelectionController::debugRenderer(RenderObject *r, bool selected) const
int textLength = text.length();
if (selected) {
int offset = 0;
- if (r->node() == m_selection.start().deprecatedNode())
- offset = m_selection.start().deprecatedEditingOffset();
- else if (r->node() == m_selection.end().deprecatedNode())
- offset = m_selection.end().deprecatedEditingOffset();
-
+ if (r->node() == m_selection.start().containerNode())
+ offset = m_selection.start().computeOffsetInContainerNode();
+ else if (r->node() == m_selection.end().containerNode())
+ offset = m_selection.end().computeOffsetInContainerNode();
+
int pos;
InlineTextBox* box = textRenderer->findNextInlineTextBox(offset, pos);
text = text.substring(box->start(), box->len());
@@ -1368,7 +1363,7 @@ void SelectionController::selectFrameElementInParentIfFullySelected()
return;
// This method's purpose is it to make it easier to select iframes (in order to delete them). Don't do anything if the iframe isn't deletable.
- if (!ownerElementParent->isContentEditable())
+ if (!ownerElementParent->rendererIsEditable())
return;
// Create compute positions before and after the element.
@@ -1456,7 +1451,9 @@ bool SelectionController::setSelectedRange(Range* range, EAffinity affinity, boo
bool SelectionController::isInPasswordField() const
{
- Node* startNode = start().deprecatedNode();
+ ASSERT(start().isNull() || start().anchorType() == Position::PositionIsOffsetInAnchor
+ || start().containerNode() || !start().anchorNode()->shadowAncestorNode());
+ Node* startNode = start().containerNode();
if (!startNode)
return false;
@@ -1828,7 +1825,7 @@ void SelectionController::setSelectionFromNone()
Document* document = m_frame->document();
bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
- if (!isNone() || !(document->inDesignMode() || caretBrowsing))
+ if (!isNone() || !(document->rendererIsEditable() || caretBrowsing))
return;
Node* node = document->documentElement();
diff --git a/Source/WebCore/editing/SelectionController.h b/Source/WebCore/editing/SelectionController.h
index d6a9dff..2e3a6cd 100644
--- a/Source/WebCore/editing/SelectionController.h
+++ b/Source/WebCore/editing/SelectionController.h
@@ -127,7 +127,7 @@ public:
bool isRange() const { return m_selection.isRange(); }
bool isCaretOrRange() const { return m_selection.isCaretOrRange(); }
bool isInPasswordField() const;
- bool isAll(StayInEditableContent stayInEditableContent = MustStayInEditableContent) const { return m_selection.isAll(stayInEditableContent); }
+ bool isAll(EditingBoundaryCrossingRule rule = CannotCrossEditingBoundary) const { return m_selection.isAll(rule); }
PassRefPtr<Range> toNormalizedRange() const { return m_selection.toNormalizedRange(); }
diff --git a/Source/WebCore/editing/SplitElementCommand.cpp b/Source/WebCore/editing/SplitElementCommand.cpp
index 888c45f..fc135f7 100644
--- a/Source/WebCore/editing/SplitElementCommand.cpp
+++ b/Source/WebCore/editing/SplitElementCommand.cpp
@@ -54,7 +54,7 @@ void SplitElementCommand::executeApply()
ExceptionCode ec = 0;
ContainerNode* parent = m_element2->parentNode();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
parent->insertBefore(m_element1.get(), m_element2.get(), ec);
if (ec)
@@ -78,7 +78,7 @@ void SplitElementCommand::doApply()
void SplitElementCommand::doUnapply()
{
- if (!m_element1 || !m_element1->isContentEditable() || !m_element2->isContentEditable())
+ if (!m_element1 || !m_element1->rendererIsEditable() || !m_element2->rendererIsEditable())
return;
Vector<RefPtr<Node> > children;
diff --git a/Source/WebCore/editing/SplitTextNodeCommand.cpp b/Source/WebCore/editing/SplitTextNodeCommand.cpp
index aea36b9..5cf7ac8 100644
--- a/Source/WebCore/editing/SplitTextNodeCommand.cpp
+++ b/Source/WebCore/editing/SplitTextNodeCommand.cpp
@@ -51,7 +51,7 @@ SplitTextNodeCommand::SplitTextNodeCommand(PassRefPtr<Text> text, int offset)
void SplitTextNodeCommand::doApply()
{
ContainerNode* parent = m_text2->parentNode();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
ExceptionCode ec = 0;
@@ -68,7 +68,7 @@ void SplitTextNodeCommand::doApply()
void SplitTextNodeCommand::doUnapply()
{
- if (!m_text1 || !m_text1->isContentEditable())
+ if (!m_text1 || !m_text1->rendererIsEditable())
return;
ASSERT(m_text1->document() == document());
@@ -89,7 +89,7 @@ void SplitTextNodeCommand::doReapply()
return;
ContainerNode* parent = m_text2->parentNode();
- if (!parent || !parent->isContentEditable())
+ if (!parent || !parent->rendererIsEditable())
return;
insertText1AndTrimText2();
diff --git a/Source/WebCore/editing/SplitTextNodeContainingElementCommand.cpp b/Source/WebCore/editing/SplitTextNodeContainingElementCommand.cpp
index 8c90fb0..7b9fd2a 100644
--- a/Source/WebCore/editing/SplitTextNodeContainingElementCommand.cpp
+++ b/Source/WebCore/editing/SplitTextNodeContainingElementCommand.cpp
@@ -48,7 +48,7 @@ void SplitTextNodeContainingElementCommand::doApply()
splitTextNode(m_text.get(), m_offset);
Element* parent = m_text->parentElement();
- if (!parent || !parent->parentElement() || !parent->parentElement()->isContentEditable())
+ if (!parent || !parent->parentElement() || !parent->parentElement()->rendererIsEditable())
return;
RenderObject* parentRenderer = parent->renderer();
diff --git a/Source/WebCore/editing/TextCheckingHelper.cpp b/Source/WebCore/editing/TextCheckingHelper.cpp
index e5553fd..009c807 100644
--- a/Source/WebCore/editing/TextCheckingHelper.cpp
+++ b/Source/WebCore/editing/TextCheckingHelper.cpp
@@ -224,7 +224,7 @@ String TextCheckingHelper::findFirstMisspelling(int& firstMisspellingOffset, boo
String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if USE(UNIFIED_TEXT_CHECKING)
String firstFoundItem;
String misspelledWord;
String badGrammarPhrase;
@@ -350,12 +350,12 @@ String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b
UNUSED_PARAM(outFirstFoundOffset);
UNUSED_PARAM(outGrammarDetail);
return "";
-#endif
+#endif // USE(UNIFIED_TEXT_CHECKING)
}
int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int /*badGrammarPhraseLength*/, int startOffset, int endOffset, bool markAll)
{
-#ifndef BUILDING_ON_TIGER
+#if USE(GRAMMAR_CHECKING)
// Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
// Optionally add a DocumentMarker for each detail in the range.
int earliestDetailLocationSoFar = -1;
@@ -402,7 +402,7 @@ int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& gram
String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
{
-#ifndef BUILDING_ON_TIGER
+ ASSERT(WTF_USE_GRAMMAR_CHECKING);
// Initialize out parameters; these will be updated if we find something to return.
outGrammarDetail.location = -1;
outGrammarDetail.length = 0;
@@ -458,18 +458,12 @@ String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail,
}
return firstBadGrammarPhrase;
-#else
- ASSERT_NOT_REACHED();
- UNUSED_PARAM(outGrammarDetail);
- UNUSED_PARAM(outGrammarPhraseOffset);
- UNUSED_PARAM(markAll);
-#endif
}
bool TextCheckingHelper::isUngrammatical(Vector<String>& guessesVector) const
{
-#ifndef BUILDING_ON_TIGER
+ ASSERT(WTF_USE_GRAMMAR_CHECKING);
if (!m_client)
return false;
@@ -511,16 +505,11 @@ bool TextCheckingHelper::isUngrammatical(Vector<String>& guessesVector) const
m_client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
return true;
-#else
- ASSERT_NOT_REACHED();
- UNUSED_PARAM(guessesVector);
- return true;
-#endif
}
Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool checkGrammar, bool& misspelled, bool& ungrammatical) const
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if USE(UNIFIED_TEXT_CHECKING)
Vector<String> guesses;
ExceptionCode ec;
misspelled = false;
@@ -578,7 +567,7 @@ Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool
UNUSED_PARAM(misspelled);
UNUSED_PARAM(ungrammatical);
return Vector<String>();
-#endif
+#endif // USE(UNIFIED_TEXT_CHECKING)
}
@@ -592,15 +581,12 @@ void TextCheckingHelper::markAllMisspellings(RefPtr<Range>& firstMisspellingRang
void TextCheckingHelper::markAllBadGrammar()
{
-#ifndef BUILDING_ON_TIGER
- // Use the "markAll" feature of findFirstBadGrammar. Ignore the return value and "out parameters"; all we need to
+ ASSERT(WTF_USE_GRAMMAR_CHECKING);
+ // Use the "markAll" feature of ofindFirstBadGrammar. Ignore the return value and "out parameters"; all we need to
// do is mark every instance.
GrammarDetail ignoredGrammarDetail;
int ignoredOffset;
findFirstBadGrammar(ignoredGrammarDetail, ignoredOffset, true);
-#else
- ASSERT_NOT_REACHED();
-#endif
}
}
diff --git a/Source/WebCore/editing/TextIterator.cpp b/Source/WebCore/editing/TextIterator.cpp
index a9546b8..1b25c87 100644
--- a/Source/WebCore/editing/TextIterator.cpp
+++ b/Source/WebCore/editing/TextIterator.cpp
@@ -2320,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.deprecatedNode(), runEnd.deprecatedEditingOffset(), ec);
+ textRunRange->setEnd(runEnd.containerNode(), runEnd.computeOffsetInContainerNode(), ec);
ASSERT(!ec);
}
}
@@ -2512,11 +2512,6 @@ tryAgain:
return matchLength;
}
-PassRefPtr<Range> findPlainText(const Range* range, const String& target, bool forward, bool caseSensitive)
-{
- return findPlainText(range, target, (forward ? 0 : Backwards) | (caseSensitive ? 0 : CaseInsensitive));
-}
-
PassRefPtr<Range> findPlainText(const Range* range, const String& target, FindOptions options)
{
// First, find the text.
diff --git a/Source/WebCore/editing/TextIterator.h b/Source/WebCore/editing/TextIterator.h
index b0c310a..0f1a6fd 100644
--- a/Source/WebCore/editing/TextIterator.h
+++ b/Source/WebCore/editing/TextIterator.h
@@ -60,8 +60,6 @@ inline bool isCollapsibleWhitespace(UChar c)
String plainText(const Range*, TextIteratorBehavior defaultBehavior = TextIteratorDefaultBehavior);
UChar* plainTextToMallocAllocatedBuffer(const Range*, unsigned& bufferLength, bool isDisplayString, TextIteratorBehavior = TextIteratorDefaultBehavior);
PassRefPtr<Range> findPlainText(const Range*, const String&, FindOptions);
-// FIXME: Switch callers over to the FindOptions version and retire this one.
-PassRefPtr<Range> findPlainText(const Range*, const String&, bool forward, bool caseSensitive);
class BitStack {
public:
diff --git a/Source/WebCore/editing/TypingCommand.cpp b/Source/WebCore/editing/TypingCommand.cpp
index 3b42915..aedda31 100644
--- a/Source/WebCore/editing/TypingCommand.cpp
+++ b/Source/WebCore/editing/TypingCommand.cpp
@@ -47,6 +47,14 @@ namespace WebCore {
using namespace HTMLNames;
+static bool canAppendNewLineFeed(const VisibleSelection& selection)
+{
+ ExceptionCode ec = 0;
+ RefPtr<BeforeTextInsertedEvent> event = BeforeTextInsertedEvent::create(String("\n"));
+ selection.rootEditableElement()->dispatchEvent(event, ec);
+ return event->text().length();
+}
+
TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, const String &textToInsert, TypingCommandOptions options, TextGranularity granularity, TextCompositionType compositionType)
: CompositeEditCommand(document)
, m_commandType(commandType)
@@ -403,12 +411,18 @@ void TypingCommand::insertTextRunWithoutNewlines(const String &text, bool select
void TypingCommand::insertLineBreak()
{
+ if (!canAppendNewLineFeed(endingSelection()))
+ return;
+
applyCommandToComposite(InsertLineBreakCommand::create(document()));
typingAddedToOpenCommand(InsertLineBreak);
}
void TypingCommand::insertParagraphSeparator()
{
+ if (!canAppendNewLineFeed(endingSelection()))
+ return;
+
applyCommandToComposite(InsertParagraphSeparatorCommand::create(document()));
typingAddedToOpenCommand(InsertParagraphSeparator);
}
@@ -429,7 +443,7 @@ void TypingCommand::insertParagraphSeparatorInQuotedContent()
bool TypingCommand::makeEditableRootEmpty()
{
Element* root = endingSelection().rootEditableElement();
- if (!root->firstChild())
+ if (!root || !root->firstChild())
return false;
if (root->firstChild() == root->lastChild() && root->firstElementChild() && root->firstElementChild()->hasTagName(brTag)) {
@@ -474,14 +488,14 @@ void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool killRing)
if (killRing && selection.isCaret() && granularity != CharacterGranularity)
selection.modify(SelectionController::AlterationExtend, DirectionBackward, CharacterGranularity);
- if (endingSelection().visibleStart().previous(true).isNull()) {
+ if (endingSelection().visibleStart().previous(CannotCrossEditingBoundary).isNull()) {
// When the caret is at the start of the editable area in an empty list item, break out of the list item.
if (breakOutOfEmptyListItem()) {
typingAddedToOpenCommand(DeleteKey);
return;
}
// When there are no visible positions in the editing root, delete its entire contents.
- if (endingSelection().visibleStart().next(true).isNull() && makeEditableRootEmpty()) {
+ if (endingSelection().visibleStart().next(CannotCrossEditingBoundary).isNull() && makeEditableRootEmpty()) {
typingAddedToOpenCommand(DeleteKey);
return;
}
@@ -493,7 +507,7 @@ void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool killRing)
return;
// If the caret is at the start of a paragraph after a table, move content into the last table cell.
- if (isStartOfParagraph(visibleStart) && isFirstPositionAfterTable(visibleStart.previous(true))) {
+ if (isStartOfParagraph(visibleStart) && isFirstPositionAfterTable(visibleStart.previous(CannotCrossEditingBoundary))) {
// Unless the caret is just before a table. We don't want to move a table into the last table cell.
if (isLastPositionBeforeTable(visibleStart))
return;
@@ -574,10 +588,10 @@ void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool ki
Position downstreamEnd = endingSelection().end().downstream();
VisiblePosition visibleEnd = endingSelection().visibleEnd();
if (visibleEnd == endOfParagraph(visibleEnd))
- downstreamEnd = visibleEnd.next(true).deepEquivalent().downstream();
+ downstreamEnd = visibleEnd.next(CannotCrossEditingBoundary).deepEquivalent().downstream();
// When deleting tables: Select the table first, then perform the deletion
if (downstreamEnd.deprecatedNode() && downstreamEnd.deprecatedNode()->renderer() && downstreamEnd.deprecatedNode()->renderer()->isTable() && !downstreamEnd.deprecatedEditingOffset()) {
- setEndingSelection(VisibleSelection(endingSelection().end(), lastDeepEditingPositionForNode(downstreamEnd.deprecatedNode()), DOWNSTREAM));
+ setEndingSelection(VisibleSelection(endingSelection().end(), positionAfterNode(downstreamEnd.deprecatedNode()), DOWNSTREAM));
typingAddedToOpenCommand(ForwardDeleteKey);
return;
}
diff --git a/Source/WebCore/editing/VisiblePosition.cpp b/Source/WebCore/editing/VisiblePosition.cpp
index 10798ad..c3c05fd 100644
--- a/Source/WebCore/editing/VisiblePosition.cpp
+++ b/Source/WebCore/editing/VisiblePosition.cpp
@@ -59,18 +59,22 @@ void VisiblePosition::init(const Position& position, EAffinity affinity)
m_affinity = DOWNSTREAM;
}
-VisiblePosition VisiblePosition::next(bool stayInEditableContent) const
+VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
{
+ // FIXME: Support CanSkipEditingBoundary
+ ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
-
- if (!stayInEditableContent)
+
+ if (rule == CanCrossEditingBoundary)
return next;
-
+
return honorEditableBoundaryAtOrAfter(next);
}
-VisiblePosition VisiblePosition::previous(bool stayInEditableContent) const
+VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
{
+ // FIXME: Support CanSkipEditingBoundary
+ ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
// find first previous DOM position that is visible
Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
@@ -91,7 +95,7 @@ VisiblePosition VisiblePosition::previous(bool stayInEditableContent) const
}
#endif
- if (!stayInEditableContent)
+ if (rule == CanCrossEditingBoundary)
return prev;
return honorEditableBoundaryAtOrBefore(prev);
@@ -469,7 +473,7 @@ Position VisiblePosition::canonicalPosition(const Position& passedPosition)
// 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 && node->hasTagName(htmlTag) && !node->isContentEditable() && node->document()->body() && node->document()->body()->isContentEditable())
+ if (node && node->hasTagName(htmlTag) && !node->rendererIsEditable() && node->document()->body() && node->document()->body()->rendererIsEditable())
return next.isNotNull() ? next : prev;
Node* editingRoot = editableRootForPosition(position);
diff --git a/Source/WebCore/editing/VisiblePosition.h b/Source/WebCore/editing/VisiblePosition.h
index 008d676..505c914 100644
--- a/Source/WebCore/editing/VisiblePosition.h
+++ b/Source/WebCore/editing/VisiblePosition.h
@@ -26,6 +26,7 @@
#ifndef VisiblePosition_h
#define VisiblePosition_h
+#include "EditingBoundary.h"
#include "Node.h"
#include "Position.h"
#include "TextDirection.h"
@@ -47,8 +48,6 @@ namespace WebCore {
class InlineBox;
-enum StayInEditableContent { MayLeaveEditableContent, MustStayInEditableContent };
-
class VisiblePosition {
public:
// NOTE: UPSTREAM affinity will be used only if pos is at end of a wrapped line,
@@ -69,8 +68,8 @@ public:
// FIXME: Change the following functions' parameter from a boolean to StayInEditableContent.
// next() and previous() will increment/decrement by a character cluster.
- VisiblePosition next(bool stayInEditableContent = false) const;
- VisiblePosition previous(bool stayInEditableContent = false) const;
+ VisiblePosition next(EditingBoundaryCrossingRule = CanCrossEditingBoundary) const;
+ VisiblePosition previous(EditingBoundaryCrossingRule = CanCrossEditingBoundary) const;
VisiblePosition honorEditableBoundaryAtOrBefore(const VisiblePosition&) const;
VisiblePosition honorEditableBoundaryAtOrAfter(const VisiblePosition&) const;
diff --git a/Source/WebCore/editing/VisibleSelection.cpp b/Source/WebCore/editing/VisibleSelection.cpp
index 75531ca..5633c90 100644
--- a/Source/WebCore/editing/VisibleSelection.cpp
+++ b/Source/WebCore/editing/VisibleSelection.cpp
@@ -89,7 +89,8 @@ VisibleSelection::VisibleSelection(const Range* range, EAffinity affinity)
VisibleSelection VisibleSelection::selectionFromContentsOfNode(Node* node)
{
- return VisibleSelection(firstDeepEditingPositionForNode(node), lastDeepEditingPositionForNode(node), DOWNSTREAM);
+ ASSERT(!editingIgnoresContent(node));
+ return VisibleSelection(firstPositionInNode(node), lastPositionInNode(node), DOWNSTREAM);
}
void VisibleSelection::setBase(const Position& position)
@@ -172,8 +173,8 @@ PassRefPtr<Range> VisibleSelection::toNormalizedRange() const
s = s.parentAnchoredEquivalent();
e = e.parentAnchoredEquivalent();
}
-
- if (s.isNull() || e.isNull())
+
+ if (!s.containerNode() || !e.containerNode())
return 0;
// VisibleSelections are supposed to always be valid. This constructor will ASSERT
@@ -208,7 +209,7 @@ static PassRefPtr<Range> makeSearchRange(const Position& pos)
Position start(pos.parentAnchoredEquivalent());
searchRange->selectNodeContents(boundary, ec);
- searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
+ searchRange->setStart(start.containerNode(), start.offsetInContainerNode(), ec);
ASSERT(!ec);
if (ec)
@@ -217,9 +218,9 @@ static PassRefPtr<Range> makeSearchRange(const Position& pos)
return searchRange.release();
}
-bool VisibleSelection::isAll(StayInEditableContent stayInEditableContent) const
+bool VisibleSelection::isAll(EditingBoundaryCrossingRule rule) const
{
- return !shadowTreeRootNode() && visibleStart().previous(stayInEditableContent).isNull() && visibleEnd().next(stayInEditableContent).isNull();
+ return !shadowTreeRootNode() && visibleStart().previous(rule).isNull() && visibleEnd().next(rule).isNull();
}
void VisibleSelection::appendTrailingWhitespace()
@@ -305,7 +306,7 @@ void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(Text
// The paragraph break after the last paragraph in the last cell of a block table ends
// at the start of the paragraph after the table.
if (isBlock(table))
- end = end.next(true);
+ end = end.next(CannotCrossEditingBoundary);
else
end = wordEnd;
}
@@ -355,7 +356,7 @@ void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(Text
// The paragraph break after the last paragraph in the last cell of a block table ends
// at the start of the paragraph after the table, not at the position just after the table.
if (isBlock(table))
- end = end.next(true);
+ end = end.next(CannotCrossEditingBoundary);
// There is no parargraph break after the last paragraph in the last cell of an inline table.
else
end = visibleParagraphEnd;
@@ -457,7 +458,7 @@ void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
Node* startRoot = highestEditableRoot(m_start);
Node* endRoot = highestEditableRoot(m_end);
- Node* baseEditableAncestor = lowestEditableAncestor(m_base.deprecatedNode());
+ Node* baseEditableAncestor = lowestEditableAncestor(m_base.containerNode());
// The base, start and end are all in the same region. No adjustment necessary.
if (baseRoot == startRoot && baseRoot == endRoot)
@@ -492,19 +493,19 @@ 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.deprecatedNode());
+ Node* endEditableAncestor = lowestEditableAncestor(m_end.containerNode());
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.deprecatedNode()) == baseEditableAncestor && !isEditablePosition(p))) {
+ p = positionAfterNode(shadowAncestor);
+ while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) {
Node* root = editableRootForPosition(p);
shadowAncestor = root ? root->shadowAncestorNode() : 0;
- p = isAtomicNode(p.deprecatedNode()) ? positionInParentBeforeNode(p.deprecatedNode()) : previousVisuallyDistinctCandidate(p);
+ p = isAtomicNode(p.containerNode()) ? positionInParentBeforeNode(p.containerNode()) : previousVisuallyDistinctCandidate(p);
if (p.isNull() && (shadowAncestor != root))
- p = lastDeepEditingPositionForNode(shadowAncestor);
+ p = positionAfterNode(shadowAncestor);
}
VisiblePosition previous(p);
@@ -522,16 +523,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.deprecatedNode());
+ Node* startEditableAncestor = lowestEditableAncestor(m_start.containerNode());
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.deprecatedNode()) == baseEditableAncestor && !isEditablePosition(p))) {
+ while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) {
Node* root = editableRootForPosition(p);
shadowAncestor = root ? root->shadowAncestorNode() : 0;
- p = isAtomicNode(p.deprecatedNode()) ? positionInParentAfterNode(p.deprecatedNode()) : nextVisuallyDistinctCandidate(p);
+ p = isAtomicNode(p.containerNode()) ? positionInParentAfterNode(p.containerNode()) : nextVisuallyDistinctCandidate(p);
if (p.isNull() && (shadowAncestor != root))
p = positionBeforeNode(shadowAncestor);
}
@@ -551,7 +552,7 @@ void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
}
// Correct the extent if necessary.
- if (baseEditableAncestor != lowestEditableAncestor(m_extent.deprecatedNode()))
+ if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode()))
m_extent = m_baseIsFirst ? m_end : m_start;
}
diff --git a/Source/WebCore/editing/VisibleSelection.h b/Source/WebCore/editing/VisibleSelection.h
index 5d52a08..a352c20 100644
--- a/Source/WebCore/editing/VisibleSelection.h
+++ b/Source/WebCore/editing/VisibleSelection.h
@@ -79,7 +79,7 @@ public:
bool isBaseFirst() const { return m_baseIsFirst; }
- bool isAll(StayInEditableContent) const;
+ bool isAll(EditingBoundaryCrossingRule) const;
void appendTrailingWhitespace();
diff --git a/Source/WebCore/editing/WrapContentsInDummySpanCommand.cpp b/Source/WebCore/editing/WrapContentsInDummySpanCommand.cpp
index 5fa0b39..51f744c 100644
--- a/Source/WebCore/editing/WrapContentsInDummySpanCommand.cpp
+++ b/Source/WebCore/editing/WrapContentsInDummySpanCommand.cpp
@@ -64,7 +64,7 @@ void WrapContentsInDummySpanCommand::doUnapply()
{
ASSERT(m_element);
- if (!m_dummySpan || !m_element->isContentEditable())
+ if (!m_dummySpan || !m_element->rendererIsEditable())
return;
Vector<RefPtr<Node> > children;
@@ -84,7 +84,7 @@ void WrapContentsInDummySpanCommand::doReapply()
{
ASSERT(m_element);
- if (!m_dummySpan || !m_element->isContentEditable())
+ if (!m_dummySpan || !m_element->rendererIsEditable())
return;
executeApply();
diff --git a/Source/WebCore/editing/htmlediting.cpp b/Source/WebCore/editing/htmlediting.cpp
index a078d91..564eff6 100644
--- a/Source/WebCore/editing/htmlediting.cpp
+++ b/Source/WebCore/editing/htmlediting.cpp
@@ -34,6 +34,7 @@
#include "HTMLInterchange.h"
#include "HTMLLIElement.h"
#include "HTMLNames.h"
+#include "HTMLObjectElement.h"
#include "HTMLOListElement.h"
#include "HTMLUListElement.h"
#include "PositionIterator.h"
@@ -73,22 +74,20 @@ bool editingIgnoresContent(const Node* node)
bool canHaveChildrenForEditing(const Node* node)
{
- return !node->hasTagName(hrTag) &&
- !node->hasTagName(brTag) &&
- !node->hasTagName(imgTag) &&
- !node->hasTagName(buttonTag) &&
- !node->hasTagName(inputTag) &&
- !node->hasTagName(textareaTag) &&
- !node->hasTagName(objectTag) &&
- !node->hasTagName(iframeTag) &&
- !node->hasTagName(embedTag) &&
- !node->hasTagName(appletTag) &&
- !node->hasTagName(selectTag) &&
- !node->hasTagName(datagridTag) &&
+ return !node->isTextNode()
+ && !node->hasTagName(brTag)
+ && !node->hasTagName(imgTag)
+ && !node->hasTagName(inputTag)
+ && !node->hasTagName(textareaTag)
+ && (!node->hasTagName(objectTag) || static_cast<const HTMLObjectElement*>(node)->useFallbackContent())
+ && !node->hasTagName(iframeTag)
+ && !node->hasTagName(embedTag)
+ && !node->hasTagName(appletTag)
+ && !node->hasTagName(selectTag)
#if ENABLE(WML)
- !node->hasTagName(WMLNames::doTag) &&
+ && !node->hasTagName(WMLNames::doTag)
#endif
- !node->isTextNode();
+ && ((!node->hasTagName(hrTag) && !node->hasTagName(datagridTag)) || node->hasChildNodes());
}
// Compare two positions, taking into account the possibility that one or both
@@ -144,7 +143,7 @@ Node* highestEditableRoot(const Position& position)
node = highestRoot;
while (node) {
- if (node->isContentEditable())
+ if (node->rendererIsEditable())
highestRoot = node;
if (node->hasTagName(bodyTag))
break;
@@ -161,7 +160,7 @@ Node* lowestEditableAncestor(Node* node)
Node *lowestRoot = 0;
while (node) {
- if (node->isContentEditable())
+ if (node->rendererIsEditable())
return node->rootEditableElement();
if (node->hasTagName(bodyTag))
break;
@@ -180,7 +179,7 @@ bool isEditablePosition(const Position& p)
if (node->renderer() && node->renderer()->isTable())
node = node->parentNode();
- return node->isContentEditable();
+ return node->rendererIsEditable();
}
bool isAtUnsplittableElement(const Position& pos)
@@ -199,7 +198,7 @@ bool isRichlyEditablePosition(const Position& p)
if (node->renderer() && node->renderer()->isTable())
node = node->parentNode();
- return node->isContentRichlyEditable();
+ return node->rendererIsRichlyEditable();
}
Element* editableRootForPosition(const Position& p)
@@ -221,7 +220,7 @@ Element* unsplittableElementForPosition(const Position& p)
{
// Since enclosingNodeOfType won't search beyond the highest root editable node,
// this code works even if the closest table cell was outside of the root editable node.
- Element* enclosingCell = static_cast<Element*>(enclosingNodeOfType(p, &isTableCell, true));
+ Element* enclosingCell = static_cast<Element*>(enclosingNodeOfType(p, &isTableCell));
if (enclosingCell)
return enclosingCell;
@@ -277,14 +276,14 @@ Position previousVisuallyDistinctCandidate(const Position& position)
VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot)
{
// position falls before highestRoot.
- if (comparePositions(position, firstDeepEditingPositionForNode(highestRoot)) == -1 && highestRoot->isContentEditable())
- return firstDeepEditingPositionForNode(highestRoot);
+ if (comparePositions(position, firstPositionInNode(highestRoot)) == -1 && highestRoot->rendererIsEditable())
+ return firstPositionInNode(highestRoot);
Position p = position;
if (Node* shadowAncestor = p.deprecatedNode()->shadowAncestorNode())
if (shadowAncestor != p.deprecatedNode())
- p = lastDeepEditingPositionForNode(shadowAncestor);
+ p = positionAfterNode(shadowAncestor);
while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot))
p = isAtomicNode(p.deprecatedNode()) ? positionInParentAfterNode(p.deprecatedNode()) : nextVisuallyDistinctCandidate(p);
@@ -298,14 +297,15 @@ VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& positio
VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot)
{
// When position falls after highestRoot, the result is easy to compute.
- if (comparePositions(position, lastDeepEditingPositionForNode(highestRoot)) == 1)
- return lastDeepEditingPositionForNode(highestRoot);
+ if (comparePositions(position, lastPositionInNode(highestRoot)) == 1)
+ return lastPositionInNode(highestRoot);
Position p = position;
-
- if (Node* shadowAncestor = p.deprecatedNode()->shadowAncestorNode())
+
+ if (Node* shadowAncestor = p.deprecatedNode()->shadowAncestorNode()) {
if (shadowAncestor != p.deprecatedNode())
- p = firstDeepEditingPositionForNode(shadowAncestor);
+ p = firstPositionInOrBeforeNode(shadowAncestor);
+ }
while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot))
p = isAtomicNode(p.deprecatedNode()) ? positionInParentBeforeNode(p.deprecatedNode()) : previousVisuallyDistinctCandidate(p);
@@ -327,9 +327,18 @@ bool isBlock(const Node* node)
// FIXME: Pass a position to this function. The enclosing block of [table, x] for example, should be the
// block that contains the table and not the table, and this function should be the only one responsible for
// knowing about these kinds of special cases.
-Node* enclosingBlock(Node* node)
+Node* enclosingBlock(Node* node, EditingBoundaryCrossingRule rule)
{
- return static_cast<Element*>(enclosingNodeOfType(firstPositionInOrBeforeNode(node), isBlock));
+ return static_cast<Element*>(enclosingNodeOfType(firstPositionInOrBeforeNode(node), isBlock, rule));
+}
+
+TextDirection directionOfEnclosingBlock(const Position& position)
+{
+ Node* enclosingBlockNode = enclosingBlock(position.containerNode());
+ if (!enclosingBlockNode)
+ return LTR;
+ RenderObject* renderer = enclosingBlockNode->renderer();
+ return renderer ? renderer->style()->direction() : LTR;
}
// This method is used to create positions in the DOM. It returns the maximum valid offset
@@ -561,7 +570,7 @@ PassRefPtr<Range> extendRangeToWrappingNodes(PassRefPtr<Range> range, const Rang
Node* ancestor = range->commonAncestorContainer(ec);// find the cloeset common ancestor
Node* highestNode = 0;
// traverse through ancestors as long as they are contained within the range, content-editable, and below rootNode (could be =0).
- while (ancestor && ancestor->isContentEditable() && isNodeVisiblyContainedWithin(ancestor, maximumRange) && ancestor != rootNode) {
+ while (ancestor && ancestor->rendererIsEditable() && isNodeVisiblyContainedWithin(ancestor, maximumRange) && ancestor != rootNode) {
highestNode = ancestor;
ancestor = ancestor->parentNode();
}
@@ -592,7 +601,7 @@ Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
Node* root = highestEditableRoot(p);
for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
- if (root && !n->isContentEditable())
+ if (root && !n->rendererIsEditable())
continue;
if (n->hasTagName(tagName))
return n;
@@ -603,18 +612,20 @@ Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
return 0;
}
-Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), bool onlyReturnEditableNodes)
+Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule)
{
+ // FIXME: support CanSkipCrossEditingBoundary
+ ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
if (p.isNull())
return 0;
- Node* root = highestEditableRoot(p);
+ Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0;
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)
+ if (root && !n->rendererIsEditable())
continue;
- if ((*nodeIsOfType)(n))
+ if (nodeIsOfType(n))
return n;
if (n == root)
return 0;
@@ -623,12 +634,14 @@ Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*),
return 0;
}
-Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*))
+Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule)
{
Node* highest = 0;
- Node* root = highestEditableRoot(p);
+ Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0;
for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
- if ((*nodeIsOfType)(n))
+ if (root && !n->rendererIsEditable())
+ continue;
+ if (nodeIsOfType(n))
highest = n;
if (n == root)
break;
@@ -721,8 +734,8 @@ Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
return 0;
- VisiblePosition firstInListChild(firstDeepEditingPositionForNode(listChildNode));
- VisiblePosition lastInListChild(lastDeepEditingPositionForNode(listChildNode));
+ VisiblePosition firstInListChild(firstPositionInOrBeforeNode(listChildNode));
+ VisiblePosition lastInListChild(lastPositionInOrAfterNode(listChildNode));
if (firstInListChild != visiblePos || lastInListChild != visiblePos)
return 0;
@@ -754,7 +767,7 @@ bool canMergeLists(Element* firstList, Element* secondList)
return false;
return firstList->hasTagName(secondList->tagQName())// make sure the list types match (ol vs. ul)
- && firstList->isContentEditable() && secondList->isContentEditable()// both lists are editable
+ && firstList->rendererIsEditable() && secondList->rendererIsEditable() // both lists are editable
&& firstList->rootEditableElement() == secondList->rootEditableElement()// don't cross editing boundaries
&& isVisiblyAdjacent(positionInParentAfterNode(firstList), positionInParentBeforeNode(secondList));
// Make sure there is no visible content between this li and the previous list
@@ -932,15 +945,6 @@ bool isNodeRendered(const Node *node)
return renderer->style()->visibility() == VISIBLE;
}
-Node *nearestMailBlockquote(const Node *node)
-{
- for (Node *n = const_cast<Node *>(node); n; n = n->parentNode()) {
- if (isMailBlockquote(n))
- return n;
- }
- return 0;
-}
-
unsigned numEnclosingMailBlockquotes(const Position& p)
{
unsigned num = 0;
@@ -1016,7 +1020,7 @@ VisibleSelection selectionForParagraphIteration(const VisibleSelection& original
// (a table is itself a paragraph).
if (Node* table = isFirstPositionAfterTable(endOfSelection))
if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
- newSelection = VisibleSelection(startOfSelection, endOfSelection.previous(true));
+ newSelection = VisibleSelection(startOfSelection, endOfSelection.previous(CannotCrossEditingBoundary));
// If the start of the selection to modify is just before a table,
// and if the end of the selection is inside that table, then the first paragraph
@@ -1024,7 +1028,7 @@ VisibleSelection selectionForParagraphIteration(const VisibleSelection& original
// containing the table itself.
if (Node* table = isLastPositionBeforeTable(startOfSelection))
if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
- newSelection = VisibleSelection(startOfSelection.next(true), endOfSelection);
+ newSelection = VisibleSelection(startOfSelection.next(CannotCrossEditingBoundary), endOfSelection);
return newSelection;
}
diff --git a/Source/WebCore/editing/htmlediting.h b/Source/WebCore/editing/htmlediting.h
index b71e879..cb2b2a4 100644
--- a/Source/WebCore/editing/htmlediting.h
+++ b/Source/WebCore/editing/htmlediting.h
@@ -26,9 +26,11 @@
#ifndef htmlediting_h
#define htmlediting_h
+#include "EditingBoundary.h"
#include "ExceptionCode.h"
#include "HTMLNames.h"
#include "Position.h"
+#include "TextDirection.h"
#include <wtf/Forward.h>
#include <wtf/unicode/CharacterNames.h>
@@ -54,18 +56,17 @@ class VisibleSelection;
Node* highestAncestor(Node*);
Node* highestEditableRoot(const Position&);
-Node* highestEnclosingNodeOfType(const Position&, bool (*nodeIsOfType)(const Node*));
+Node* highestEnclosingNodeOfType(const Position&, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
Node* lowestEditableAncestor(Node*);
-Node* enclosingBlock(Node*);
+Node* enclosingBlock(Node*, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
Node* enclosingTableCell(const Position&);
Node* enclosingEmptyListItem(const VisiblePosition&);
Node* enclosingAnchorElement(const Position&);
Node* enclosingNodeWithTag(const Position&, const QualifiedName&);
-Node* enclosingNodeOfType(const Position&, bool (*nodeIsOfType)(const Node*), bool onlyReturnEditableNodes = true);
+Node* enclosingNodeOfType(const Position&, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
Node* tabSpanNode(const Node*);
-Node* nearestMailBlockquote(const Node*);
Node* isLastPositionBeforeTable(const VisiblePosition&);
Node* isFirstPositionAfterTable(const VisiblePosition&);
@@ -96,6 +97,8 @@ bool isNodeVisiblyContainedWithin(Node*, const Range*);
bool isRenderedAsNonInlineTableImageOrHR(const Node*);
bool isNodeInTextFormControl(Node* node);
+TextDirection directionOfEnclosingBlock(const Position&);
+
// -------------------------------------------------------------------------
// Position
// -------------------------------------------------------------------------
@@ -115,34 +118,18 @@ Position positionOutsideContainingSpecialElement(const Position&, Node** contain
inline Position firstPositionInOrBeforeNode(Node* node)
{
+ if (!node)
+ return Position();
return editingIgnoresContent(node) ? positionBeforeNode(node) : firstPositionInNode(node);
}
inline Position lastPositionInOrAfterNode(Node* node)
{
+ if (!node)
+ return Position();
return editingIgnoresContent(node) ? positionAfterNode(node) : lastPositionInNode(node);
}
-// Position creation functions are inline to prevent ref-churn.
-// Other Position creation functions are in Position.h
-// but these depend on lastOffsetForEditing which is defined in htmlediting.h.
-
-// NOTE: first/lastDeepEditingPositionForNode return legacy editing positions (like [img, 0])
-// for elements which editing ignores. The rest of the editing code will treat [img, 0]
-// as "the last position before the img".
-// New code should use the creation functions in Position.h instead.
-inline Position firstDeepEditingPositionForNode(Node* anchorNode)
-{
- ASSERT(anchorNode);
- return Position(anchorNode, 0);
-}
-
-inline Position lastDeepEditingPositionForNode(Node* anchorNode)
-{
- ASSERT(anchorNode);
- return Position(anchorNode, lastOffsetForEditing(anchorNode));
-}
-
// comparision functions on Position
int comparePositions(const Position&, const Position&);
@@ -237,7 +224,7 @@ inline bool isWhitespace(UChar c)
{
return c == noBreakSpace || c == ' ' || c == '\n' || c == '\t';
}
-String stringWithRebalancedWhitespace(const String&, bool, bool);
+String stringWithRebalancedWhitespace(const String&, bool startIsStartOfParagraph, bool endIsEndOfParagraph);
const String& nonBreakingSpaceString();
}
diff --git a/Source/WebCore/editing/mac/EditorMac.mm b/Source/WebCore/editing/mac/EditorMac.mm
index 4c617c0..60bfe6c 100644
--- a/Source/WebCore/editing/mac/EditorMac.mm
+++ b/Source/WebCore/editing/mac/EditorMac.mm
@@ -216,4 +216,13 @@ void Editor::writeSelectionToPasteboard(const String& pasteboardName, const Vect
Pasteboard::writeSelection([NSPasteboard pasteboardWithName:pasteboardName], types.get(), selectedRange().get(), true, m_frame);
}
+void Editor::readSelectionFromPasteboard(const String& pasteboardName)
+{
+ Pasteboard pasteboard([NSPasteboard pasteboardWithName:pasteboardName]);
+ if (m_frame->selection()->isContentRichlyEditable())
+ pasteWithPasteboard(&pasteboard, true);
+ else
+ pasteAsPlainTextWithPasteboard(&pasteboard);
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/editing/markup.cpp b/Source/WebCore/editing/markup.cpp
index 9d97b3f..316cec7 100644
--- a/Source/WebCore/editing/markup.cpp
+++ b/Source/WebCore/editing/markup.cpp
@@ -488,10 +488,8 @@ static Node* highestAncestorToWrapMarkup(const Range* range, Node* fullySelected
specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAncestor);
// Retain the Mail quote level by including all ancestor mail block quotes.
- for (Node* ancestor = range->firstNode(); ancestor; ancestor = ancestor->parentNode()) {
- if (isMailBlockquote(ancestor))
- specialCommonAncestor = ancestor;
- }
+ if (Node* highestMailBlockquote = highestEnclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isMailBlockquote, CanCrossEditingBoundary))
+ specialCommonAncestor = highestMailBlockquote;
}
Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor;
@@ -634,7 +632,7 @@ String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterc
// Styles that Mail blockquotes contribute should only be placed on the Mail blockquote, to help
// us differentiate those styles from ones that the user has applied. This helps us
// get the color of content pasted into blockquotes right.
- style->removeStyleAddedByNode(nearestMailBlockquote(parentOfLastClosed));
+ style->removeStyleAddedByNode(enclosingNodeOfType(firstPositionInNode(parentOfLastClosed), isMailBlockquote, CanCrossEditingBoundary));
// Document default styles will be added on another wrapper span.
if (document && document->documentElement())
diff --git a/Source/WebCore/editing/visible_units.cpp b/Source/WebCore/editing/visible_units.cpp
index 0baacf2..c9ca8c0 100644
--- a/Source/WebCore/editing/visible_units.cpp
+++ b/Source/WebCore/editing/visible_units.cpp
@@ -126,6 +126,7 @@ static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearch
// Use the character iterator to translate the next value into a DOM position.
BackwardsCharacterIterator charIt(searchRange.get());
charIt.advance(string.size() - suffixLength - next);
+ // FIXME: charIt can get out of shadow host.
return VisiblePosition(charIt.range()->endPosition(), DOWNSTREAM);
}
@@ -377,8 +378,8 @@ static VisiblePosition startPositionForLine(const VisiblePosition& c)
startBox = startBox->nextLeafChild();
}
- VisiblePosition visPos = startBox->isInlineTextBox() ? VisiblePosition(Position(startNode, static_cast<InlineTextBox *>(startBox)->start(), Position::PositionIsOffsetInAnchor), DOWNSTREAM)
- : VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM);
+ VisiblePosition visPos = startNode->isTextNode() ? VisiblePosition(Position(startNode, static_cast<InlineTextBox *>(startBox)->start(), Position::PositionIsOffsetInAnchor), DOWNSTREAM)
+ : VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM);
return positionAvoidingFirstPositionInTable(visPos);
}
@@ -476,10 +477,10 @@ bool isEndOfLine(const VisiblePosition &p)
// The first leaf before node that has the same editability as node.
static Node* previousLeafWithSameEditability(Node* node)
{
- bool editable = node->isContentEditable();
+ bool editable = node->rendererIsEditable();
Node* n = node->previousLeafNode();
while (n) {
- if (editable == n->isContentEditable())
+ if (editable == n->rendererIsEditable())
return n;
n = n->previousLeafNode();
}
@@ -571,18 +572,20 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
// Could not find a previous line. This means we must already be on the first line.
// 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();
+ Element* rootElement = node->rendererIsEditable() ? node->rootEditableElement() : node->document()->documentElement();
+ if (!rootElement)
+ return VisiblePosition();
return VisiblePosition(firstPositionInNode(rootElement), DOWNSTREAM);
}
static Node* nextLeafWithSameEditability(Node* node, int offset)
{
- bool editable = node->isContentEditable();
+ bool editable = node->rendererIsEditable();
ASSERT(offset >= 0);
Node* child = node->childNode(offset);
Node* n = child ? child->nextLeafNode() : node->lastDescendant()->nextLeafNode();
while (n) {
- if (editable == n->isContentEditable())
+ if (editable == n->rendererIsEditable())
return n;
n = n->nextLeafNode();
}
@@ -594,10 +597,10 @@ static Node* nextLeafWithSameEditability(Node* node)
if (!node)
return 0;
- bool editable = node->isContentEditable();
+ bool editable = node->rendererIsEditable();
Node* n = node->nextLeafNode();
while (n) {
- if (editable == n->isContentEditable())
+ if (editable == n->rendererIsEditable())
return n;
n = n->nextLeafNode();
}
@@ -676,7 +679,9 @@ VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
// Could not find a next line. This means we must already be on the last line.
// 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();
+ Element* rootElement = node->rendererIsEditable() ? node->rootEditableElement() : node->document()->documentElement();
+ if (!rootElement)
+ return VisiblePosition();
return VisiblePosition(lastPositionInNode(rootElement), DOWNSTREAM);
}
@@ -743,18 +748,25 @@ VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossi
return VisiblePosition();
if (isRenderedAsNonInlineTableImageOrHR(startNode))
- return firstDeepEditingPositionForNode(startNode);
+ return positionBeforeNode(startNode);
Node* startBlock = enclosingBlock(startNode);
- Node *node = startNode;
+ Node* node = startNode;
+ Node* highestRoot = highestEditableRoot(p);
int offset = p.deprecatedEditingOffset();
Position::AnchorType type = p.anchorType();
- Node *n = startNode;
+ Node* n = startNode;
while (n) {
- if (boundaryCrossingRule == CannotCrossEditingBoundary && n->isContentEditable() != startNode->isContentEditable())
+ if (boundaryCrossingRule == CannotCrossEditingBoundary && n->rendererIsEditable() != startNode->rendererIsEditable())
break;
+ if (boundaryCrossingRule == CanSkipOverEditingBoundary) {
+ while (n && n->rendererIsEditable() != startNode->rendererIsEditable())
+ n = n->traversePreviousNodePostOrder(startBlock);
+ if (!n || !n->isDescendantOf(highestRoot))
+ break;
+ }
RenderObject *r = n->renderer();
if (!r) {
n = n->traversePreviousNodePostOrder(startBlock);
@@ -807,19 +819,27 @@ VisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossing
Node* startNode = p.deprecatedNode();
if (isRenderedAsNonInlineTableImageOrHR(startNode))
- return lastDeepEditingPositionForNode(startNode);
+ return positionAfterNode(startNode);
Node* startBlock = enclosingBlock(startNode);
- Node *stayInsideBlock = startBlock;
+ Node* stayInsideBlock = startBlock;
- Node *node = startNode;
+ Node* node = startNode;
+ Node* highestRoot = highestEditableRoot(p);
int offset = p.deprecatedEditingOffset();
Position::AnchorType type = p.anchorType();
- Node *n = startNode;
+ Node* n = startNode;
while (n) {
- if (boundaryCrossingRule == CannotCrossEditingBoundary && n->isContentEditable() != startNode->isContentEditable())
+ if (boundaryCrossingRule == CannotCrossEditingBoundary && n->rendererIsEditable() != startNode->rendererIsEditable())
break;
+ if (boundaryCrossingRule == CanSkipOverEditingBoundary) {
+ while (n && n->rendererIsEditable() != startNode->rendererIsEditable())
+ n = n->traverseNextNode(stayInsideBlock);
+ if (!n || !n->isDescendantOf(highestRoot))
+ break;
+ }
+
RenderObject *r = n->renderer();
if (!r) {
n = n->traverseNextNode(stayInsideBlock);
@@ -862,20 +882,21 @@ VisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossing
return VisiblePosition(Position(node, type), DOWNSTREAM);
}
+// FIXME: isStartOfParagraph(startOfNextParagraph(pos)) is not always true
VisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition)
{
- VisiblePosition paragraphEnd(endOfParagraph(visiblePosition));
- VisiblePosition afterParagraphEnd(paragraphEnd.next(true));
+ VisiblePosition paragraphEnd(endOfParagraph(visiblePosition, CanSkipOverEditingBoundary));
+ VisiblePosition afterParagraphEnd(paragraphEnd.next(CannotCrossEditingBoundary));
// The position after the last position in the last cell of a table
// is not the start of the next paragraph.
if (isFirstPositionAfterTable(afterParagraphEnd))
- return afterParagraphEnd.next(true);
+ return afterParagraphEnd.next(CannotCrossEditingBoundary);
return afterParagraphEnd;
}
-bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
+bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b, EditingBoundaryCrossingRule boundaryCrossingRule)
{
- return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
+ return a.isNotNull() && startOfParagraph(a, boundaryCrossingRule) == startOfParagraph(b, boundaryCrossingRule);
}
bool isStartOfParagraph(const VisiblePosition &pos, EditingBoundaryCrossingRule boundaryCrossingRule)
@@ -914,41 +935,37 @@ VisiblePosition nextParagraphPosition(const VisiblePosition& p, int x)
// ---------
-VisiblePosition startOfBlock(const VisiblePosition &c)
+VisiblePosition startOfBlock(const VisiblePosition& visiblePosition, EditingBoundaryCrossingRule rule)
{
- Position p = c.deepEquivalent();
- Node* startNode = p.deprecatedNode();
- if (!startNode)
+ Position position = visiblePosition.deepEquivalent();
+ Node* startBlock;
+ if (!position.containerNode() || !(startBlock = enclosingBlock(position.containerNode(), rule)))
return VisiblePosition();
- return VisiblePosition(firstPositionInNode(startNode->enclosingBlockFlowElement()), DOWNSTREAM);
+ return firstPositionInNode(startBlock);
}
-VisiblePosition endOfBlock(const VisiblePosition &c)
+VisiblePosition endOfBlock(const VisiblePosition& visiblePosition, EditingBoundaryCrossingRule rule)
{
- Position p = c.deepEquivalent();
-
- Node* startNode = p.deprecatedNode();
- if (!startNode)
+ Position position = visiblePosition.deepEquivalent();
+ Node* endBlock;
+ if (!position.containerNode() || !(endBlock = enclosingBlock(position.containerNode(), rule)))
return VisiblePosition();
-
- Node *startBlock = startNode->enclosingBlockFlowElement();
-
- return VisiblePosition(lastPositionInNode(startBlock), VP_DEFAULT_AFFINITY);
+ return lastPositionInNode(endBlock);
}
bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
{
- return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
+ return !a.isNull() && enclosingBlock(a.deepEquivalent().containerNode()) == enclosingBlock(b.deepEquivalent().containerNode());
}
bool isStartOfBlock(const VisiblePosition &pos)
{
- return pos.isNotNull() && pos == startOfBlock(pos);
+ return pos.isNotNull() && pos == startOfBlock(pos, CanCrossEditingBoundary);
}
bool isEndOfBlock(const VisiblePosition &pos)
{
- return pos.isNotNull() && pos == endOfBlock(pos);
+ return pos.isNotNull() && pos == endOfBlock(pos, CanCrossEditingBoundary);
}
// ---------
@@ -1012,7 +1029,7 @@ VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
if (!highestRoot)
return VisiblePosition();
- return firstDeepEditingPositionForNode(highestRoot);
+ return firstPositionInNode(highestRoot);
}
VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
@@ -1021,88 +1038,7 @@ VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
if (!highestRoot)
return VisiblePosition();
- return lastDeepEditingPositionForNode(highestRoot);
-}
-
-static void getLeafBoxesInLogicalOrder(RootInlineBox* rootBox, Vector<InlineBox*>& leafBoxesInLogicalOrder)
-{
- unsigned char minLevel = 128;
- unsigned char maxLevel = 0;
- unsigned count = 0;
- InlineBox* r = rootBox->firstLeafChild();
- // First find highest and lowest levels,
- // and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
- while (r) {
- if (r->bidiLevel() > maxLevel)
- maxLevel = r->bidiLevel();
- if (r->bidiLevel() < minLevel)
- minLevel = r->bidiLevel();
- leafBoxesInLogicalOrder.append(r);
- r = r->nextLeafChild();
- ++count;
- }
-
- if (rootBox->renderer()->style()->visuallyOrdered())
- return;
- // Reverse of reordering of the line (L2 according to Bidi spec):
- // L2. From the highest level found in the text to the lowest odd level on each line,
- // reverse any contiguous sequence of characters that are at that level or higher.
-
- // Reversing the reordering of the line is only done up to the lowest odd level.
- if (!(minLevel % 2))
- minLevel++;
-
- InlineBox** end = leafBoxesInLogicalOrder.end();
- while (minLevel <= maxLevel) {
- InlineBox** iter = leafBoxesInLogicalOrder.begin();
- while (iter != end) {
- while (iter != end) {
- if ((*iter)->bidiLevel() >= minLevel)
- break;
- ++iter;
- }
- InlineBox** first = iter;
- while (iter != end) {
- if ((*iter)->bidiLevel() < minLevel)
- break;
- ++iter;
- }
- InlineBox** last = iter;
- std::reverse(first, last);
- }
- ++minLevel;
- }
-}
-
-static void getLogicalStartBoxAndNode(RootInlineBox* rootBox, InlineBox*& startBox, Node*& startNode)
-{
- Vector<InlineBox*> leafBoxesInLogicalOrder;
- getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
- startBox = 0;
- startNode = 0;
- for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) {
- startBox = leafBoxesInLogicalOrder[i];
- startNode = startBox->renderer()->node();
- if (startNode)
- return;
- }
-}
-
-static void getLogicalEndBoxAndNode(RootInlineBox* rootBox, InlineBox*& endBox, Node*& endNode)
-{
- Vector<InlineBox*> leafBoxesInLogicalOrder;
- getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
- endBox = 0;
- endNode = 0;
- // Generated content (e.g. list markers and CSS :before and :after
- // pseudoelements) have no corresponding DOM element, and so cannot be
- // represented by a VisiblePosition. Use whatever precedes instead.
- for (size_t i = leafBoxesInLogicalOrder.size(); i > 0; --i) {
- endBox = leafBoxesInLogicalOrder[i - 1];
- endNode = endBox->renderer()->node();
- if (endNode)
- return;
- }
+ return lastPositionInNode(highestRoot);
}
static VisiblePosition logicalStartPositionForLine(const VisiblePosition& c)
@@ -1122,8 +1058,7 @@ static VisiblePosition logicalStartPositionForLine(const VisiblePosition& c)
}
InlineBox* logicalStartBox;
- Node* logicalStartNode;
- getLogicalStartBoxAndNode(rootBox, logicalStartBox, logicalStartNode);
+ Node* logicalStartNode = rootBox->getLogicalStartBoxWithNode(logicalStartBox);
if (!logicalStartNode)
return VisiblePosition();
@@ -1158,8 +1093,8 @@ static VisiblePosition logicalEndPositionForLine(const VisiblePosition& c)
}
InlineBox* logicalEndBox;
- Node* logicalEndNode;
- getLogicalEndBoxAndNode(rootBox, logicalEndBox, logicalEndNode);
+ Node* logicalEndNode = rootBox->getLogicalEndBoxWithNode(logicalEndBox);
+
if (!logicalEndNode)
return VisiblePosition();
diff --git a/Source/WebCore/editing/visible_units.h b/Source/WebCore/editing/visible_units.h
index 167bd2c..18b9665 100644
--- a/Source/WebCore/editing/visible_units.h
+++ b/Source/WebCore/editing/visible_units.h
@@ -32,6 +32,7 @@
namespace WebCore {
+class RootInlineBox;
class VisiblePosition;
enum EWordSide { RightWordIfOnBoundary = false, LeftWordIfOnBoundary = true };
@@ -70,11 +71,11 @@ VisiblePosition previousParagraphPosition(const VisiblePosition &, int x);
VisiblePosition nextParagraphPosition(const VisiblePosition &, int x);
bool isStartOfParagraph(const VisiblePosition &, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
bool isEndOfParagraph(const VisiblePosition &, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
-bool inSameParagraph(const VisiblePosition &, const VisiblePosition &);
+bool inSameParagraph(const VisiblePosition &, const VisiblePosition &, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
// blocks (true paragraphs; line break elements don't break blocks)
-VisiblePosition startOfBlock(const VisiblePosition &);
-VisiblePosition endOfBlock(const VisiblePosition &);
+VisiblePosition startOfBlock(const VisiblePosition &, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
+VisiblePosition endOfBlock(const VisiblePosition &, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
bool inSameBlock(const VisiblePosition &, const VisiblePosition &);
bool isStartOfBlock(const VisiblePosition &);
bool isEndOfBlock(const VisiblePosition &);