Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / editing / Editor.cpp
index 0dc1f6d..e3fcc20 100644 (file)
 #include "config.h"
 #include "core/editing/Editor.h"
 
-#include "CSSPropertyNames.h"
-#include "HTMLNames.h"
-#include "SVGNames.h"
-#include "XLinkNames.h"
-#include "bindings/v8/ExceptionStatePlaceholder.h"
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
+#include "core/CSSPropertyNames.h"
+#include "core/EventNames.h"
+#include "core/HTMLNames.h"
+#include "core/XLinkNames.h"
 #include "core/accessibility/AXObjectCache.h"
-#include "core/clipboard/Clipboard.h"
 #include "core/clipboard/DataObject.h"
+#include "core/clipboard/DataTransfer.h"
 #include "core/clipboard/Pasteboard.h"
 #include "core/css/CSSComputedStyleDeclaration.h"
 #include "core/css/StylePropertySet.h"
 #include "core/dom/DocumentFragment.h"
 #include "core/dom/DocumentMarkerController.h"
-#include "core/dom/NodeList.h"
 #include "core/dom/NodeTraversal.h"
 #include "core/dom/ParserContentPolicy.h"
 #include "core/dom/Text.h"
@@ -68,6 +67,8 @@
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Settings.h"
+#include "core/frame/UseCounter.h"
+#include "core/html/HTMLCanvasElement.h"
 #include "core/html/HTMLImageElement.h"
 #include "core/html/HTMLInputElement.h"
 #include "core/html/HTMLTextAreaElement.h"
@@ -84,9 +85,8 @@
 #include "platform/weborigin/KURL.h"
 #include "wtf/unicode/CharacterNames.h"
 
