diff options
author | Steve Block <steveblock@google.com> | 2009-12-15 10:12:09 +0000 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2009-12-17 17:41:10 +0000 |
commit | 643ca7872b450ea4efacab6188849e5aac2ba161 (patch) | |
tree | 6982576c228bcd1a7efe98afed544d840751094c /WebCore/editing | |
parent | d026980fde6eb3b01c1fe49441174e89cd1be298 (diff) | |
download | external_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')
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); |