#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"
#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"
#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;
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;
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
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.
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);
if (m_frame.selection().isInPasswordField())
return false;
- return !dispatchCPPEvent(EventTypeNames::copy, ClipboardWritable);
+ return !dispatchCPPEvent(EventTypeNames::copy, DataTransferWritable);
}
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)
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()) {
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;
}
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;
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);
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());
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());
}
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();
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);
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();
respondToChangedContents(newSelection);
}
-void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd)
+void Editor::unappliedEditing(PassRefPtrWillBeRawPtr<EditCommandComposition> cmd)
{
EventQueueScope scope;
m_frame.document()->updateLayout();
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())
respondToChangedContents(newSelection);
}
-void Editor::reappliedEditing(PassRefPtr<EditCommandComposition> cmd)
+void Editor::reappliedEditing(PassRefPtrWillBeRawPtr<EditCommandComposition> cmd)
{
EventQueueScope scope;
m_frame.document()->updateLayout();
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)
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);
}
VisibleSelection selection = selectionForCommand(triggeringEvent);
if (!selection.isContentEditable())
return false;
- RefPtr<Range> range = selection.toNormalizedRange();
spellChecker().updateMarkersForWordsAffectedByEditing(isSpaceOrNewline(text[0]));
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;
// 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);
}
}
}
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();
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());
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);
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
}
// 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);
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();
{
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;
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;
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)
frame().selection().setShouldShowBlockCursor(m_overwriteModeEnabled);
}
-} // namespace WebCore
+void Editor::trace(Visitor* visitor)
+{
+ visitor->trace(m_lastEditCommand);
+ visitor->trace(m_mark);
+}
+
+} // namespace blink