-namespace WebCore {
+namespace blink {
 
-using namespace std;
 using namespace HTMLNames;
 using namespace WTF;
 using namespace Unicode;
@@ -117,7 +117,7 @@ VisibleSelection Editor::selectionForCommand(Event* event)
     HTMLTextFormControlElement* textFormControlOfSelectionStart = enclosingTextFormControl(selection.start());
     HTMLTextFormControlElement* textFromControlOfTarget = isHTMLTextFormControlElement(*event->target()->toNode()) ? toHTMLTextFormControlElement(event->target()->toNode()) : 0;
     if (textFromControlOfTarget && (selection.start().isNull() || textFromControlOfTarget != textFormControlOfSelectionStart)) {
-        if (RefPtr<Range> range = textFromControlOfTarget->selection())
+        if (RefPtrWillBeRawPtr<Range> range = textFromControlOfTarget->selection())
             return VisibleSelection(range.get(), DOWNSTREAM, selection.isDirectional());
     }
     return selection;
@@ -194,17 +194,17 @@ bool Editor::canEditRichly() const
 
 bool Editor::canDHTMLCut()
 {
-    return !m_frame.selection().isInPasswordField() && !dispatchCPPEvent(EventTypeNames::beforecut, ClipboardNumb);
+    return !m_frame.selection().isInPasswordField() && !dispatchCPPEvent(EventTypeNames::beforecut, DataTransferNumb);
 }
 
 bool Editor::canDHTMLCopy()
 {
-    return !m_frame.selection().isInPasswordField() && !dispatchCPPEvent(EventTypeNames::beforecopy, ClipboardNumb);
+    return !m_frame.selection().isInPasswordField() && !dispatchCPPEvent(EventTypeNames::beforecopy, DataTransferNumb);
 }
 
 bool Editor::canDHTMLPaste()
 {
-    return !dispatchCPPEvent(EventTypeNames::beforepaste, ClipboardNumb);
+    return !dispatchCPPEvent(EventTypeNames::beforepaste, DataTransferNumb);
 }
 
 bool Editor::canCut() const
@@ -255,10 +255,10 @@ bool Editor::canDeleteRange(Range* range) const
     if (!startContainer || !endContainer)
         return false;
 
-    if (!startContainer->rendererIsEditable() || !endContainer->rendererIsEditable())
+    if (!startContainer->hasEditableStyle() || !endContainer->hasEditableStyle())
         return false;
 
-    if (range->collapsed(IGNORE_EXCEPTION)) {
+    if (range->collapsed()) {
         VisiblePosition start(range->startPosition(), DOWNSTREAM);
         VisiblePosition previous = start.previous();
         // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
@@ -344,15 +344,15 @@ void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
 
 void Editor::pasteAsPlainText(const String& pastingText, bool smartReplace)
 {
-    Node* target = findEventTargetFromSelection();
+    Element* target = findEventTargetFromSelection();
     if (!target)
         return;
     target->dispatchEvent(TextEvent::createForPlainTextPaste(m_frame.domWindow(), pastingText, smartReplace), IGNORE_EXCEPTION);
 }
 
-void Editor::pasteAsFragment(PassRefPtr<DocumentFragment> pastingFragment, bool smartReplace, bool matchStyle)
+void Editor::pasteAsFragment(PassRefPtrWillBeRawPtr<DocumentFragment> pastingFragment, bool smartReplace, bool matchStyle)
 {
-    Node* target = findEventTargetFromSelection();
+    Element* target = findEventTargetFromSelection();
     if (!target)
         return;
     target->dispatchEvent(TextEvent::createForFragmentPaste(m_frame.domWindow(), pastingFragment, smartReplace, matchStyle), IGNORE_EXCEPTION);
@@ -363,7 +363,7 @@ bool Editor::tryDHTMLCopy()
     if (m_frame.selection().isInPasswordField())
         return false;
 
-    return !dispatchCPPEvent(EventTypeNames::copy, ClipboardWritable);
+    return !dispatchCPPEvent(EventTypeNames::copy, DataTransferWritable);
 }
 
 bool Editor::tryDHTMLCut()
@@ -371,12 +371,12 @@ bool Editor::tryDHTMLCut()
     if (m_frame.selection().isInPasswordField())
         return false;
 
-    return !dispatchCPPEvent(EventTypeNames::cut, ClipboardWritable);
+    return !dispatchCPPEvent(EventTypeNames::cut, DataTransferWritable);
 }
 
 bool Editor::tryDHTMLPaste(PasteMode pasteMode)
 {
-    return !dispatchCPPEvent(EventTypeNames::paste, ClipboardReadable, pasteMode);
+    return !dispatchCPPEvent(EventTypeNames::paste, DataTransferReadable, pasteMode);
 }
 
 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
@@ -387,8 +387,8 @@ void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
 
 void Editor::pasteWithPasteboard(Pasteboard* pasteboard)
 {
-    RefPtr<Range> range = selectedRange();
-    RefPtr<DocumentFragment> fragment;
+    RefPtrWillBeRawPtr<Range> range = selectedRange();
+    RefPtrWillBeRawPtr<DocumentFragment> fragment = nullptr;
     bool chosePlainText = false;
 
     if (pasteboard->isHTMLAvailable()) {
@@ -421,59 +421,77 @@ void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard, Range* selectedR
     pasteboard->writeHTML(html, url, plainText, canSmartCopyOrDelete());
 }
 
+static Image* imageFromNode(const Node& node)
+{
+    node.document().updateLayoutIgnorePendingStylesheets();
+    RenderObject* renderer = node.renderer();
+    if (!renderer)
+        return nullptr;
+
+    if (renderer->isCanvas())
+        return toHTMLCanvasElement(node).copiedImage();
+
+    if (renderer->isImage()) {
+        RenderImage* renderImage = toRenderImage(renderer);
+        if (!renderImage)
+            return nullptr;
+
+        ImageResource* cachedImage = renderImage->cachedImage();
+        if (!cachedImage || cachedImage->errorOccurred())
+            return nullptr;
+        return cachedImage->imageForRenderer(renderImage);
+    }
+
+    return nullptr;
+}
+
 static void writeImageNodeToPasteboard(Pasteboard* pasteboard, Node* node, const String& title)
 {
     ASSERT(pasteboard);
     ASSERT(node);
 
-    if (!(node->renderer() && node->renderer()->isImage()))
-        return;
-
-    RenderImage* renderer = toRenderImage(node->renderer());
-    ImageResource* cachedImage = renderer->cachedImage();
-    if (!cachedImage || cachedImage->errorOccurred())
+    RefPtr<Image> image = imageFromNode(*node);
+    if (!image.get())
         return;
-    Image* image = cachedImage->imageForRenderer(renderer);
-    ASSERT(image);
 
     // FIXME: This should probably be reconciled with HitTestResult::absoluteImageURL.
     AtomicString urlString;
     if (isHTMLImageElement(*node) || isHTMLInputElement(*node))
-        urlString = toElement(node)->getAttribute(srcAttr);
+        urlString = toHTMLElement(node)->getAttribute(srcAttr);
     else if (isSVGImageElement(*node))
-        urlString = toElement(node)->getAttribute(XLinkNames::hrefAttr);
-    else if (isHTMLEmbedElement(*node) || isHTMLObjectElement(*node))
-        urlString = toElement(node)->imageSourceURL();
+        urlString = toSVGElement(node)->getAttribute(XLinkNames::hrefAttr);
+    else if (isHTMLEmbedElement(*node) || isHTMLObjectElement(*node) || isHTMLCanvasElement(*node))
+        urlString = toHTMLElement(node)->imageSourceURL();
     KURL url = urlString.isEmpty() ? KURL() : node->document().completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
 
-    pasteboard->writeImage(image, url, title);
+    pasteboard->writeImage(image.get(), url, title);
 }
 
 // Returns whether caller should continue with "the default processing", which is the same as
 // the event handler NOT setting the return value to false
-bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy, PasteMode pasteMode)
+bool Editor::dispatchCPPEvent(const AtomicString& eventType, DataTransferAccessPolicy policy, PasteMode pasteMode)
 {
-    Node* target = findEventTargetFromSelection();
+    Element* target = findEventTargetFromSelection();
     if (!target)
         return true;
 
-    RefPtrWillBeRawPtr<Clipboard> clipboard = Clipboard::create(
-        Clipboard::CopyAndPaste,
+    RefPtrWillBeRawPtr<DataTransfer> dataTransfer = DataTransfer::create(
+        DataTransfer::CopyAndPaste,
         policy,
-        policy == ClipboardWritable
+        policy == DataTransferWritable
             ? DataObject::create()
             : DataObject::createFromPasteboard(pasteMode));
 
-    RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
+    RefPtrWillBeRawPtr<Event> evt = ClipboardEvent::create(eventType, true, true, dataTransfer);
     target->dispatchEvent(evt, IGNORE_EXCEPTION);
     bool noDefaultProcessing = evt->defaultPrevented();
-    if (noDefaultProcessing && policy == ClipboardWritable) {
-        RefPtrWillBeRawPtr<DataObject> dataObject = clipboard->dataObject();
+    if (noDefaultProcessing && policy == DataTransferWritable) {
+        RefPtrWillBeRawPtr<DataObject> dataObject = dataTransfer->dataObject();
         Pasteboard::generalPasteboard()->writeDataObject(dataObject.release());
     }
 
     // invalidate clipboard here for security
-    clipboard->setAccessPolicy(ClipboardNumb);
+    dataTransfer->setAccessPolicy(DataTransferNumb);
 
     return !noDefaultProcessing;
 }
@@ -483,7 +501,7 @@ bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard)
     return smartInsertDeleteEnabled() && pasteboard->canSmartReplace();
 }
 
-void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
+void Editor::replaceSelectionWithFragment(PassRefPtrWillBeRawPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
 {
     if (m_frame.selection().isNone() || !m_frame.selection().isContentEditable() || !fragment)
         return;
@@ -509,14 +527,14 @@ void Editor::replaceSelectionWithText(const String& text, bool selectReplacement
     replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true);
 }
 
-PassRefPtr<Range> Editor::selectedRange()
+PassRefPtrWillBeRawPtr<Range> Editor::selectedRange()
 {
     return m_frame.selection().toNormalizedRange();
 }
 
 bool Editor::shouldDeleteRange(Range* range) const
 {
-    if (!range || range->collapsed(IGNORE_EXCEPTION))
+    if (!range || range->collapsed())
         return false;
 
     return canDeleteRange(range);
@@ -540,36 +558,6 @@ void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
     client().respondToChangedContents();
 }
 
-TriState Editor::selectionUnorderedListState() const
-{
-    if (m_frame.selection().isCaret()) {
-        if (enclosingNodeWithTag(m_frame.selection().selection().start(), ulTag))
-            return TrueTriState;
-    } else if (m_frame.selection().isRange()) {
-        Node* startNode = enclosingNodeWithTag(m_frame.selection().selection().start(), ulTag);
-        Node* endNode = enclosingNodeWithTag(m_frame.selection().selection().end(), ulTag);
-        if (startNode && endNode && startNode == endNode)
-            return TrueTriState;
-    }
-
-    return FalseTriState;
-}
-
-TriState Editor::selectionOrderedListState() const
-{
-    if (m_frame.selection().isCaret()) {
-        if (enclosingNodeWithTag(m_frame.selection().selection().start(), olTag))
-            return TrueTriState;
-    } else if (m_frame.selection().isRange()) {
-        Node* startNode = enclosingNodeWithTag(m_frame.selection().selection().start(), olTag);
-        Node* endNode = enclosingNodeWithTag(m_frame.selection().selection().end(), olTag);
-        if (startNode && endNode && startNode == endNode)
-            return TrueTriState;
-    }
-
-    return FalseTriState;
-}
-
 void Editor::removeFormattingAndStyle()
 {
     ASSERT(m_frame.document());
@@ -581,16 +569,16 @@ void Editor::clearLastEditCommand()
     m_lastEditCommand.clear();
 }
 
-Node* Editor::findEventTargetFrom(const VisibleSelection& selection) const
+Element* Editor::findEventTargetFrom(const VisibleSelection& selection) const
 {
-    Node* target = selection.start().element();
+    Element* target = selection.start().element();
     if (!target)
         target = m_frame.document()->body();
 
     return target;
 }
 
-Node* Editor::findEventTargetFromSelection() const
+Element* Editor::findEventTargetFromSelection() const
 {
     return findEventTargetFrom(m_frame.selection().selection());
 }
@@ -650,7 +638,7 @@ TriState Editor::selectionHasStyle(CSSPropertyID propertyID, const String& value
 
 String Editor::selectionStartCSSPropertyValue(CSSPropertyID propertyID)
 {
-    RefPtr<EditingStyle> selectionStyle = EditingStyle::styleAtSelectionStart(m_frame.selection().selection(),
+    RefPtrWillBeRawPtr<EditingStyle> selectionStyle = EditingStyle::styleAtSelectionStart(m_frame.selection().selection(),
         propertyID == CSSPropertyBackgroundColor);
     if (!selectionStyle || !selectionStyle->style())
         return String();
@@ -660,19 +648,7 @@ String Editor::selectionStartCSSPropertyValue(CSSPropertyID propertyID)
     return selectionStyle->style()->getPropertyValue(propertyID);
 }
 
-void Editor::indent()
-{
-    ASSERT(m_frame.document());
-    IndentOutdentCommand::create(*m_frame.document(), IndentOutdentCommand::Indent)->apply();
-}
-
-void Editor::outdent()
-{
-    ASSERT(m_frame.document());
-    IndentOutdentCommand::create(*m_frame.document(), IndentOutdentCommand::Outdent)->apply();
-}
-
-static void dispatchEditableContentChangedEvents(PassRefPtr<Element> startRoot, PassRefPtr<Element> endRoot)
+static void dispatchEditableContentChangedEvents(PassRefPtrWillBeRawPtr<Element> startRoot, PassRefPtrWillBeRawPtr<Element> endRoot)
 {
     if (startRoot)
         startRoot->dispatchEvent(Event::create(EventTypeNames::webkitEditableContentChanged), IGNORE_EXCEPTION);
@@ -680,7 +656,7 @@ static void dispatchEditableContentChangedEvents(PassRefPtr<Element> startRoot,
         endRoot->dispatchEvent(Event::create(EventTypeNames::webkitEditableContentChanged), IGNORE_EXCEPTION);
 }
 
-void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd)
+void Editor::appliedEditing(PassRefPtrWillBeRawPtr<CompositeEditCommand> cmd)
 {
     EventQueueScope scope;
     m_frame.document()->updateLayout();
@@ -710,7 +686,7 @@ void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd)
     respondToChangedContents(newSelection);
 }
 
-void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd)
+void Editor::unappliedEditing(PassRefPtrWillBeRawPtr<EditCommandComposition> cmd)
 {
     EventQueueScope scope;
     m_frame.document()->updateLayout();
@@ -718,7 +694,9 @@ void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd)
     dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement());
 
     VisibleSelection newSelection(cmd->startingSelection());
-    changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
+    newSelection.validatePositionsIfNeeded();
+    if (newSelection.start().document() == m_frame.document() && newSelection.end().document() == m_frame.document())
+        changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
 
     m_lastEditCommand = nullptr;
     if (UndoStack* undoStack = this->undoStack())
@@ -726,7 +704,7 @@ void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd)
     respondToChangedContents(newSelection);
 }
 
-void Editor::reappliedEditing(PassRefPtr<EditCommandComposition> cmd)
+void Editor::reappliedEditing(PassRefPtrWillBeRawPtr<EditCommandComposition> cmd)
 {
     EventQueueScope scope;
     m_frame.document()->updateLayout();
@@ -742,9 +720,9 @@ void Editor::reappliedEditing(PassRefPtr<EditCommandComposition> cmd)
     respondToChangedContents(newSelection);
 }
 
-PassOwnPtr<Editor> Editor::create(LocalFrame& frame)
+PassOwnPtrWillBeRawPtr<Editor> Editor::create(LocalFrame& frame)
 {
-    return adoptPtr(new Editor(frame));
+    return adoptPtrWillBeNoop(new Editor(frame));
 }
 
 Editor::Editor(LocalFrame& frame)
@@ -771,7 +749,7 @@ void Editor::clear()
     m_defaultParagraphSeparator = EditorParagraphSeparatorIsDiv;
 }
 
