summaryrefslogtreecommitdiffstats
path: root/WebCore/editing
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2009-12-15 10:12:09 +0000
committerSteve Block <steveblock@google.com>2009-12-17 17:41:10 +0000
commit643ca7872b450ea4efacab6188849e5aac2ba161 (patch)
tree6982576c228bcd1a7efe98afed544d840751094c /WebCore/editing
parentd026980fde6eb3b01c1fe49441174e89cd1be298 (diff)
downloadexternal_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.zip
external_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.tar.gz
external_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.tar.bz2
Merge webkit.org at r51976 : Initial merge by git.
Change-Id: Ib0e7e2f0fb4bee5a186610272edf3186f0986b43
Diffstat (limited to 'WebCore/editing')
-rw-r--r--WebCore/editing/AppendNodeCommand.cpp6
-rw-r--r--WebCore/editing/CompositeEditCommand.cpp14
-rw-r--r--WebCore/editing/DeleteButtonController.h2
-rw-r--r--WebCore/editing/DeleteFromTextNodeCommand.cpp6
-rw-r--r--WebCore/editing/DeleteSelectionCommand.cpp8
-rw-r--r--WebCore/editing/Editor.cpp90
-rw-r--r--WebCore/editing/IndentOutdentCommand.cpp75
-rw-r--r--WebCore/editing/IndentOutdentCommand.h4
-rw-r--r--WebCore/editing/InsertIntoTextNodeCommand.cpp6
-rw-r--r--WebCore/editing/InsertNodeBeforeCommand.cpp5
-rw-r--r--WebCore/editing/JoinTextNodesCommand.cpp6
-rw-r--r--WebCore/editing/MergeIdenticalElementsCommand.cpp4
-rw-r--r--WebCore/editing/RemoveNodeCommand.cpp4
-rw-r--r--WebCore/editing/SelectionController.cpp7
-rw-r--r--WebCore/editing/SplitElementCommand.cpp35
-rw-r--r--WebCore/editing/SplitElementCommand.h2
-rw-r--r--WebCore/editing/SplitTextNodeCommand.cpp9
-rw-r--r--WebCore/editing/TextIterator.cpp2
-rw-r--r--WebCore/editing/TypingCommand.cpp4
-rw-r--r--WebCore/editing/VisibleSelection.cpp2
-rw-r--r--WebCore/editing/WrapContentsInDummySpanCommand.cpp40
-rw-r--r--WebCore/editing/WrapContentsInDummySpanCommand.h2
-rw-r--r--WebCore/editing/htmlediting.cpp14
-rw-r--r--WebCore/editing/htmlediting.h1
-rw-r--r--WebCore/editing/visible_units.cpp11
25 files changed, 254 insertions, 105 deletions
diff --git a/WebCore/editing/AppendNodeCommand.cpp b/WebCore/editing/AppendNodeCommand.cpp
index ef79e9c..6178641 100644
--- a/WebCore/editing/AppendNodeCommand.cpp
+++ b/WebCore/editing/AppendNodeCommand.cpp
@@ -44,12 +44,18 @@ AppendNodeCommand::AppendNodeCommand(PassRefPtr<Element> parent, PassRefPtr<Node
void AppendNodeCommand::doApply()
{
+ if (!m_parent->isContentEditable() && m_parent->attached())
+ return;
+
ExceptionCode ec;
m_parent->appendChild(m_node.get(), ec);
}
void AppendNodeCommand::doUnapply()
{
+ if (!m_parent->isContentEditable())
+ return;
+
ExceptionCode ec;
m_node->remove(ec);
}
diff --git a/WebCore/editing/CompositeEditCommand.cpp b/WebCore/editing/CompositeEditCommand.cpp
index 1617be8..2796690 100644
--- a/WebCore/editing/CompositeEditCommand.cpp
+++ b/WebCore/editing/CompositeEditCommand.cpp
@@ -746,8 +746,9 @@ void CompositeEditCommand::cloneParagraphUnderNewElement(Position& start, Positi
{
// First we clone the outerNode
- RefPtr<Node> lastNode = outerNode->cloneNode(isTableElement(outerNode));
- appendNode(lastNode, blockElement);
+ RefPtr<Node> topNode = outerNode->cloneNode(isTableElement(outerNode));
+ appendNode(topNode, blockElement);
+ RefPtr<Node> lastNode = topNode;
if (start.node() != outerNode) {
Vector<RefPtr<Node> > ancestors;
@@ -769,12 +770,15 @@ void CompositeEditCommand::cloneParagraphUnderNewElement(Position& start, Positi
// Handle the case of paragraphs with more than one node,
// cloning all the siblings until end.node() is reached.
- if (start.node() != end.node()) {
- for (Node* n = start.node()->nextSibling(); n != NULL; n = n->nextSibling()) {
+ if (start.node() != end.node() && !start.node()->isDescendantOf(end.node())) {
+ for (Node* n = start.node()->traverseNextSibling(outerNode); n; n = n->nextSibling()) {
+ if (n->parentNode() != start.node()->parentNode())
+ lastNode = topNode->firstChild();
+
RefPtr<Node> clonedNode = n->cloneNode(true);
insertNodeAfter(clonedNode, lastNode);
lastNode = clonedNode.release();
- if (n == end.node())
+ if (n == end.node() || end.node()->isDescendantOf(n))
break;
}
}
diff --git a/WebCore/editing/DeleteButtonController.h b/WebCore/editing/DeleteButtonController.h
index 713ae8b..1286c07 100644
--- a/WebCore/editing/DeleteButtonController.h
+++ b/WebCore/editing/DeleteButtonController.h
@@ -36,7 +36,7 @@ class HTMLElement;
class RenderObject;
class VisibleSelection;
-class DeleteButtonController {
+class DeleteButtonController : public Noncopyable {
public:
DeleteButtonController(Frame*);
diff --git a/WebCore/editing/DeleteFromTextNodeCommand.cpp b/WebCore/editing/DeleteFromTextNodeCommand.cpp
index e942fef..f1d79af 100644
--- a/WebCore/editing/DeleteFromTextNodeCommand.cpp
+++ b/WebCore/editing/DeleteFromTextNodeCommand.cpp
@@ -45,6 +45,9 @@ void DeleteFromTextNodeCommand::doApply()
{
ASSERT(m_node);
+ if (!m_node->isContentEditable())
+ return;
+
ExceptionCode ec = 0;
m_text = m_node->substringData(m_offset, m_count, ec);
if (ec)
@@ -57,6 +60,9 @@ void DeleteFromTextNodeCommand::doUnapply()
{
ASSERT(m_node);
+ if (!m_node->isContentEditable())
+ return;
+
ExceptionCode ec;
m_node->insertData(m_offset, m_text, ec);
}
diff --git a/WebCore/editing/DeleteSelectionCommand.cpp b/WebCore/editing/DeleteSelectionCommand.cpp
index fbb5aea..9e4ba29 100644
--- a/WebCore/editing/DeleteSelectionCommand.cpp
+++ b/WebCore/editing/DeleteSelectionCommand.cpp
@@ -595,6 +595,14 @@ void DeleteSelectionCommand::mergeParagraphs()
return;
}
+ // Block images, tables and horizontal rules cannot be made inline with content at mergeDestination. If there is
+ // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the caret to just before the selection we deleted.
+ // See https://bugs.webkit.org/show_bug.cgi?id=25439
+ if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalent().node()) && !isStartOfParagraph(mergeDestination)) {
+ m_endingPosition = m_upstreamStart;
+ return;
+ }
+
RefPtr<Range> range = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(endOfParagraphToMove.deepEquivalent()));
RefPtr<Range> rangeToBeReplaced = Range::create(document(), rangeCompliantEquivalent(mergeDestination.deepEquivalent()), rangeCompliantEquivalent(mergeDestination.deepEquivalent()));
if (!document()->frame()->editor()->client()->shouldMoveRangeAfterDelete(range.get(), rangeToBeReplaced.get()))
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
index 3f3f736..0744fd6 100644
--- a/WebCore/editing/Editor.cpp
+++ b/WebCore/editing/Editor.cpp
@@ -30,6 +30,7 @@
#include "AXObjectCache.h"
#include "ApplyStyleCommand.h"
#include "CharacterNames.h"
+#include "CompositionEvent.h"
#include "CreateLinkCommand.h"
#include "CSSComputedStyleDeclaration.h"
#include "CSSMutableStyleDeclaration.h"
@@ -831,7 +832,7 @@ TriState Editor::selectionHasStyle(CSSStyleDeclaration* style) const
TriState nodeState = triStateOfStyleInComputedStyle(style, nodeStyle.get(), !node->isTextNode());
if (node == m_frame->selection()->start().node())
state = nodeState;
- else if (state != nodeState) {
+ else if (state != nodeState && node->isTextNode()) {
state = MixedTriState;
break;
}
@@ -1003,6 +1004,16 @@ bool Editor::insertParagraphSeparator()
return true;
}
+static bool nodeIsInTextFormControl(Node* node)
+{
+ if (!node)
+ return false;
+ Node* ancestor = node->shadowAncestorNode();
+ if (ancestor == node)
+ return false;
+ return ancestor->isElementNode() && static_cast<Element*>(ancestor)->isTextFormControl();
+}
+
void Editor::cut()
{
if (tryDHTMLCut())
@@ -1013,7 +1024,10 @@ void Editor::cut()
}
RefPtr<Range> selection = selectedRange();
if (shouldDeleteRange(selection.get())) {
- Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
+ if (nodeIsInTextFormControl(m_frame->selection()->start().node()))
+ Pasteboard::generalPasteboard()->writePlainText(m_frame->selectedText());
+ else
+ Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
didWriteSelectionToPasteboard();
deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
}
@@ -1027,13 +1041,17 @@ void Editor::copy()
systemBeep();
return;
}
-
- Document* document = m_frame->document();
- if (HTMLImageElement* imageElement = imageElementFromImageDocument(document))
- Pasteboard::generalPasteboard()->writeImage(imageElement, document->url(), document->title());
- else
- Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
-
+
+ if (nodeIsInTextFormControl(m_frame->selection()->start().node()))
+ Pasteboard::generalPasteboard()->writePlainText(m_frame->selectedText());
+ else {
+ Document* document = m_frame->document();
+ if (HTMLImageElement* imageElement = imageElementFromImageDocument(document))
+ Pasteboard::generalPasteboard()->writeImage(imageElement, document->url(), document->title());
+ else
+ Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
+ }
+
didWriteSelectionToPasteboard();
}
@@ -1353,6 +1371,16 @@ void Editor::confirmComposition(const String& text, bool preserveSelection)
return;
}
+ // Dispatch a compositionend event to the focused node.
+ // We should send this event before sending a TextEvent as written in Section 6.2.2 and 6.2.3 of
+ // the DOM Event specification.
+ Node* target = m_frame->document()->focusedNode();
+ if (target) {
+ RefPtr<CompositionEvent> event = CompositionEvent::create(eventNames().compositionendEvent, m_frame->domWindow(), text);
+ ExceptionCode ec = 0;
+ target->dispatchEvent(event, ec);
+ }
+
// If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
// will delete the old composition with an optimized replace operation.
if (text.isEmpty())
@@ -1379,7 +1407,38 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
setIgnoreCompositionSelectionChange(false);
return;
}
-
+
+ Node* target = m_frame->document()->focusedNode();
+ if (target) {
+ // Dispatch an appropriate composition event to the focused node.
+ // We check the composition status and choose an appropriate composition event since this
+ // function is used for three purposes:
+ // 1. Starting a new composition.
+ // Send a compositionstart event when this function creates a new composition node, i.e.
+ // m_compositionNode == 0 && !text.isEmpty().
+ // 2. Updating the existing composition node.
+ // Send a compositionupdate event when this function updates the existing composition
+ // node, i.e. m_compositionNode != 0 && !text.isEmpty().
+ // 3. Canceling the ongoing composition.
+ // Send a compositionend event when function deletes the existing composition node, i.e.
+ // m_compositionNode != 0 && test.isEmpty().
+ RefPtr<CompositionEvent> event;
+ if (!m_compositionNode) {
+ // We should send a compositionstart event only when the given text is not empty because this
+ // function doesn't create a composition node when the text is empty.
+ if (!text.isEmpty())
+ event = CompositionEvent::create(eventNames().compositionstartEvent, m_frame->domWindow(), text);
+ } else {
+ if (!text.isEmpty())
+ event = CompositionEvent::create(eventNames().compositionupdateEvent, m_frame->domWindow(), text);
+ else
+ event = CompositionEvent::create(eventNames().compositionendEvent, m_frame->domWindow(), text);
+ }
+ ExceptionCode ec = 0;
+ if (event.get())
+ target->dispatchEvent(event, ec);
+ }
+
// If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
// will delete the old composition with an optimized replace operation.
if (text.isEmpty())
@@ -1754,8 +1813,9 @@ static String findFirstMisspellingOrBadGrammarInRange(EditorClient* client, Rang
}
if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength)
break;
- setStart(paragraphRange.get(), startOfNextParagraph(paragraphRange->endPosition()));
- setEnd(paragraphRange.get(), endOfParagraph(paragraphRange->startPosition()));
+ VisiblePosition newParagraphStart = startOfNextParagraph(paragraphRange->endPosition());
+ setStart(paragraphRange.get(), newParagraphStart);
+ setEnd(paragraphRange.get(), endOfParagraph(newParagraphStart));
firstIteration = false;
totalLengthProcessed += currentLength;
}
@@ -2693,6 +2753,9 @@ bool Editor::insideVisibleArea(const IntPoint& point) const
return true;
RenderPart* renderer = frame->ownerRenderer();
+ if (!renderer)
+ return false;
+
RenderBlock* container = renderer->containingBlock();
if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
return true;
@@ -2719,6 +2782,9 @@ bool Editor::insideVisibleArea(Range* range) const
return true;
RenderPart* renderer = frame->ownerRenderer();
+ if (!renderer)
+ return false;
+
RenderBlock* container = renderer->containingBlock();
if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
return true;
diff --git a/WebCore/editing/IndentOutdentCommand.cpp b/WebCore/editing/IndentOutdentCommand.cpp
index 808a2f8..5e6f339 100644
--- a/WebCore/editing/IndentOutdentCommand.cpp
+++ b/WebCore/editing/IndentOutdentCommand.cpp
@@ -129,17 +129,8 @@ void IndentOutdentCommand::indentIntoBlockquote(const VisiblePosition& endOfCurr
targetBlockquote = 0;
}
-void IndentOutdentCommand::indentRegion()
+void IndentOutdentCommand::indentRegion(const VisiblePosition& startOfSelection, const VisiblePosition& endOfSelection)
{
- VisibleSelection selection = selectionForParagraphIteration(endingSelection());
- VisiblePosition startOfSelection = selection.visibleStart();
- VisiblePosition endOfSelection = selection.visibleEnd();
- int startIndex = indexForVisiblePosition(startOfSelection);
- int endIndex = indexForVisiblePosition(endOfSelection);
-
- ASSERT(!startOfSelection.isNull());
- ASSERT(!endOfSelection.isNull());
-
// Special case empty unsplittable elements because there's nothing to split
// and there's nothing to move.
Position start = startOfSelection.deepEquivalent().downstream();
@@ -162,6 +153,12 @@ void IndentOutdentCommand::indentRegion()
blockquoteForNextIndent = 0;
else
indentIntoBlockquote(endOfCurrentParagraph, endOfNextParagraph, blockquoteForNextIndent);
+
+ // indentIntoBlockquote could move more than one paragraph if the paragraph
+ // is in a list item or a table. As a result, endAfterSelection could refer to a position
+ // no longer in the document.
+ if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().node()->inDocument())
+ break;
// Sanity check: Make sure our moveParagraph calls didn't remove endOfNextParagraph.deepEquivalent().node()
// If somehow we did, return to prevent crashes.
if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().node()->inDocument()) {
@@ -169,14 +166,7 @@ void IndentOutdentCommand::indentRegion()
return;
}
endOfCurrentParagraph = endOfNextParagraph;
- }
-
- updateLayout();
-
- RefPtr<Range> startRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), startIndex, 0, true);
- RefPtr<Range> endRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), endIndex, 0, true);
- if (startRange && endRange)
- setEndingSelection(VisibleSelection(startRange->startPosition(), endRange->startPosition(), DOWNSTREAM));
+ }
}
void IndentOutdentCommand::outdentParagraph()
@@ -242,36 +232,40 @@ void IndentOutdentCommand::outdentParagraph()
moveParagraph(startOfParagraph(visibleStartOfParagraph), endOfParagraph(visibleEndOfParagraph), VisiblePosition(Position(placeholder.get(), 0)), true);
}
-void IndentOutdentCommand::outdentRegion()
+void IndentOutdentCommand::outdentRegion(const VisiblePosition& startOfSelection, const VisiblePosition& endOfSelection)
{
- VisiblePosition startOfSelection = endingSelection().visibleStart();
- VisiblePosition endOfSelection = endingSelection().visibleEnd();
VisiblePosition endOfLastParagraph = endOfParagraph(endOfSelection);
- ASSERT(!startOfSelection.isNull());
- ASSERT(!endOfSelection.isNull());
-
if (endOfParagraph(startOfSelection) == endOfLastParagraph) {
outdentParagraph();
return;
}
-
+
Position originalSelectionEnd = endingSelection().end();
- setEndingSelection(endingSelection().visibleStart());
- outdentParagraph();
- Position originalSelectionStart = endingSelection().start();
- VisiblePosition endOfCurrentParagraph = endOfParagraph(endOfParagraph(endingSelection().visibleStart()).next(true));
+ VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection);
VisiblePosition endAfterSelection = endOfParagraph(endOfParagraph(endOfSelection).next());
+
while (endOfCurrentParagraph != endAfterSelection) {
VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
if (endOfCurrentParagraph == endOfLastParagraph)
setEndingSelection(VisibleSelection(originalSelectionEnd, DOWNSTREAM));
else
setEndingSelection(endOfCurrentParagraph);
+
outdentParagraph();
+
+ // outdentParagraph could move more than one paragraph if the paragraph
+ // is in a list item. As a result, endAfterSelection and endOfNextParagraph
+ // could refer to positions no longer in the document.
+ if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().node()->inDocument())
+ break;
+
+ if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().node()->inDocument()) {
+ endOfCurrentParagraph = endingSelection().end();
+ endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
+ }
endOfCurrentParagraph = endOfNextParagraph;
}
- setEndingSelection(VisibleSelection(originalSelectionStart, endingSelection().end(), DOWNSTREAM));
}
void IndentOutdentCommand::doApply()
@@ -295,10 +289,27 @@ void IndentOutdentCommand::doApply()
if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(true)));
+ VisibleSelection selection = selectionForParagraphIteration(endingSelection());
+ VisiblePosition startOfSelection = selection.visibleStart();
+ VisiblePosition endOfSelection = selection.visibleEnd();
+
+ int startIndex = indexForVisiblePosition(startOfSelection);
+ int endIndex = indexForVisiblePosition(endOfSelection);
+
+ ASSERT(!startOfSelection.isNull());
+ ASSERT(!endOfSelection.isNull());
+
if (m_typeOfAction == Indent)
- indentRegion();
+ indentRegion(startOfSelection, endOfSelection);
else
- outdentRegion();
+ outdentRegion(startOfSelection, endOfSelection);
+
+ updateLayout();
+
+ RefPtr<Range> startRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), startIndex, 0, true);
+ RefPtr<Range> endRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), endIndex, 0, true);
+ if (startRange && endRange)
+ setEndingSelection(VisibleSelection(startRange->startPosition(), endRange->startPosition(), DOWNSTREAM));
}
}
diff --git a/WebCore/editing/IndentOutdentCommand.h b/WebCore/editing/IndentOutdentCommand.h
index 817b4c8..8705bf1 100644
--- a/WebCore/editing/IndentOutdentCommand.h
+++ b/WebCore/editing/IndentOutdentCommand.h
@@ -46,8 +46,8 @@ private:
virtual void doApply();
virtual EditAction editingAction() const { return m_typeOfAction == Indent ? EditActionIndent : EditActionOutdent; }
- void indentRegion();
- void outdentRegion();
+ void indentRegion(const VisiblePosition&, const VisiblePosition&);
+ void outdentRegion(const VisiblePosition&, const VisiblePosition&);
void outdentParagraph();
bool tryIndentingAsListItem(const VisiblePosition&);
void indentIntoBlockquote(const VisiblePosition&, const VisiblePosition&, RefPtr<Element>&);
diff --git a/WebCore/editing/InsertIntoTextNodeCommand.cpp b/WebCore/editing/InsertIntoTextNodeCommand.cpp
index 4905fae..9c3423a 100644
--- a/WebCore/editing/InsertIntoTextNodeCommand.cpp
+++ b/WebCore/editing/InsertIntoTextNodeCommand.cpp
@@ -43,12 +43,18 @@ InsertIntoTextNodeCommand::InsertIntoTextNodeCommand(PassRefPtr<Text> node, unsi
void InsertIntoTextNodeCommand::doApply()
{
+ if (!m_node->isContentEditable())
+ return;
+
ExceptionCode ec;
m_node->insertData(m_offset, m_text, ec);
}
void InsertIntoTextNodeCommand::doUnapply()
{
+ if (!m_node->isContentEditable())
+ return;
+
ExceptionCode ec;
m_node->deleteData(m_offset, m_text.length(), ec);
}
diff --git a/WebCore/editing/InsertNodeBeforeCommand.cpp b/WebCore/editing/InsertNodeBeforeCommand.cpp
index 4f60963..2ce9846 100644
--- a/WebCore/editing/InsertNodeBeforeCommand.cpp
+++ b/WebCore/editing/InsertNodeBeforeCommand.cpp
@@ -46,7 +46,7 @@ InsertNodeBeforeCommand::InsertNodeBeforeCommand(PassRefPtr<Node> insertChild, P
void InsertNodeBeforeCommand::doApply()
{
Node* parent = m_refChild->parentNode();
- if (!parent)
+ if (!parent || !parent->isContentEditable())
return;
ExceptionCode ec;
@@ -55,6 +55,9 @@ void InsertNodeBeforeCommand::doApply()
void InsertNodeBeforeCommand::doUnapply()
{
+ if (!m_insertChild->isContentEditable())
+ return;
+
ExceptionCode ec;
m_insertChild->remove(ec);
}
diff --git a/WebCore/editing/JoinTextNodesCommand.cpp b/WebCore/editing/JoinTextNodesCommand.cpp
index f981481..fa0987d 100644
--- a/WebCore/editing/JoinTextNodesCommand.cpp
+++ b/WebCore/editing/JoinTextNodesCommand.cpp
@@ -45,6 +45,10 @@ void JoinTextNodesCommand::doApply()
if (m_text1->nextSibling() != m_text2)
return;
+ Node* parent = m_text2->parentNode();
+ if (!parent || !parent->isContentEditable())
+ return;
+
ExceptionCode ec = 0;
m_text2->insertData(0, m_text1->data(), ec);
if (ec)
@@ -59,7 +63,7 @@ void JoinTextNodesCommand::doUnapply()
return;
Node* parent = m_text2->parentNode();
- if (!parent)
+ if (!parent || !parent->isContentEditable())
return;
ExceptionCode ec = 0;
diff --git a/WebCore/editing/MergeIdenticalElementsCommand.cpp b/WebCore/editing/MergeIdenticalElementsCommand.cpp
index 99ba286..f56f726 100644
--- a/WebCore/editing/MergeIdenticalElementsCommand.cpp
+++ b/WebCore/editing/MergeIdenticalElementsCommand.cpp
@@ -42,7 +42,7 @@ MergeIdenticalElementsCommand::MergeIdenticalElementsCommand(PassRefPtr<Element>
void MergeIdenticalElementsCommand::doApply()
{
- if (m_element1->nextSibling() != m_element2)
+ if (m_element1->nextSibling() != m_element2 || !m_element1->isContentEditable() || !m_element2->isContentEditable())
return;
m_atChild = m_element2->firstChild();
@@ -68,7 +68,7 @@ void MergeIdenticalElementsCommand::doUnapply()
RefPtr<Node> atChild = m_atChild.release();
Node* parent = m_element2->parent();
- if (!parent)
+ if (!parent || !parent->isContentEditable())
return;
ExceptionCode ec = 0;
diff --git a/WebCore/editing/RemoveNodeCommand.cpp b/WebCore/editing/RemoveNodeCommand.cpp
index 62a36be..f6d6a4b 100644
--- a/WebCore/editing/RemoveNodeCommand.cpp
+++ b/WebCore/editing/RemoveNodeCommand.cpp
@@ -42,7 +42,7 @@ RemoveNodeCommand::RemoveNodeCommand(PassRefPtr<Node> node)
void RemoveNodeCommand::doApply()
{
Node* parent = m_node->parentNode();
- if (!parent)
+ if (!parent || !parent->isContentEditable())
return;
m_parent = parent;
@@ -56,7 +56,7 @@ void RemoveNodeCommand::doUnapply()
{
RefPtr<Node> parent = m_parent.release();
RefPtr<Node> refChild = m_refChild.release();
- if (!parent)
+ if (!parent || !parent->isContentEditable())
return;
ExceptionCode ec;
diff --git a/WebCore/editing/SelectionController.cpp b/WebCore/editing/SelectionController.cpp
index 00672f2..af89ccb 100644
--- a/WebCore/editing/SelectionController.cpp
+++ b/WebCore/editing/SelectionController.cpp
@@ -994,11 +994,14 @@ void SelectionController::paintCaret(GraphicsContext* p, int tx, int ty, const I
IntRect caret = intersection(drawingRect, clipRect);
if (!caret.isEmpty()) {
Color caretColor = Color::black;
+ ColorSpace colorSpace = DeviceColorSpace;
Element* element = rootEditableElement();
- if (element && element->renderer())
+ if (element && element->renderer()) {
caretColor = element->renderer()->style()->color();
+ colorSpace = element->renderer()->style()->colorSpace();
+ }
- p->fillRect(caret, caretColor);
+ p->fillRect(caret, caretColor, colorSpace);
}
}
diff --git a/WebCore/editing/SplitElementCommand.cpp b/WebCore/editing/SplitElementCommand.cpp
index 35dfc6f..2998c6a 100644
--- a/WebCore/editing/SplitElementCommand.cpp
+++ b/WebCore/editing/SplitElementCommand.cpp
@@ -41,35 +41,39 @@ SplitElementCommand::SplitElementCommand(PassRefPtr<Element> element, PassRefPtr
ASSERT(m_atChild->parentNode() == m_element2);
}
-void SplitElementCommand::doApply()
+void SplitElementCommand::executeApply()
{
- RefPtr<Element> prefixElement = m_element2->cloneElementWithoutChildren();
-
if (m_atChild->parentNode() != m_element2)
return;
-
+
Vector<RefPtr<Node> > children;
for (Node* node = m_element2->firstChild(); node != m_atChild; node = node->nextSibling())
children.append(node);
-
+
ExceptionCode ec = 0;
-
+
Node* parent = m_element2->parentNode();
- if (!parent)
+ if (!parent || !parent->isContentEditable())
return;
- parent->insertBefore(prefixElement.get(), m_element2.get(), ec);
+ parent->insertBefore(m_element1.get(), m_element2.get(), ec);
if (ec)
return;
- m_element1 = prefixElement.release();
-
+
size_t size = children.size();
for (size_t i = 0; i < size; ++i)
m_element1->appendChild(children[i], ec);
}
+
+void SplitElementCommand::doApply()
+{
+ m_element1 = m_element2->cloneElementWithoutChildren();
+
+ executeApply();
+}
void SplitElementCommand::doUnapply()
{
- if (!m_element1)
+ if (!m_element1 || !m_element1->isContentEditable() || !m_element2->isContentEditable())
return;
Vector<RefPtr<Node> > children;
@@ -85,7 +89,14 @@ void SplitElementCommand::doUnapply()
m_element2->insertBefore(children[i].get(), refChild.get(), ec);
m_element1->remove(ec);
- m_element1 = 0;
}
+void SplitElementCommand::doReapply()
+{
+ if (!m_element1)
+ return;
+
+ executeApply();
+}
+
} // namespace WebCore
diff --git a/WebCore/editing/SplitElementCommand.h b/WebCore/editing/SplitElementCommand.h
index 2732762..7ea8f5b 100644
--- a/WebCore/editing/SplitElementCommand.h
+++ b/WebCore/editing/SplitElementCommand.h
@@ -42,6 +42,8 @@ private:
virtual void doApply();
virtual void doUnapply();
+ virtual void doReapply();
+ void executeApply();
RefPtr<Element> m_element1;
RefPtr<Element> m_element2;
diff --git a/WebCore/editing/SplitTextNodeCommand.cpp b/WebCore/editing/SplitTextNodeCommand.cpp
index 3b04e01..15daa49 100644
--- a/WebCore/editing/SplitTextNodeCommand.cpp
+++ b/WebCore/editing/SplitTextNodeCommand.cpp
@@ -49,6 +49,10 @@ SplitTextNodeCommand::SplitTextNodeCommand(PassRefPtr<Text> text, int offset)
void SplitTextNodeCommand::doApply()
{
+ Node* parent = m_text2->parentNode();
+ if (!parent || !parent->isContentEditable())
+ return;
+
ExceptionCode ec = 0;
String prefixText = m_text2->substringData(0, m_offset, ec);
@@ -59,9 +63,6 @@ void SplitTextNodeCommand::doApply()
ASSERT(prefixTextNode);
document()->copyMarkers(m_text2.get(), 0, m_offset, prefixTextNode.get(), 0);
- Node* parent = m_text2->parentNode();
- if (!parent)
- return;
parent->insertBefore(prefixTextNode.get(), m_text2.get(), ec);
if (ec)
return;
@@ -72,7 +73,7 @@ void SplitTextNodeCommand::doApply()
void SplitTextNodeCommand::doUnapply()
{
- if (!m_text1)
+ if (!m_text1 || !m_text1->isContentEditable())
return;
ASSERT(m_text1->document() == document());
diff --git a/WebCore/editing/TextIterator.cpp b/WebCore/editing/TextIterator.cpp
index d36849c..df271b6 100644
--- a/WebCore/editing/TextIterator.cpp
+++ b/WebCore/editing/TextIterator.cpp
@@ -218,7 +218,7 @@ static void pushFullyClippedState(BitStack& stack, Node* node)
// Push true if this node full clips its contents, or if a parent already has fully
// clipped and this is not a node that ignores its container's clip.
- stack.push(fullyClipsContents(node) || stack.top() && !ignoresContainerClip(node));
+ stack.push(fullyClipsContents(node) || (stack.top() && !ignoresContainerClip(node)));
}
static void setUpFullyClippedStack(BitStack& stack, Node* node)
diff --git a/WebCore/editing/TypingCommand.cpp b/WebCore/editing/TypingCommand.cpp
index f5901d7..2b0f61e 100644
--- a/WebCore/editing/TypingCommand.cpp
+++ b/WebCore/editing/TypingCommand.cpp
@@ -90,7 +90,7 @@ void TypingCommand::deleteKeyPressed(Document *document, bool smartDelete, TextG
ASSERT(frame);
EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand)) {
+ if (granularity == CharacterGranularity && isOpenForMoreTypingCommand(lastEditCommand)) {
static_cast<TypingCommand*>(lastEditCommand)->deleteKeyPressed(granularity, killRing);
return;
}
@@ -109,7 +109,7 @@ void TypingCommand::forwardDeleteKeyPressed(Document *document, bool smartDelete
ASSERT(frame);
EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand)) {
+ if (granularity == CharacterGranularity && isOpenForMoreTypingCommand(lastEditCommand)) {
static_cast<TypingCommand*>(lastEditCommand)->forwardDeleteKeyPressed(granularity, killRing);
return;
}
diff --git a/WebCore/editing/VisibleSelection.cpp b/WebCore/editing/VisibleSelection.cpp
index 206de86..68d5a3e 100644
--- a/WebCore/editing/VisibleSelection.cpp
+++ b/WebCore/editing/VisibleSelection.cpp
@@ -237,7 +237,7 @@ void VisibleSelection::appendTrailingWhitespace()
for (; charIt.length(); charIt.advance(1)) {
UChar c = charIt.characters()[0];
- if (!isSpaceOrNewline(c) && c != noBreakSpace || c == '\n')
+ if ((!isSpaceOrNewline(c) && c != noBreakSpace) || c == '\n')
break;
m_end = charIt.range()->endPosition();
}
diff --git a/WebCore/editing/WrapContentsInDummySpanCommand.cpp b/WebCore/editing/WrapContentsInDummySpanCommand.cpp
index 7622c1e..5fa0b39 100644
--- a/WebCore/editing/WrapContentsInDummySpanCommand.cpp
+++ b/WebCore/editing/WrapContentsInDummySpanCommand.cpp
@@ -38,35 +38,37 @@ WrapContentsInDummySpanCommand::WrapContentsInDummySpanCommand(PassRefPtr<Elemen
ASSERT(m_element);
}
-void WrapContentsInDummySpanCommand::doApply()
+void WrapContentsInDummySpanCommand::executeApply()
{
Vector<RefPtr<Node> > children;
for (Node* child = m_element->firstChild(); child; child = child->nextSibling())
children.append(child);
-
- RefPtr<HTMLElement> span = createStyleSpanElement(document());
-
+
ExceptionCode ec;
-
+
size_t size = children.size();
for (size_t i = 0; i < size; ++i)
- span->appendChild(children[i].release(), ec);
-
- m_element->appendChild(span.get(), ec);
-
- m_dummySpan = span.release();
+ m_dummySpan->appendChild(children[i].release(), ec);
+
+ m_element->appendChild(m_dummySpan.get(), ec);
}
+void WrapContentsInDummySpanCommand::doApply()
+{
+ m_dummySpan = createStyleSpanElement(document());
+
+ executeApply();
+}
+
void WrapContentsInDummySpanCommand::doUnapply()
{
ASSERT(m_element);
- RefPtr<HTMLElement> span = m_dummySpan.release();
- if (!span)
+ if (!m_dummySpan || !m_element->isContentEditable())
return;
Vector<RefPtr<Node> > children;
- for (Node* child = span->firstChild(); child; child = child->nextSibling())
+ for (Node* child = m_dummySpan->firstChild(); child; child = child->nextSibling())
children.append(child);
ExceptionCode ec;
@@ -75,7 +77,17 @@ void WrapContentsInDummySpanCommand::doUnapply()
for (size_t i = 0; i < size; ++i)
m_element->appendChild(children[i].release(), ec);
- span->remove(ec);
+ m_dummySpan->remove(ec);
}
+void WrapContentsInDummySpanCommand::doReapply()
+{
+ ASSERT(m_element);
+
+ if (!m_dummySpan || !m_element->isContentEditable())
+ return;
+
+ executeApply();
+}
+
} // namespace WebCore
diff --git a/WebCore/editing/WrapContentsInDummySpanCommand.h b/WebCore/editing/WrapContentsInDummySpanCommand.h
index b12131a..be3af66 100644
--- a/WebCore/editing/WrapContentsInDummySpanCommand.h
+++ b/WebCore/editing/WrapContentsInDummySpanCommand.h
@@ -44,6 +44,8 @@ private:
virtual void doApply();
virtual void doUnapply();
+ virtual void doReapply();
+ void executeApply();
RefPtr<Element> m_element;
RefPtr<HTMLElement> m_dummySpan;
diff --git a/WebCore/editing/htmlediting.cpp b/WebCore/editing/htmlediting.cpp
index d19ef6b..8b1c98d 100644
--- a/WebCore/editing/htmlediting.cpp
+++ b/WebCore/editing/htmlediting.cpp
@@ -289,7 +289,7 @@ VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& positio
while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
p = isAtomicNode(p.node()) ? positionInParentAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
- if (p.node() && !p.node()->isDescendantOf(highestRoot))
+ if (p.node() && p.node() != highestRoot && !p.node()->isDescendantOf(highestRoot))
return VisiblePosition();
return VisiblePosition(p);
@@ -310,7 +310,7 @@ VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& positio
while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
p = isAtomicNode(p.node()) ? positionInParentBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
- if (p.node() && !p.node()->isDescendantOf(highestRoot))
+ if (p.node() && p.node() != highestRoot && !p.node()->isDescendantOf(highestRoot))
return VisiblePosition();
return VisiblePosition(p);
@@ -494,6 +494,7 @@ bool validBlockTag(const AtomicString& blockTag)
static Node* firstInSpecialElement(const Position& pos)
{
+ // FIXME: This begins at pos.node(), which doesn't necessarily contain pos (suppose pos was [img, 0]). See <rdar://problem/5027702>.
Node* rootEditableElement = pos.node()->rootEditableElement();
for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
if (isSpecialElement(n)) {
@@ -509,6 +510,7 @@ static Node* firstInSpecialElement(const Position& pos)
static Node* lastInSpecialElement(const Position& pos)
{
+ // FIXME: This begins at pos.node(), which doesn't necessarily contain pos (suppose pos was [img, 0]). See <rdar://problem/5027702>.
Node* rootEditableElement = pos.node()->rootEditableElement();
for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
if (isSpecialElement(n)) {
@@ -1077,6 +1079,14 @@ bool isNodeVisiblyContainedWithin(Node* node, const Range* selectedRange)
&& visiblePositionAfterNode(node) == selectedRange->endPosition();
}
+bool isRenderedAsNonInlineTableImageOrHR(const Node* node)
+{
+ if (!node)
+ return false;
+ RenderObject* renderer = node->renderer();
+ return renderer && ((renderer->isTable() && !renderer->isInline()) || (renderer->isImage() && !renderer->isInline()) || renderer->isHR());
+}
+
PassRefPtr<Range> avoidIntersectionWithNode(const Range* range, Node* node)
{
if (!range)
diff --git a/WebCore/editing/htmlediting.h b/WebCore/editing/htmlediting.h
index f44181c..43048e0 100644
--- a/WebCore/editing/htmlediting.h
+++ b/WebCore/editing/htmlediting.h
@@ -91,6 +91,7 @@ bool isTableStructureNode(const Node*);
bool isListElement(Node*);
bool isNodeRendered(const Node*);
bool isNodeVisiblyContainedWithin(Node*, const Range*);
+bool isRenderedAsNonInlineTableImageOrHR(const Node*);
// -------------------------------------------------------------------------
diff --git a/WebCore/editing/visible_units.cpp b/WebCore/editing/visible_units.cpp
index c96fdfd..84ace83 100644
--- a/WebCore/editing/visible_units.cpp
+++ b/WebCore/editing/visible_units.cpp
@@ -776,12 +776,6 @@ VisiblePosition nextSentencePosition(const VisiblePosition &c)
return c.honorEditableBoundaryAtOrBefore(next);
}
-static bool renderedAsNonInlineTableOrHR(RenderObject* renderer)
-{
- return renderer && ((renderer->isTable() && !renderer->isInline()) || renderer->isHR());
-}
-
-// FIXME: Broken for positions before/after images that aren't inline (5027702)
VisiblePosition startOfParagraph(const VisiblePosition& c)
{
Position p = c.deepEquivalent();
@@ -790,7 +784,7 @@ VisiblePosition startOfParagraph(const VisiblePosition& c)
if (!startNode)
return VisiblePosition();
- if (renderedAsNonInlineTableOrHR(startNode->renderer()) && p.atLastEditingPositionForNode())
+ if (isRenderedAsNonInlineTableImageOrHR(startNode))
return firstDeepEditingPositionForNode(startNode);
Node* startBlock = enclosingBlock(startNode);
@@ -841,7 +835,6 @@ VisiblePosition startOfParagraph(const VisiblePosition& c)
return VisiblePosition(node, offset, DOWNSTREAM);
}
-// FIXME: Broken for positions before/after images that aren't inline (5027702)
VisiblePosition endOfParagraph(const VisiblePosition &c)
{
if (c.isNull())
@@ -850,7 +843,7 @@ VisiblePosition endOfParagraph(const VisiblePosition &c)
Position p = c.deepEquivalent();
Node* startNode = p.node();
- if (renderedAsNonInlineTableOrHR(startNode->renderer()) && p.atFirstEditingPositionForNode())
+ if (isRenderedAsNonInlineTableImageOrHR(startNode))
return lastDeepEditingPositionForNode(startNode);
Node* startBlock = enclosingBlock(startNode);