summaryrefslogtreecommitdiff
path: root/Source/WebCore/editing
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/editing')
-rw-r--r--Source/WebCore/editing/CompositeEditCommand.cpp4
-rw-r--r--Source/WebCore/editing/Editor.cpp7
-rw-r--r--Source/WebCore/editing/ReplaceSelectionCommand.cpp17
-rw-r--r--Source/WebCore/editing/ReplaceSelectionCommand.h5
-rw-r--r--Source/WebCore/editing/TextIterator.cpp2
-rw-r--r--Source/WebCore/editing/VisibleSelection.cpp6
-rw-r--r--Source/WebCore/editing/markup.cpp80
-rw-r--r--Source/WebCore/editing/markup.h6
-rw-r--r--Source/WebCore/editing/visible_units.cpp9
-rw-r--r--Source/WebCore/editing/visible_units.h1
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