-bool Editor::insertText(const String& text, Event* triggeringEvent)
+bool Editor::insertText(const String& text, KeyboardEvent* triggeringEvent)
 {
     return m_frame.eventHandler().handleTextInputEvent(text, triggeringEvent);
 }
@@ -784,7 +762,6 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
     VisibleSelection selection = selectionForCommand(triggeringEvent);
     if (!selection.isContentEditable())
         return false;
-    RefPtr<Range> range = selection.toNormalizedRange();
 
     spellChecker().updateMarkersForWordsAffectedByEditing(isSpaceOrNewline(text[0]));
 
@@ -794,7 +771,7 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
     selection = selectionForCommand(triggeringEvent);
     if (selection.isContentEditable()) {
         if (Node* selectionStart = selection.start().deprecatedNode()) {
-            RefPtr<Document> document(selectionStart->document());
+            RefPtrWillBeRawPtr<Document> document(selectionStart->document());
 
             // Insert the text
             TypingCommand::Options options = 0;
@@ -805,7 +782,7 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
             // Reveal the current selection
             if (LocalFrame* editedFrame = document->frame()) {
                 if (Page* page = editedFrame->page())
-                    page->focusController().focusedOrMainFrame()->selection().revealSelection(ScrollAlignment::alignCenterIfNeeded);
+                    toLocalFrame(page->focusController().focusedOrMainFrame())->selection().revealSelection(ScrollAlignment::alignCenterIfNeeded);
             }
         }
     }
@@ -850,7 +827,7 @@ void Editor::cut()
         return; // DHTML did the whole operation
     if (!canCut())
         return;
-    RefPtr<Range> selection = selectedRange();
+    RefPtrWillBeRawPtr<Range> selection = selectedRange();
     if (shouldDeleteRange(selection.get())) {
         spellChecker().updateMarkersForWordsAffectedByEditing(true);
         String plainText = m_frame.selectedTextForClipboard();
@@ -920,6 +897,71 @@ void Editor::performDelete()
     setStartNewKillRingSequence(false);
 }
 
+static void countEditingEvent(ExecutionContext* executionContext, const Event* event, UseCounter::Feature featureOnInput, UseCounter::Feature featureOnTextArea, UseCounter::Feature featureOnContentEditable, UseCounter::Feature featureOnNonNode)
+{
+    EventTarget* eventTarget = event->target();
+    Node* node = eventTarget->toNode();
+    if (!node) {
+        UseCounter::count(executionContext, featureOnNonNode);
+        return;
+    }
+
+    if (isHTMLInputElement(node)) {
+        UseCounter::count(executionContext, featureOnInput);
+        return;
+    }
+
+    if (isHTMLTextAreaElement(node)) {
+        UseCounter::count(executionContext, featureOnTextArea);
+        return;
+    }
+
+    HTMLTextFormControlElement* control = enclosingTextFormControl(node);
+    if (isHTMLInputElement(control)) {
+        UseCounter::count(executionContext, featureOnInput);
+        return;
+    }
+
+    if (isHTMLTextAreaElement(control)) {
+        UseCounter::count(executionContext, featureOnTextArea);
+        return;
+    }
+
+    UseCounter::count(executionContext, featureOnContentEditable);
+}
+
+void Editor::countEvent(ExecutionContext* executionContext, const Event* event)
+{
+    if (!executionContext)
+        return;
+
+    if (event->type() == EventTypeNames::textInput) {
+        countEditingEvent(executionContext, event,
+            UseCounter::TextInputEventOnInput,
+            UseCounter::TextInputEventOnTextArea,
+            UseCounter::TextInputEventOnContentEditable,
+            UseCounter::TextInputEventOnNotNode);
+        return;
+    }
+
+    if (event->type() == EventTypeNames::webkitBeforeTextInserted) {
+        countEditingEvent(executionContext, event,
+            UseCounter::WebkitBeforeTextInsertedOnInput,
+            UseCounter::WebkitBeforeTextInsertedOnTextArea,
+            UseCounter::WebkitBeforeTextInsertedOnContentEditable,
+            UseCounter::WebkitBeforeTextInsertedOnNotNode);
+        return;
+    }
+
+    if (event->type() == EventTypeNames::webkitEditableContentChanged) {
+        countEditingEvent(executionContext, event,
+            UseCounter::WebkitEditableContentChangedOnInput,
+            UseCounter::WebkitEditableContentChangedOnTextArea,
+            UseCounter::WebkitEditableContentChangedOnContentEditable,
+            UseCounter::WebkitEditableContentChangedOnNotNode);
+    }
+}
+
 void Editor::copyImage(const HitTestResult& result)
 {
     writeImageNodeToPasteboard(Pasteboard::generalPasteboard(), result.innerNonSharedNode(), result.altDisplayString());
@@ -994,7 +1036,7 @@ void Editor::transpose()
     previous = previous.previous();
     if (!inSameParagraph(next, previous))
         return;
-    RefPtr<Range> range = makeRange(previous, next);
+    RefPtrWillBeRawPtr<Range> range = makeRange(previous, next);
     if (!range)
         return;
     VisibleSelection newSelection(range.get(), DOWNSTREAM);
@@ -1063,10 +1105,10 @@ IntRect Editor::firstRectForRange(Range* range) const
 
     if (startCaretRect.y() == endCaretRect.y()) {
         // start and end are on the same line
-        return IntRect(min(startCaretRect.x(), endCaretRect.x()),
+        return IntRect(std::min(startCaretRect.x(), endCaretRect.x()),
             startCaretRect.y(),
             abs(endCaretRect.x() - startCaretRect.x()),
-            max(startCaretRect.height(), endCaretRect.height()));
+            std::max(startCaretRect.height(), endCaretRect.height()));
     }
 
     // start and end aren't on the same line, so go from start to the end of its line
@@ -1084,7 +1126,7 @@ void Editor::computeAndSetTypingStyle(StylePropertySet* style, EditAction editin
     }
 
     // Calculate the current typing style.
-    RefPtr<EditingStyle> typingStyle;
+    RefPtrWillBeRawPtr<EditingStyle> typingStyle = nullptr;
     if (m_frame.selection().typingStyle()) {
         typingStyle = m_frame.selection().typingStyle()->copy();
         typingStyle->overrideWithStyle(style);
@@ -1095,7 +1137,7 @@ void Editor::computeAndSetTypingStyle(StylePropertySet* style, EditAction editin
     typingStyle->prepareToApplyAt(m_frame.selection().selection().visibleStart().deepEquivalent(), EditingStyle::PreserveWritingDirection);
 
     // Handle block styles, substracting these from the typing style.
-    RefPtr<EditingStyle> blockStyle = typingStyle->extractAndRemoveBlockProperties();
+    RefPtrWillBeRawPtr<EditingStyle> blockStyle = typingStyle->extractAndRemoveBlockProperties();
     if (!blockStyle->isEmpty()) {
         ASSERT(m_frame.document());
         ApplyStyleCommand::create(*m_frame.document(), blockStyle.get(), editingAction)->apply();
@@ -1115,7 +1157,7 @@ bool Editor::findString(const String& target, FindOptions options)
 {
     VisibleSelection selection = m_frame.selection().selection();
 
-    RefPtr<Range> resultRange = rangeOfString(target, selection.firstRange().get(), options);
+    RefPtrWillBeRawPtr<Range> resultRange = rangeOfString(target, selection.firstRange().get(), options);
 
     if (!resultRange)
         return false;
@@ -1125,9 +1167,9 @@ bool Editor::findString(const String& target, FindOptions options)
     return true;
 }
 
-PassRefPtr<Range> Editor::findStringAndScrollToVisible(const String& target, Range* previousMatch, FindOptions options)
+PassRefPtrWillBeRawPtr<Range> Editor::findStringAndScrollToVisible(const String& target, Range* previousMatch, FindOptions options)
 {
-    RefPtr<Range> nextMatch = rangeOfString(target, previousMatch, options);
+    RefPtrWillBeRawPtr<Range> nextMatch = rangeOfString(target, previousMatch, options);
     if (!nextMatch)
         return nullptr;
 
@@ -1137,75 +1179,76 @@ PassRefPtr<Range> Editor::findStringAndScrollToVisible(const String& target, Ran
     return nextMatch.release();
 }
 
-PassRefPtr<Range> Editor::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
+static PassRefPtrWillBeRawPtr<Range> findStringBetweenPositions(const String& target, const Position& start, const Position& end, FindOptions options)
+{
+    Position searchStart(start);
+    Position searchEnd(end);
+
+    bool forward = !(options & Backwards);
+
+    while (true) {
+        Position resultStart;
+        Position resultEnd;
+        findPlainText(searchStart, searchEnd, target, options, resultStart, resultEnd);
+        if (resultStart == resultEnd)
+            return nullptr;
+
+        RefPtrWillBeRawPtr<Range> resultRange = Range::create(*resultStart.document(), resultStart, resultEnd);
+        if (!resultRange->collapsed())
+            return resultRange.release();
+
+        // Found text spans over multiple TreeScopes. Since it's impossible to return such section as a Range,
+        // we skip this match and seek for the next occurrence.
+        // FIXME: Handle this case.
+        if (forward)
+            searchStart = resultStart.next();
+        else
+            searchEnd = resultEnd.previous();
+    }
+
+    ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
+PassRefPtrWillBeRawPtr<Range> Editor::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
 {
     if (target.isEmpty())
         return nullptr;
 
-    // Start from an edge of the reference range, if there's a reference range that's not in shadow content. Which edge
-    // is used depends on whether we're searching forward or backward, and whether startInSelection is set.
-    RefPtr<Range> searchRange(rangeOfContents(m_frame.document()));
+    // Start from an edge of the reference range. Which edge is used depends on whether we're searching forward or
+    // backward, and whether startInSelection is set.
+    Position searchStart = firstPositionInNode(m_frame.document());
+    Position searchEnd = lastPositionInNode(m_frame.document());
 
     bool forward = !(options & Backwards);
     bool startInReferenceRange = referenceRange && (options & StartInSelection);
     if (referenceRange) {
         if (forward)
-            searchRange->setStart(startInReferenceRange ? referenceRange->startPosition() : referenceRange->endPosition());
+            searchStart = startInReferenceRange ? referenceRange->startPosition() : referenceRange->endPosition();
         else
-            searchRange->setEnd(startInReferenceRange ? referenceRange->endPosition() : referenceRange->startPosition());
+            searchEnd = startInReferenceRange ? referenceRange->endPosition() : referenceRange->startPosition();
     }
 
-    RefPtr<Node> shadowTreeRoot = referenceRange && referenceRange->startContainer() ? referenceRange->startContainer()->nonBoundaryShadowTreeRootNode() : 0;
-    if (shadowTreeRoot) {
-        if (forward)
-            searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->countChildren());
-        else
-            searchRange->setStart(shadowTreeRoot.get(), 0);
-    }
+    RefPtrWillBeRawPtr<Range> resultRange = findStringBetweenPositions(target, searchStart, searchEnd, options);
 
-    RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, options));
     // If we started in the reference range and the found range exactly matches the reference range, find again.
     // Build a selection with the found range to remove collapsed whitespace.
     // Compare ranges instead of selection objects to ignore the way that the current selection was made.
-    if (startInReferenceRange && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), referenceRange)) {
-        searchRange = rangeOfContents(m_frame.document());
+    if (resultRange && startInReferenceRange && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), referenceRange)) {
         if (forward)
-            searchRange->setStart(referenceRange->endPosition());
+            searchStart = resultRange->endPosition();
         else
-            searchRange->setEnd(referenceRange->startPosition());
-
-        if (shadowTreeRoot) {
-            if (forward)
-                searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->countChildren());
-            else
-                searchRange->setStart(shadowTreeRoot.get(), 0);
-        }
-
-        resultRange = findPlainText(searchRange.get(), target, options);
-    }
-
-    // If nothing was found in the shadow tree, search in main content following the shadow tree.
-    if (resultRange->collapsed(ASSERT_NO_EXCEPTION) && shadowTreeRoot) {
-        searchRange = rangeOfContents(m_frame.document());
-        if (forward)
-            searchRange->setStartAfter(shadowTreeRoot->shadowHost());
-        else
-            searchRange->setEndBefore(shadowTreeRoot->shadowHost());
-
-        resultRange = findPlainText(searchRange.get(), target, options);
+            searchEnd = resultRange->startPosition();
+        resultRange = findStringBetweenPositions(target, searchStart, searchEnd, options);
     }
 
-    // If we didn't find anything and we're wrapping, search again in the entire document (this will
-    // redundantly re-search the area already searched in some cases).
-    if (resultRange->collapsed(ASSERT_NO_EXCEPTION) && options & WrapAround) {
-        searchRange = rangeOfContents(m_frame.document());
-        resultRange = findPlainText(searchRange.get(), target, options);
-        // We used to return false here if we ended up with the same range that we started with
-        // (e.g., the reference range was already the only instance of this text). But we decided that
-        // this should be a success case instead, so we'll just fall through in that case.
+    if (!resultRange && options & WrapAround) {
+        searchStart = firstPositionInNode(m_frame.document());
+        searchEnd = lastPositionInNode(m_frame.document());
+        resultRange = findStringBetweenPositions(target, searchStart, searchEnd, options);
     }
 
-    return resultRange->collapsed(ASSERT_NO_EXCEPTION) ? nullptr : resultRange.release();
+    return resultRange.release();
 }
 
 void Editor::setMarkedTextMatchesAreHighlighted(bool flag)
@@ -1235,4 +1278,10 @@ void Editor::toggleOverwriteModeEnabled()
     frame().selection().setShouldShowBlockCursor(m_overwriteModeEnabled);
 }
 
-} // namespace WebCore
+void Editor::trace(Visitor* visitor)
+{
+    visitor->trace(m_lastEditCommand);
+    visitor->trace(m_mark);
+}
+
+} // namespace blink