diff options
Diffstat (limited to 'Source/WebCore/editing')
| -rw-r--r-- | Source/WebCore/editing/CompositeEditCommand.cpp | 4 | ||||
| -rw-r--r-- | Source/WebCore/editing/Editor.cpp | 7 | ||||
| -rw-r--r-- | Source/WebCore/editing/ReplaceSelectionCommand.cpp | 17 | ||||
| -rw-r--r-- | Source/WebCore/editing/ReplaceSelectionCommand.h | 5 | ||||
| -rw-r--r-- | Source/WebCore/editing/TextIterator.cpp | 2 | ||||
| -rw-r--r-- | Source/WebCore/editing/VisibleSelection.cpp | 6 | ||||
| -rw-r--r-- | Source/WebCore/editing/markup.cpp | 80 | ||||
| -rw-r--r-- | Source/WebCore/editing/markup.h | 6 | ||||
| -rw-r--r-- | Source/WebCore/editing/visible_units.cpp | 9 | ||||
| -rw-r--r-- | Source/WebCore/editing/visible_units.h | 1 |
10 files changed, 111 insertions, 26 deletions
diff --git a/Source/WebCore/editing/CompositeEditCommand.cpp b/Source/WebCore/editing/CompositeEditCommand.cpp index 5a8a44e6f..f82b298b5 100644 --- a/Source/WebCore/editing/CompositeEditCommand.cpp +++ b/Source/WebCore/editing/CompositeEditCommand.cpp @@ -929,8 +929,8 @@ PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar // We can bail as we have a full block to work with. ASSERT(upstreamStart.deprecatedNode()->isDescendantOf(enclosingBlock(upstreamEnd.deprecatedNode()))); return 0; - } else if (isEndOfDocument(visibleEnd)) { - // At the end of the document. We can bail here as well. + } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { + // At the end of the editable region. We can bail here as well. return 0; } } diff --git a/Source/WebCore/editing/Editor.cpp b/Source/WebCore/editing/Editor.cpp index cde883e1c..6f4548163 100644 --- a/Source/WebCore/editing/Editor.cpp +++ b/Source/WebCore/editing/Editor.cpp @@ -946,7 +946,7 @@ bool Editor::insertLineBreak() return true; VisiblePosition caret = m_frame->selection()->selection().visibleStart(); - bool alignToEdge = isEndOfDocument(caret); + bool alignToEdge = isEndOfEditableOrNonEditableContent(caret); bool autocorrectionIsApplied = m_alternativeTextController->applyAutocorrectionBeforeTypingIfAppropriate(); TypingCommand::insertLineBreak(m_frame->document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0); revealSelectionAfterEditingOperation(alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded : ScrollAlignment::alignCenterIfNeeded); @@ -966,7 +966,7 @@ bool Editor::insertParagraphSeparator() return true; VisiblePosition caret = m_frame->selection()->selection().visibleStart(); - bool alignToEdge = isEndOfDocument(caret); + bool alignToEdge = isEndOfEditableOrNonEditableContent(caret); bool autocorrectionIsApplied = m_alternativeTextController->applyAutocorrectionBeforeTypingIfAppropriate(); TypingCommand::insertParagraphSeparator(m_frame->document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0); revealSelectionAfterEditingOperation(alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded : ScrollAlignment::alignCenterIfNeeded); @@ -1996,6 +1996,7 @@ void Editor::markAndReplaceFor(PassRefPtr<SpellCheckRequest> request, const Vect bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; + bool shouldMarkLink = textCheckingOptions & TextCheckingTypeLink; bool shouldPerformReplacement = textCheckingOptions & TextCheckingTypeReplacement; bool shouldShowCorrectionPanel = textCheckingOptions & TextCheckingTypeShowCorrectionPanel; bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & TextCheckingTypeCorrection); @@ -2080,7 +2081,7 @@ void Editor::markAndReplaceFor(PassRefPtr<SpellCheckRequest> request, const Vect if (result->type == TextCheckingTypeLink && selectionOffset > resultLocation + resultLength + 1) continue; - if (!(shouldPerformReplacement || shouldShowCorrectionPanel) || !doReplacement) + if (!(shouldPerformReplacement || shouldShowCorrectionPanel || shouldMarkLink) || !doReplacement) continue; String replacedString = plainText(rangeToReplace.get()); diff --git a/Source/WebCore/editing/ReplaceSelectionCommand.cpp b/Source/WebCore/editing/ReplaceSelectionCommand.cpp index 75f4434f3..ab33ad9ab 100644 --- a/Source/WebCore/editing/ReplaceSelectionCommand.cpp +++ b/Source/WebCore/editing/ReplaceSelectionCommand.cpp @@ -830,7 +830,7 @@ void ReplaceSelectionCommand::doApply() visibleStart = endingSelection().visibleStart(); if (fragment.hasInterchangeNewlineAtStart()) { if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) { - if (!isEndOfDocument(visibleStart)) + if (!isEndOfEditableOrNonEditableContent(visibleStart)) setEndingSelection(visibleStart.next()); } else insertParagraphSeparator(); @@ -936,7 +936,10 @@ void ReplaceSelectionCommand::doApply() if (RefPtr<Node> nodeToSplitTo = nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(insertionPos)) { if (insertionPos.containerNode() != nodeToSplitTo->parentNode()) { - nodeToSplitTo = splitTreeToNode(insertionPos.anchorNode(), nodeToSplitTo->parentNode()).get(); + Node* splitStart = insertionPos.computeNodeAfterPosition(); + if (!splitStart) + splitStart = insertionPos.containerNode(); + nodeToSplitTo = splitTreeToNode(splitStart, nodeToSplitTo->parentNode()).get(); insertionPos = positionInParentBeforeNode(nodeToSplitTo.get()); } } @@ -964,7 +967,7 @@ void ReplaceSelectionCommand::doApply() Node* blockStart = enclosingBlock(insertionPos.deprecatedNode()); if ((isListElement(refNode.get()) || (isLegacyAppleStyleSpan(refNode.get()) && isListElement(refNode->firstChild()))) && blockStart && blockStart->renderer()->isListItem()) - refNode = insertAsListItems(refNode, blockStart, insertionPos, insertedNodes); + refNode = insertAsListItems(toHTMLElement(refNode.get()), blockStart, insertionPos, insertedNodes); else { insertNodeAt(refNode, insertionPos); insertedNodes.respondToNodeInsertion(refNode.get()); @@ -1229,12 +1232,12 @@ EditAction ReplaceSelectionCommand::editingAction() const // If the user is inserting a list into an existing list, instead of nesting the list, // we put the list items into the existing list. -Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<Node> prpListElement, Node* insertionBlock, const Position& insertPos, InsertedNodes& insertedNodes) +Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<HTMLElement> prpListElement, Node* insertionBlock, const Position& insertPos, InsertedNodes& insertedNodes) { - RefPtr<Node> listElement = prpListElement; + RefPtr<HTMLElement> listElement = prpListElement; while (listElement->hasChildNodes() && isListElement(listElement->firstChild()) && listElement->childNodeCount() == 1) - listElement = listElement->firstChild(); + listElement = toHTMLElement(listElement->firstChild()); bool isStart = isStartOfParagraph(insertPos); bool isEnd = isEndOfParagraph(insertPos); @@ -1252,7 +1255,7 @@ Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<Node> prpListElement while (RefPtr<Node> listItem = listElement->firstChild()) { ExceptionCode ec = 0; - toContainerNode(listElement.get())->removeChild(listItem.get(), ec); + listElement->removeChild(listItem.get(), ec); ASSERT(!ec); if (isStart || isMiddle) { insertNodeBefore(listItem, lastNode); diff --git a/Source/WebCore/editing/ReplaceSelectionCommand.h b/Source/WebCore/editing/ReplaceSelectionCommand.h index 3a0b5a516..d56c5119a 100644 --- a/Source/WebCore/editing/ReplaceSelectionCommand.h +++ b/Source/WebCore/editing/ReplaceSelectionCommand.h @@ -31,10 +31,7 @@ namespace WebCore { class DocumentFragment; -class EditingStyle; -class Node; class ReplacementFragment; -class StylePropertySet; class ReplaceSelectionCommand : public CompositeEditCommand { public: @@ -75,7 +72,7 @@ private: RefPtr<Node> m_lastNodeInserted; }; - Node* insertAsListItems(PassRefPtr<Node>, Node* insertionNode, const Position&, InsertedNodes&); + Node* insertAsListItems(PassRefPtr<HTMLElement> listElement, Node* insertionNode, const Position&, InsertedNodes&); void updateNodesInserted(Node*); bool shouldRemoveEndBR(Node*, const VisiblePosition&); diff --git a/Source/WebCore/editing/TextIterator.cpp b/Source/WebCore/editing/TextIterator.cpp index 3f2000d41..b3b84a75e 100644 --- a/Source/WebCore/editing/TextIterator.cpp +++ b/Source/WebCore/editing/TextIterator.cpp @@ -1734,7 +1734,7 @@ static inline void unlockSearcher() // ICU's search ignores the distinction between small kana letters and ones // that are not small, and also characters that differ only in the voicing -// marks when considering only primary collation strength diffrences. +// marks when considering only primary collation strength differences. // This is not helpful for end users, since these differences make words // distinct, so for our purposes we need these to be considered. // The Unicode folks do not think the collation algorithm should be diff --git a/Source/WebCore/editing/VisibleSelection.cpp b/Source/WebCore/editing/VisibleSelection.cpp index 6e68c350b..2971498f3 100644 --- a/Source/WebCore/editing/VisibleSelection.cpp +++ b/Source/WebCore/editing/VisibleSelection.cpp @@ -293,11 +293,11 @@ void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(Text VisiblePosition start = VisiblePosition(m_start, m_affinity); VisiblePosition originalEnd(m_end, m_affinity); EWordSide side = RightWordIfOnBoundary; - if (isEndOfDocument(start) || (isEndOfLine(start) && !isStartOfLine(start) && !isEndOfParagraph(start))) + if (isEndOfEditableOrNonEditableContent(start) || (isEndOfLine(start) && !isStartOfLine(start) && !isEndOfParagraph(start))) side = LeftWordIfOnBoundary; m_start = startOfWord(start, side).deepEquivalent(); side = RightWordIfOnBoundary; - if (isEndOfDocument(originalEnd) || (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd))) + if (isEndOfEditableOrNonEditableContent(originalEnd) || (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd))) side = LeftWordIfOnBoundary; VisiblePosition wordEnd(endOfWord(originalEnd, side)); @@ -349,7 +349,7 @@ void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(Text break; case ParagraphGranularity: { VisiblePosition pos(m_start, m_affinity); - if (isStartOfLine(pos) && isEndOfDocument(pos)) + if (isStartOfLine(pos) && isEndOfEditableOrNonEditableContent(pos)) pos = pos.previous(); m_start = startOfParagraph(pos).deepEquivalent(); VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition(m_end, m_affinity)); diff --git a/Source/WebCore/editing/markup.cpp b/Source/WebCore/editing/markup.cpp index a1c5a3362..4983dcd4d 100644 --- a/Source/WebCore/editing/markup.cpp +++ b/Source/WebCore/editing/markup.cpp @@ -665,7 +665,7 @@ PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document* document, const { // We use a fake body element here to trick the HTML parser to using the InBody insertion mode. RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(document); - RefPtr<DocumentFragment> fragment = Range::createDocumentFragmentForElement(markup, fakeBody.get(), scriptingPermission); + RefPtr<DocumentFragment> fragment = createContextualFragment(markup, fakeBody.get(), scriptingPermission); if (fragment && !baseURL.isEmpty() && baseURL != blankURL() && baseURL != document->baseURL()) completeURLs(fragment.get(), baseURL); @@ -992,7 +992,7 @@ String urlToMarkup(const KURL& url, const String& title) return markup.toString(); } -PassRefPtr<DocumentFragment> createFragmentFromSource(const String& markup, Element* contextElement, ExceptionCode& ec) +PassRefPtr<DocumentFragment> createFragmentForInnerOuterHTML(const String& markup, Element* contextElement, ExceptionCode& ec) { Document* document = contextElement->document(); RefPtr<DocumentFragment> fragment = DocumentFragment::create(document); @@ -1010,6 +1010,82 @@ PassRefPtr<DocumentFragment> createFragmentFromSource(const String& markup, Elem return fragment.release(); } +PassRefPtr<DocumentFragment> createFragmentForTransformToFragment(const String& sourceString, const String& sourceMIMEType, Document* outputDoc) +{ + RefPtr<DocumentFragment> fragment = outputDoc->createDocumentFragment(); + + if (sourceMIMEType == "text/html") { + // As far as I can tell, there isn't a spec for how transformToFragment is supposed to work. + // Based on the documentation I can find, it looks like we want to start parsing the fragment in the InBody insertion mode. + // Unfortunately, that's an implementation detail of the parser. + // We achieve that effect here by passing in a fake body element as context for the fragment. + RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(outputDoc); + fragment->parseHTML(sourceString, fakeBody.get()); + } else if (sourceMIMEType == "text/plain") + fragment->parserAddChild(Text::create(outputDoc, sourceString)); + else { + bool successfulParse = fragment->parseXML(sourceString, 0); + if (!successfulParse) + return 0; + } + + // FIXME: Do we need to mess with URLs here? + + return fragment.release(); +} + +static inline void removeElementPreservingChildren(PassRefPtr<DocumentFragment> fragment, HTMLElement* element) +{ + ExceptionCode ignoredExceptionCode; + + RefPtr<Node> nextChild; + for (RefPtr<Node> child = element->firstChild(); child; child = nextChild) { + nextChild = child->nextSibling(); + element->removeChild(child.get(), ignoredExceptionCode); + ASSERT(!ignoredExceptionCode); + fragment->insertBefore(child, element, ignoredExceptionCode); + ASSERT(!ignoredExceptionCode); + } + fragment->removeChild(element, ignoredExceptionCode); + ASSERT(!ignoredExceptionCode); +} + +PassRefPtr<DocumentFragment> createContextualFragment(const String& markup, Element* element, FragmentScriptingPermission scriptingPermission) +{ + ASSERT(element); + HTMLElement* htmlElement = toHTMLElement(element); + if (htmlElement->ieForbidsInsertHTML()) + return 0; + + if (htmlElement->hasLocalName(colTag) || htmlElement->hasLocalName(colgroupTag) || htmlElement->hasLocalName(framesetTag) + || htmlElement->hasLocalName(headTag) || htmlElement->hasLocalName(styleTag) || htmlElement->hasLocalName(titleTag)) + return 0; + + // FIXME: This code is almost identical to createFragmentForInnerOuterHTML except this code doesn't handle exceptions. + RefPtr<DocumentFragment> fragment = element->document()->createDocumentFragment(); + + if (element->document()->isHTMLDocument()) + fragment->parseHTML(markup, element, scriptingPermission); + else if (!fragment->parseXML(markup, element, scriptingPermission)) + return 0; // FIXME: We should propagate a syntax error exception out here. + + // We need to pop <html> and <body> elements and remove <head> to + // accommodate folks passing complete HTML documents to make the + // child of an element. + + RefPtr<Node> nextNode; + for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) { + nextNode = node->nextSibling(); + if (node->hasTagName(htmlTag) || node->hasTagName(headTag) || node->hasTagName(bodyTag)) { + HTMLElement* element = toHTMLElement(node.get()); + if (Node* firstChild = element->firstChild()) + nextNode = firstChild; + removeElementPreservingChildren(fragment, element); + } + } + return fragment.release(); +} + static inline bool hasOneChild(ContainerNode* node) { Node* firstChild = node->firstChild(); diff --git a/Source/WebCore/editing/markup.h b/Source/WebCore/editing/markup.h index 625fd6eb4..a36cb350a 100644 --- a/Source/WebCore/editing/markup.h +++ b/Source/WebCore/editing/markup.h @@ -48,10 +48,12 @@ namespace WebCore { enum EAbsoluteURLs { DoNotResolveURLs, ResolveAllURLs, ResolveNonLocalURLs }; PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String& text); - PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document*, const String& markup, const String& baseURL, FragmentScriptingPermission = FragmentScriptingAllowed); + PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document*, const String& markup, const String& baseURL, FragmentScriptingPermission = AllowScriptingContent); PassRefPtr<DocumentFragment> createFragmentFromMarkupWithContext(Document*, const String& markup, unsigned fragmentStart, unsigned fragmentEnd, const String& baseURL, FragmentScriptingPermission); PassRefPtr<DocumentFragment> createFragmentFromNodes(Document*, const Vector<Node*>&); - PassRefPtr<DocumentFragment> createFragmentFromSource(const String&, Element*, ExceptionCode&); + PassRefPtr<DocumentFragment> createFragmentForInnerOuterHTML(const String&, Element*, ExceptionCode&); + PassRefPtr<DocumentFragment> createFragmentForTransformToFragment(const String&, const String& sourceMIMEType, Document* outputDoc); + PassRefPtr<DocumentFragment> createContextualFragment(const String&, Element*, FragmentScriptingPermission); bool isPlainTextMarkup(Node *node); diff --git a/Source/WebCore/editing/visible_units.cpp b/Source/WebCore/editing/visible_units.cpp index 622455987..1f1f85d53 100644 --- a/Source/WebCore/editing/visible_units.cpp +++ b/Source/WebCore/editing/visible_units.cpp @@ -1369,12 +1369,12 @@ bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b) bool isStartOfDocument(const VisiblePosition &p) { - return p.isNotNull() && p.previous().isNull(); + return p.isNotNull() && p.previous(CanCrossEditingBoundary).isNull(); } bool isEndOfDocument(const VisiblePosition &p) { - return p.isNotNull() && p.next().isNull(); + return p.isNotNull() && p.next(CanCrossEditingBoundary).isNull(); } // --------- @@ -1397,6 +1397,11 @@ VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition) return lastPositionInNode(highestRoot); } +bool isEndOfEditableOrNonEditableContent(const VisiblePosition &p) +{ + return p.isNotNull() && p.next().isNull(); +} + VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction) { return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c); diff --git a/Source/WebCore/editing/visible_units.h b/Source/WebCore/editing/visible_units.h index c5c1eb653..05b1a30bc 100644 --- a/Source/WebCore/editing/visible_units.h +++ b/Source/WebCore/editing/visible_units.h @@ -94,6 +94,7 @@ bool isEndOfDocument(const VisiblePosition &); // editable content VisiblePosition startOfEditableContent(const VisiblePosition&); VisiblePosition endOfEditableContent(const VisiblePosition&); +bool isEndOfEditableOrNonEditableContent(const VisiblePosition&); } // namespace WebCore |
