diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/page/DragController.cpp')
-rw-r--r-- | chromium/third_party/WebKit/Source/core/page/DragController.cpp | 138 |
1 files changed, 88 insertions, 50 deletions
diff --git a/chromium/third_party/WebKit/Source/core/page/DragController.cpp b/chromium/third_party/WebKit/Source/core/page/DragController.cpp index 166fc1c5725..b53c4ea6dc0 100644 --- a/chromium/third_party/WebKit/Source/core/page/DragController.cpp +++ b/chromium/third_party/WebKit/Source/core/page/DragController.cpp @@ -36,7 +36,6 @@ #include "core/dom/Element.h" #include "core/dom/Node.h" #include "core/dom/Text.h" -#include "core/dom/TextEvent.h" #include "core/dom/shadow/ShadowRoot.h" #include "core/editing/Editor.h" #include "core/editing/FrameSelection.h" @@ -44,35 +43,36 @@ #include "core/editing/ReplaceSelectionCommand.h" #include "core/editing/htmlediting.h" #include "core/editing/markup.h" +#include "core/events/TextEvent.h" #include "core/fetch/ImageResource.h" #include "core/fetch/ResourceFetcher.h" +#include "core/frame/Frame.h" +#include "core/frame/FrameView.h" #include "core/html/HTMLAnchorElement.h" #include "core/html/HTMLFormElement.h" #include "core/html/HTMLInputElement.h" #include "core/html/HTMLPlugInElement.h" #include "core/loader/FrameLoadRequest.h" #include "core/loader/FrameLoader.h" -#include "core/page/DragActions.h" #include "core/page/DragClient.h" +#include "core/page/DragData.h" #include "core/page/DragSession.h" #include "core/page/DragState.h" #include "core/page/EventHandler.h" -#include "core/page/Frame.h" -#include "core/page/FrameView.h" #include "core/page/Page.h" -#include "core/page/Settings.h" -#include "core/platform/DragData.h" +#include "core/frame/Settings.h" #include "core/platform/DragImage.h" -#include "core/platform/graphics/FloatRect.h" -#include "core/platform/graphics/Image.h" -#include "core/platform/graphics/ImageOrientation.h" -#include "core/platform/network/ResourceRequest.h" +#include "core/platform/chromium/ChromiumDataObject.h" #include "core/rendering/HitTestRequest.h" #include "core/rendering/HitTestResult.h" #include "core/rendering/RenderImage.h" #include "core/rendering/RenderTheme.h" #include "core/rendering/RenderView.h" -#include "weborigin/SecurityOrigin.h" +#include "platform/geometry/FloatRect.h" +#include "platform/graphics/Image.h" +#include "platform/graphics/ImageOrientation.h" +#include "platform/network/ResourceRequest.h" +#include "platform/weborigin/SecurityOrigin.h" #include "wtf/CurrentTime.h" #include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" @@ -91,6 +91,7 @@ static const int MaxOriginalImageArea = 1500 * 1500; static const int LinkDragBorderInset = 2; static const float DragImageAlpha = 0.75f; +#if !ASSERT_DISABLED static bool dragTypeIsValid(DragSourceAction action) { switch (action) { @@ -105,6 +106,7 @@ static bool dragTypeIsValid(DragSourceAction action) // Make sure MSVC doesn't complain that not all control paths return a value. return false; } +#endif static PlatformMouseEvent createMouseEvent(DragData* dragData) { @@ -121,6 +123,11 @@ static PlatformMouseEvent createMouseEvent(DragData* dragData) metaKey, currentTime()); } +static PassRefPtr<Clipboard> createDraggingClipboard(ClipboardAccessPolicy policy, DragData* dragData) +{ + return Clipboard::create(Clipboard::DragAndDrop, policy, dragData->platformData()); +} + DragController::DragController(Page* page, DragClient* client) : m_page(page) , m_client(client) @@ -154,16 +161,16 @@ static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragD if (PassRefPtr<DocumentFragment> fragment = dragData->asFragment(frame, context, allowPlainText, chosePlainText)) return fragment; - if (dragData->containsURL(frame, DragData::DoNotConvertFilenames)) { + if (dragData->containsURL(DragData::DoNotConvertFilenames)) { String title; - String url = dragData->asURL(frame, DragData::DoNotConvertFilenames, &title); + String url = dragData->asURL(DragData::DoNotConvertFilenames, &title); if (!url.isEmpty()) { RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(document); anchor->setHref(url); if (title.isEmpty()) { // Try the plain text first because the url might be normalized or escaped. if (dragData->containsPlainText()) - title = dragData->asPlainText(frame); + title = dragData->asPlainText(); if (title.isEmpty()) title = url; } @@ -177,7 +184,7 @@ static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragD } if (allowPlainText && dragData->containsPlainText()) { chosePlainText = true; - return createFragmentFromText(context.get(), dragData->asPlainText(frame)).get(); + return createFragmentFromText(context.get(), dragData->asPlainText()).get(); } return 0; @@ -213,9 +220,9 @@ void DragController::dragExited(DragData* dragData) if (RefPtr<FrameView> v = mainFrame->view()) { ClipboardAccessPolicy policy = (!m_documentUnderMouse || m_documentUnderMouse->securityOrigin()->isLocal()) ? ClipboardReadable : ClipboardTypesReadable; - RefPtr<Clipboard> clipboard = Clipboard::create(policy, dragData, mainFrame); + RefPtr<Clipboard> clipboard = createDraggingClipboard(policy, dragData); clipboard->setSourceOperation(dragData->draggingSourceOperationMask()); - mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get()); + mainFrame->eventHandler().cancelDragAndDrop(createMouseEvent(dragData), clipboard.get()); clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security } mouseMovedIntoDocument(0); @@ -238,9 +245,9 @@ bool DragController::performDrag(DragData* dragData) bool preventedDefault = false; if (mainFrame->view()) { // Sending an event can result in the destruction of the view and part. - RefPtr<Clipboard> clipboard = Clipboard::create(ClipboardReadable, dragData, mainFrame.get()); + RefPtr<Clipboard> clipboard = createDraggingClipboard(ClipboardReadable, dragData); clipboard->setSourceOperation(dragData->draggingSourceOperationMask()); - preventedDefault = mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get()); + preventedDefault = mainFrame->eventHandler().performDragAndDrop(createMouseEvent(dragData), clipboard.get()); clipboard->setAccessPolicy(ClipboardNumb); // Invalidate clipboard here for security } if (preventedDefault) { @@ -259,7 +266,7 @@ bool DragController::performDrag(DragData* dragData) if (operationForLoad(dragData) == DragOperationNone) return false; - m_page->mainFrame()->loader()->load(FrameLoadRequest(0, ResourceRequest(dragData->asURL(m_page->mainFrame())))); + m_page->mainFrame()->loader().load(FrameLoadRequest(0, ResourceRequest(dragData->asURL()))); return true; } @@ -310,7 +317,7 @@ static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint& float zoomFactor = frame ? frame->pageZoomFactor() : 1; LayoutPoint point = roundedLayoutPoint(FloatPoint(p.x() * zoomFactor, p.y() * zoomFactor)); - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent); HitTestResult result(point); documentUnderMouse->renderView()->hitTest(request, result); @@ -432,7 +439,7 @@ static bool setSelectionToDragCaret(Frame* frame, VisibleSelection& dragCaret, R bool DragController::dispatchTextInputEventFor(Frame* innerFrame, DragData* dragData) { ASSERT(m_page->dragCaretController().hasCaret()); - String text = m_page->dragCaretController().isContentRichlyEditable() ? "" : dragData->asPlainText(innerFrame); + String text = m_page->dragCaretController().isContentRichlyEditable() ? "" : dragData->asPlainText(); Node* target = innerFrame->editor().findEventTargetFrom(m_page->dragCaretController().caretPosition()); return target->dispatchEvent(TextEvent::createForDrop(innerFrame->domWindow(), text), IGNORE_EXCEPTION); } @@ -489,9 +496,8 @@ bool DragController::concludeEditDrag(DragData* dragData) if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) { bool chosePlainText = false; RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, innerFrame.get(), range, true, chosePlainText); - if (!fragment || !innerFrame->editor().shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { + if (!fragment) return false; - } if (dragIsMove(innerFrame->selection(), dragData)) { // NSTextView behavior is to always smart delete on moving a selection, @@ -511,10 +517,9 @@ bool DragController::concludeEditDrag(DragData* dragData) } } } else { - String text = dragData->asPlainText(innerFrame.get()); - if (text.isEmpty() || !innerFrame->editor().shouldInsertText(text, range.get(), EditorInsertActionDropped)) { + String text = dragData->asPlainText(); + if (text.isEmpty()) return false; - } if (setSelectionToDragCaret(innerFrame.get(), dragCaret, range, point)) { ASSERT(m_documentUnderMouse); @@ -524,7 +529,7 @@ bool DragController::concludeEditDrag(DragData* dragData) if (rootEditableElement) { if (Frame* frame = rootEditableElement->document().frame()) - frame->eventHandler()->updateDragStateAfterEditDragIfNeeded(rootEditableElement.get()); + frame->eventHandler().updateDragStateAfterEditDragIfNeeded(rootEditableElement.get()); } return true; @@ -542,7 +547,7 @@ bool DragController::canProcessDrag(DragData* dragData) if (!m_page->mainFrame()->contentRenderer()) return false; - result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point); + result = m_page->mainFrame()->eventHandler().hitTestResultAtPoint(point); if (!result.innerNonSharedNode()) return false; @@ -592,12 +597,12 @@ bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation) return false; ClipboardAccessPolicy policy = m_documentUnderMouse->securityOrigin()->isLocal() ? ClipboardReadable : ClipboardTypesReadable; - RefPtr<Clipboard> clipboard = Clipboard::create(policy, dragData, mainFrame.get()); + RefPtr<Clipboard> clipboard = createDraggingClipboard(policy, dragData); DragOperation srcOpMask = dragData->draggingSourceOperationMask(); clipboard->setSourceOperation(srcOpMask); PlatformMouseEvent event = createMouseEvent(dragData); - if (!mainFrame->eventHandler()->updateDragAndDrop(event, clipboard.get())) { + if (!mainFrame->eventHandler().updateDragAndDrop(event, clipboard.get())) { clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security return false; } @@ -614,45 +619,77 @@ bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation) return true; } -Node* DragController::draggableNode(const Frame* src, Node* startNode, const IntPoint& dragOrigin, DragState& state) const +Node* DragController::draggableNode(const Frame* src, Node* startNode, const IntPoint& dragOrigin, SelectionDragPolicy selectionDragPolicy, DragSourceAction& dragType) const { - state.m_dragType = (src->selection().contains(dragOrigin)) ? DragSourceActionSelection : DragSourceActionNone; + if (src->selection().contains(dragOrigin)) { + dragType = DragSourceActionSelection; + if (selectionDragPolicy == ImmediateSelectionDragResolution) + return startNode; + } else { + dragType = DragSourceActionNone; + } + Node* node = 0; + DragSourceAction candidateDragType = DragSourceActionNone; for (const RenderObject* renderer = startNode->renderer(); renderer; renderer = renderer->parent()) { - Node* node = renderer->nonPseudoNode(); - if (!node) + node = renderer->nonPseudoNode(); + if (!node) { // Anonymous render blocks don't correspond to actual DOM nodes, so we skip over them // for the purposes of finding a draggable node. continue; - if (!(state.m_dragType & DragSourceActionSelection) && node->isTextNode() && node->canStartSelection()) + } + if (dragType != DragSourceActionSelection && node->isTextNode() && node->canStartSelection()) { // In this case we have a click in the unselected portion of text. If this text is // selectable, we want to start the selection process instead of looking for a parent // to try to drag. return 0; + } if (node->isElementNode()) { EUserDrag dragMode = renderer->style()->userDrag(); if (dragMode == DRAG_NONE) continue; + // Even if the image is part of a selection, we always only drag the image in this case. if (renderer->isImage() && src->settings() && src->settings()->loadsImagesAutomatically()) { - state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionImage); + dragType = DragSourceActionImage; return node; } + // Other draggable elements are considered unselectable. if (isHTMLAnchorElement(node) && toHTMLAnchorElement(node)->isLiveLink()) { - state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionLink); - return node; + candidateDragType = DragSourceActionLink; + break; } if (dragMode == DRAG_ELEMENT) { - state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionDHTML); - return node; + candidateDragType = DragSourceActionDHTML; + break; } } } - // We either have nothing to drag or we have a selection and we're not over a draggable element. - return (state.m_dragType & DragSourceActionSelection) ? startNode : 0; + if (candidateDragType == DragSourceActionNone) { + // Either: + // 1) Nothing under the cursor is considered draggable, so we bail out. + // 2) There was a selection under the cursor but selectionDragPolicy is set to + // DelayedSelectionDragResolution and no other draggable element could be found, so bail + // out and allow text selection to start at the cursor instead. + return 0; + } + + ASSERT(node); + if (dragType == DragSourceActionSelection) { + // Dragging unselectable elements in a selection has special behavior if selectionDragPolicy + // is DelayedSelectionDragResolution and this drag was flagged as a potential selection + // drag. In that case, don't allow selection and just drag the entire selection instead. + ASSERT(selectionDragPolicy == DelayedSelectionDragResolution); + node = startNode; + } else { + // If the cursor isn't over a selection, then just drag the node we found earlier. + ASSERT(dragType == DragSourceActionNone); + dragType = candidateDragType; + } + return node; } static ImageResource* getImageResource(Element* element) @@ -683,7 +720,7 @@ static void prepareClipboardForImageDrag(Frame* source, Clipboard* clipboard, El range->selectNode(node, ASSERT_NO_EXCEPTION); source->selection().setSelection(VisibleSelection(range.get(), DOWNSTREAM)); } - clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, source); + clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label); } bool DragController::populateDragClipboard(Frame* src, const DragState& state, const IntPoint& dragOrigin) @@ -693,7 +730,7 @@ bool DragController::populateDragClipboard(Frame* src, const DragState& state, c if (!src->view() || !src->contentRenderer()) return false; - HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin, HitTestRequest::ReadOnly | HitTestRequest::Active); + HitTestResult hitTestResult = src->eventHandler().hitTestResultAtPoint(dragOrigin); // FIXME: Can this even happen? I guess it's possible, but should verify // with a layout test. if (!state.m_dragSrc->contains(hitTestResult.innerNode())) { @@ -727,7 +764,7 @@ bool DragController::populateDragClipboard(Frame* src, const DragState& state, c return false; // Simplify whitespace so the title put on the clipboard resembles what the user sees // on the web page. This includes replacing newlines with spaces. - clipboard->writeURL(linkURL, hitTestResult.textContent().simplifyWhiteSpace(), src); + clipboard->writeURL(linkURL, hitTestResult.textContent().simplifyWhiteSpace()); } // FIXME: For DHTML/draggable element drags, write element markup to clipboard. return true; @@ -813,12 +850,13 @@ bool DragController::startDrag(Frame* src, const DragState& state, const Platfor if (!src->view() || !src->contentRenderer()) return false; - HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin); - if (!state.m_dragSrc->contains(hitTestResult.innerNode())) + HitTestResult hitTestResult = src->eventHandler().hitTestResultAtPoint(dragOrigin); + if (!state.m_dragSrc->contains(hitTestResult.innerNode())) { // The original node being dragged isn't under the drag origin anymore... maybe it was // hidden or moved out from under the cursor. Regardless, we don't want to start a drag on // something that's not actually under the drag origin. return false; + } const KURL& linkURL = hitTestResult.absoluteLinkURL(); const KURL& imageURL = hitTestResult.absoluteImageURL(); @@ -830,7 +868,7 @@ bool DragController::startDrag(Frame* src, const DragState& state, const Platfor Clipboard* clipboard = state.m_dragClipboard.get(); // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. - OwnPtr<DragImage> dragImage = clipboard->createDragImage(dragOffset); + OwnPtr<DragImage> dragImage = clipboard->createDragImage(dragOffset, src); if (dragImage) { dragLocation = dragLocationForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragOffset, !linkURL.isEmpty()); } @@ -910,7 +948,7 @@ DragOperation DragController::dragOperation(DragData* dragData) // attached sheet If this can be determined from within WebCore // operationForDrag can be pulled into WebCore itself ASSERT(dragData); - return dragData->containsURL(0) && !m_didInitiateDrag ? DragOperationCopy : DragOperationNone; + return dragData->containsURL() && !m_didInitiateDrag ? DragOperationCopy : DragOperationNone; } bool DragController::isCopyKeyDown(DragData*) |