📄 dragcontroller.cpp
字号:
/* * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "DragController.h"#include "CSSStyleDeclaration.h"#include "Clipboard.h"#include "ClipboardAccessPolicy.h"#include "DocLoader.h"#include "Document.h"#include "DocumentFragment.h"#include "DragActions.h"#include "DragClient.h"#include "DragData.h"#include "Editor.h"#include "EditorClient.h"#include "Element.h"#include "EventHandler.h"#include "FloatRect.h"#include "Frame.h"#include "FrameLoader.h"#include "FrameView.h"#include "HTMLAnchorElement.h"#include "HTMLInputElement.h"#include "HTMLNames.h"#include "HitTestResult.h"#include "Image.h"#include "MoveSelectionCommand.h"#include "Node.h"#include "Page.h"#include "RenderFileUploadControl.h"#include "RenderImage.h"#include "ReplaceSelectionCommand.h"#include "ResourceRequest.h"#include "SelectionController.h"#include "Settings.h"#include "Text.h"#include "htmlediting.h"#include "markup.h"#include <wtf/CurrentTime.h>#include <wtf/RefPtr.h>namespace WebCore {static PlatformMouseEvent createMouseEvent(DragData* dragData){ // FIXME: We should fake modifier keys here. return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPosition(), LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime());} DragController::DragController(Page* page, DragClient* client) : m_page(page) , m_client(client) , m_document(0) , m_dragInitiator(0) , m_dragDestinationAction(DragDestinationActionNone) , m_dragSourceAction(DragSourceActionNone) , m_didInitiateDrag(false) , m_isHandlingDrag(false) , m_dragOperation(DragOperationNone){} DragController::~DragController(){ m_client->dragControllerDestroyed();} static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragData, RefPtr<Range> context, bool allowPlainText, bool& chosePlainText){ ASSERT(dragData); chosePlainText = false; Document* document = context->ownerDocument(); ASSERT(document); if (document && dragData->containsCompatibleContent()) { if (PassRefPtr<DocumentFragment> fragment = dragData->asFragment(document)) return fragment; if (dragData->containsURL()) { String title; String url = dragData->asURL(&title); if (!url.isEmpty()) { RefPtr<HTMLAnchorElement> anchor = new HTMLAnchorElement(document); anchor->setHref(url); ExceptionCode ec; RefPtr<Node> anchorText = document->createTextNode(title); anchor->appendChild(anchorText, ec); RefPtr<DocumentFragment> fragment = document->createDocumentFragment(); fragment->appendChild(anchor, ec); return fragment.get(); } } } if (allowPlainText && dragData->containsPlainText()) { chosePlainText = true; return createFragmentFromText(context.get(), dragData->asPlainText()).get(); } return 0;}bool DragController::dragIsMove(SelectionController* selection){ return m_document == m_dragInitiator && selection->isContentEditable() && !isCopyKeyDown();}void DragController::cancelDrag(){ m_page->dragCaretController()->clear();}void DragController::dragEnded(){ m_dragInitiator = 0; m_didInitiateDrag = false; m_page->dragCaretController()->clear(); } DragOperation DragController::dragEntered(DragData* dragData) { return dragEnteredOrUpdated(dragData);} void DragController::dragExited(DragData* dragData) { ASSERT(dragData); Frame* mainFrame = m_page->mainFrame(); if (RefPtr<FrameView> v = mainFrame->view()) { ClipboardAccessPolicy policy = mainFrame->loader()->baseURL().isLocalFile() ? ClipboardReadable : ClipboardTypesReadable; RefPtr<Clipboard> clipboard = dragData->createClipboard(policy); clipboard->setSourceOperation(dragData->draggingSourceOperationMask()); mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get()); clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security } cancelDrag(); m_document = 0;} DragOperation DragController::dragUpdated(DragData* dragData) { return dragEnteredOrUpdated(dragData);} bool DragController::performDrag(DragData* dragData){ ASSERT(dragData); m_document = m_page->mainFrame()->documentAtPoint(dragData->clientPosition()); if (m_isHandlingDrag) { ASSERT(m_dragDestinationAction & DragDestinationActionDHTML); m_client->willPerformDragDestinationAction(DragDestinationActionDHTML, dragData); RefPtr<Frame> mainFrame = m_page->mainFrame(); if (mainFrame->view()) { // Sending an event can result in the destruction of the view and part. RefPtr<Clipboard> clipboard = dragData->createClipboard(ClipboardReadable); clipboard->setSourceOperation(dragData->draggingSourceOperationMask()); mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get()); clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security } m_document = 0; return true; } if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeEditDrag(dragData)) { m_document = 0; return true; } m_document = 0; if (operationForLoad(dragData) == DragOperationNone) return false; m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragData); m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL()), false); return true;} DragOperation DragController::dragEnteredOrUpdated(DragData* dragData){ ASSERT(dragData); IntPoint windowPoint = dragData->clientPosition(); Document* newDraggingDoc = 0; if (Frame* frame = m_page->mainFrame()) newDraggingDoc = frame->documentAtPoint(windowPoint); if (m_document != newDraggingDoc) { if (m_document) cancelDrag(); m_document = newDraggingDoc; } m_dragDestinationAction = m_client->actionMaskForDrag(dragData); DragOperation operation = DragOperationNone; if (m_dragDestinationAction == DragDestinationActionNone) cancelDrag(); else { operation = tryDocumentDrag(dragData, m_dragDestinationAction); if (operation == DragOperationNone && (m_dragDestinationAction & DragDestinationActionLoad)) return operationForLoad(dragData); } return operation;}static HTMLInputElement* asFileInput(Node* node){ ASSERT(node); // The button for a FILE input is a sub element with no set input type // In order to get around this problem we assume any non-FILE input element // is this internal button, and try querying the shadow parent node. if (node->hasTagName(HTMLNames::inputTag) && node->isShadowNode() && static_cast<HTMLInputElement*>(node)->inputType() != HTMLInputElement::FILE) node = node->shadowParentNode(); if (!node || !node->hasTagName(HTMLNames::inputTag)) return 0; HTMLInputElement* inputElem = static_cast<HTMLInputElement*>(node); if (inputElem->inputType() == HTMLInputElement::FILE) return inputElem; return 0;} DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask){ ASSERT(dragData); if (!m_document) return DragOperationNone; DragOperation operation = DragOperationNone; if (actionMask & DragDestinationActionDHTML) operation = tryDHTMLDrag(dragData); m_isHandlingDrag = operation != DragOperationNone; RefPtr<FrameView> frameView = m_document->view(); if (!frameView) return operation; if ((actionMask & DragDestinationActionEdit) && !m_isHandlingDrag && canProcessDrag(dragData)) { if (dragData->containsColor()) return DragOperationGeneric; IntPoint dragPos = dragData->clientPosition(); IntPoint point = frameView->windowToContents(dragPos); Element* element = m_document->elementFromPoint(point.x(), point.y()); ASSERT(element); Frame* innerFrame = element->document()->frame(); ASSERT(innerFrame); if (!asFileInput(element)) { VisibleSelection dragCaret; if (Frame* frame = m_document->frame()) dragCaret = frame->visiblePositionForPoint(point); m_page->dragCaretController()->setSelection(dragCaret); } return dragIsMove(innerFrame->selection()) ? DragOperationMove : DragOperationCopy; } m_page->dragCaretController()->clear(); return operation;}DragSourceAction DragController::delegateDragSourceAction(const IntPoint& windowPoint){ m_dragSourceAction = m_client->dragSourceActionMaskForPoint(windowPoint); return m_dragSourceAction;} DragOperation DragController::operationForLoad(DragData* dragData){ ASSERT(dragData); Document* doc = 0; doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition()); if (doc && (m_didInitiateDrag || doc->isPluginDocument() || (doc->frame() && doc->frame()->editor()->clientIsEditable()))) return DragOperationNone; return dragOperation(dragData);}static bool setSelectionToDragCaret(Frame* frame, VisibleSelection& dragCaret, RefPtr<Range>& range, const IntPoint& point){ frame->selection()->setSelection(dragCaret); if (frame->selection()->isNone()) { dragCaret = frame->visiblePositionForPoint(point); frame->selection()->setSelection(dragCaret); range = dragCaret.toNormalizedRange(); } return !frame->selection()->isNone() && frame->selection()->isContentEditable();}bool DragController::concludeEditDrag(DragData* dragData){ ASSERT(dragData); ASSERT(!m_isHandlingDrag); if (!m_document) return false; IntPoint point = m_document->view()->windowToContents(dragData->clientPosition()); Element* element = m_document->elementFromPoint(point.x(), point.y()); ASSERT(element); Frame* innerFrame = element->ownerDocument()->frame(); ASSERT(innerFrame); if (dragData->containsColor()) { Color color = dragData->asColor(); if (!color.isValid()) return false; if (!innerFrame) return false; RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange(); RefPtr<CSSStyleDeclaration> style = m_document->createCSSStyleDeclaration(); ExceptionCode ec; style->setProperty("color", color.name(), ec); if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get())) return false; m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); innerFrame->editor()->applyStyle(style.get(), EditActionSetColor); return true; } if (!m_page->dragController()->canProcessDrag(dragData)) { m_page->dragCaretController()->clear(); return false; } if (HTMLInputElement* fileInput = asFileInput(element)) { if (!fileInput->isEnabled()) return false; if (!dragData->containsFiles()) return false; Vector<String> filenames; dragData->asFilenames(filenames); if (filenames.isEmpty()) return false; // Ugly. For security none of the API's available to us to set the input value // on file inputs. Even forcing a change in HTMLInputElement doesn't work as // RenderFileUploadControl clears the file when doing updateFromElement() RenderFileUploadControl* renderer = static_cast<RenderFileUploadControl*>(fileInput->renderer()); if (!renderer) return false; renderer->receiveDroppedFiles(filenames); return true; } VisibleSelection dragCaret(m_page->dragCaretController()->selection()); m_page->dragCaretController()->clear(); RefPtr<Range> range = dragCaret.toNormalizedRange(); // For range to be null a WebKit client must have done something bad while // manually controlling drag behaviour if (!range)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -