#include "core/events/KeyboardEvent.h"
#include "core/events/ScopedEventQueue.h"
#include "core/events/TextEvent.h"
-#include "core/events/ThreadLocalEventNames.h"
#include "core/fetch/ImageResource.h"
#include "core/fetch/ResourceFetcher.h"
-#include "core/frame/Frame.h"
#include "core/frame/FrameView.h"
+#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/html/HTMLImageElement.h"
#include "core/html/HTMLInputElement.h"
#include "core/page/Page.h"
#include "core/rendering/HitTestResult.h"
#include "core/rendering/RenderImage.h"
+#include "core/svg/SVGImageElement.h"
#include "platform/KillRing.h"
#include "platform/weborigin/KURL.h"
#include "wtf/unicode/CharacterNames.h"
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;
return 0;
Node* node = body->firstChild();
- if (!node)
- return 0;
- if (!node->hasTagName(imgTag))
+ if (!isHTMLImageElement(node))
return 0;
return toHTMLImageElement(node);
}
if (!startContainer->rendererIsEditable() || !endContainer->rendererIsEditable())
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::pasteWithPasteboard(Pasteboard* pasteboard)
{
- RefPtr<Range> range = selectedRange();
+ RefPtrWillBeRawPtr<Range> range = selectedRange();
RefPtr<DocumentFragment> fragment;
bool chosePlainText = false;
// FIXME: This should probably be reconciled with HitTestResult::absoluteImageURL.
AtomicString urlString;
- if (node->hasTagName(imgTag) || node->hasTagName(inputTag))
+ if (isHTMLImageElement(*node) || isHTMLInputElement(*node))
urlString = toElement(node)->getAttribute(srcAttr);
- else if (node->hasTagName(SVGNames::imageTag))
+ else if (isSVGImageElement(*node))
urlString = toElement(node)->getAttribute(XLinkNames::hrefAttr);
- else if (node->hasTagName(embedTag) || node->hasTagName(objectTag))
+ else if (isHTMLEmbedElement(*node) || isHTMLObjectElement(*node))
urlString = toElement(node)->imageSourceURL();
KURL url = urlString.isEmpty() ? KURL() : node->document().completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
if (!target)
return true;
- RefPtr<Clipboard> clipboard = Clipboard::create(
+ RefPtrWillBeRawPtr<Clipboard> clipboard = Clipboard::create(
Clipboard::CopyAndPaste,
policy,
policy == ClipboardWritable
? DataObject::create()
: DataObject::createFromPasteboard(pasteMode));
- RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
+ RefPtrWillBeRawPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
target->dispatchEvent(evt, IGNORE_EXCEPTION);
bool noDefaultProcessing = evt->defaultPrevented();
if (noDefaultProcessing && policy == ClipboardWritable) {
- RefPtr<DataObject> dataObject = clipboard->dataObject();
+ RefPtrWillBeRawPtr<DataObject> dataObject = clipboard->dataObject();
Pasteboard::generalPasteboard()->writeDataObject(dataObject.release());
}
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);
void Editor::notifyComponentsOnChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions options)
{
- client().respondToChangedSelection(m_frame.selection().selectionType());
+ client().respondToChangedSelection(&m_frame, m_frame.selection().selectionType());
setStartNewKillRingSequence(true);
}
VisibleSelection newSelection(cmd->startingSelection());
changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
- m_lastEditCommand = 0;
+ m_lastEditCommand = nullptr;
if (UndoStack* undoStack = this->undoStack())
undoStack->registerRedoStep(cmd);
respondToChangedContents(newSelection);
VisibleSelection newSelection(cmd->endingSelection());
changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
- m_lastEditCommand = 0;
+ m_lastEditCommand = nullptr;
if (UndoStack* undoStack = this->undoStack())
undoStack->registerUndoStep(cmd);
respondToChangedContents(newSelection);
}
-PassOwnPtr<Editor> Editor::create(Frame& frame)
+PassOwnPtr<Editor> Editor::create(LocalFrame& frame)
{
return adoptPtr(new Editor(frame));
}
-Editor::Editor(Frame& frame)
+Editor::Editor(LocalFrame& frame)
: m_frame(frame)
, m_preventRevealSelection(0)
, m_shouldStartNewKillRingSequence(false)
VisibleSelection selection = selectionForCommand(triggeringEvent);
if (!selection.isContentEditable())
return false;
- RefPtr<Range> range = selection.toNormalizedRange();
spellChecker().updateMarkersForWordsAffectedByEditing(isSpaceOrNewline(text[0]));
TypingCommand::insertText(*document.get(), text, selection, options, triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm : TypingCommand::TextCompositionNone);
// Reveal the current selection
- if (Frame* editedFrame = document->frame()) {
+ 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();
void Editor::setBaseWritingDirection(WritingDirection direction)
{
- Node* focusedElement = frame().document()->focusedElement();
- if (focusedElement && isHTMLTextFormControlElement(*focusedElement)) {
+ Element* focusedElement = frame().document()->focusedElement();
+ if (isHTMLTextFormControlElement(focusedElement)) {
if (direction == NaturalWritingDirection)
return;
- toHTMLElement(focusedElement)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
+ focusedElement->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
focusedElement->dispatchInputEvent();
- frame().document()->updateStyleIfNeeded();
+ frame().document()->updateRenderTreeIfNeeded();
return;
}
- RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create();
+ RefPtrWillBeRawPtr<MutableStylePropertySet> style = MutableStylePropertySet::create();
style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDirection ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", false);
applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
}
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);
// does not call EditorClient::respondToChangedSelection(), which, on the Mac, sends selection change notifications and
// starts a new kill ring sequence, but we want to do these things (matches AppKit).
if (selectionDidNotChangeDOMPosition)
- client().respondToChangedSelection(m_frame.selection().selectionType());
+ client().respondToChangedSelection(&m_frame, m_frame.selection().selectionType());
}
IntRect Editor::firstRectForRange(Range* range) const
{
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 0;
+ return nullptr;
nextMatch->firstNode()->renderer()->scrollRectToVisible(nextMatch->boundingBox(),
ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
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 0;
+ 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->childNodeCount());
- 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->childNodeCount());
- 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) ? 0 : resultRange.release();
+ return resultRange.release();
}
void Editor::setMarkedTextMatchesAreHighlighted(bool flag)
return;
m_areMarkedTextMatchesHighlighted = flag;
- m_frame.document()->markers()->repaintMarkers(DocumentMarker::TextMatch);
+ m_frame.document()->markers().repaintMarkers(DocumentMarker::TextMatch);
}
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions options)