bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask, DragOperation& operation)
{
    ASSERT(dragData);

    if (!m_documentUnderMouse)
        return false;

    m_isHandlingDrag = false;
    if (actionMask & DragDestinationActionDHTML) {
        m_isHandlingDrag = tryDHTMLDrag(dragData, operation);
        // Do not continue if m_documentUnderMouse has been reset by tryDHTMLDrag.
        // tryDHTMLDrag fires dragenter event. The event listener that listens
        // to this event may create a nested message loop (open a modal dialog),
        // which could process dragleave event and reset m_documentUnderMouse in
        // dragExited.
        if (!m_documentUnderMouse)
            return false;
    }

    // It's unclear why this check is after tryDHTMLDrag.
    // We send drag events in tryDHTMLDrag and that may be the reason.
    RefPtr<FrameView> frameView = m_documentUnderMouse->view();
    if (!frameView)
        return false;

    if (m_isHandlingDrag) {
        m_page->dragCaretController()->clear();
        return true;
    } else if ((actionMask & DragDestinationActionEdit) && canProcessDrag(dragData)) {
        if (dragData->containsColor()) {
            operation = DragOperationGeneric;
            return true;
        }

        IntPoint point = frameView->windowToContents(dragData->clientPosition());
        Element* element = elementUnderMouse(m_documentUnderMouse, point);
        if (!asFileInput(element)) {
            VisibleSelection dragCaret = m_documentUnderMouse->frame()->visiblePositionForPoint(point);
            m_page->dragCaretController()->setSelection(dragCaret);
        }

        Frame* innerFrame = element->document()->frame();
        operation = dragIsMove(innerFrame->selection()) ? DragOperationMove : DragOperationCopy;
        return true;
    }
    // If we're not over an editable region, make sure we're clearing any prior drag cursor.
    m_page->dragCaretController()->clear();
    return false;
}
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)) {
            Selection 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;
}
Exemple #3
0
bool DragController::concludeEditDrag(DragData* dragData)
{
    ASSERT(dragData);

    RefPtr<HTMLInputElement> fileInput = m_fileInputElementUnderMouse;
    if (m_fileInputElementUnderMouse) {
        m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false);
        m_fileInputElementUnderMouse = 0;
    }

    if (!m_documentUnderMouse)
        return false;

    IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition());
    Element* element = elementUnderMouse(m_documentUnderMouse.get(), point);
    if (!element)
        return false;
    Frame* innerFrame = element->ownerDocument()->frame();
    ASSERT(innerFrame);

    if (m_page->dragCaretController()->hasCaret() && !dispatchTextInputEventFor(innerFrame, dragData))
        return true;

    if (dragData->containsColor()) {
        Color color = dragData->asColor();
        if (!color.isValid())
            return false;
        RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange();
        RefPtr<StylePropertySet> style = StylePropertySet::create();
        style->setProperty(CSSPropertyColor, color.serialized(), false);
        if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get()))
            return false;
        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
        innerFrame->editor()->applyStyle(style.get(), EditActionSetColor);
        return true;
    }

    if (dragData->containsFiles() && fileInput) {
        // fileInput should be the element we hit tested for, unless it was made
        // display:none in a drop event handler.
        ASSERT(fileInput == element || !fileInput->renderer());
        if (fileInput->disabled())
            return false;

        Vector<String> filenames;
        dragData->asFilenames(filenames);
        if (filenames.isEmpty())
            return false;

        fileInput->receiveDroppedFiles(filenames);
        m_client->willPerformDragDestinationAction(DragDestinationActionUpload, dragData);
        return true;
    }

    if (!m_page->dragController()->canProcessDrag(dragData)) {
        m_page->dragCaretController()->clear();
        return false;
    }

    VisibleSelection dragCaret = m_page->dragCaretController()->caretPosition();
    m_page->dragCaretController()->clear();
    RefPtr<Range> range = dragCaret.toNormalizedRange();
    RefPtr<Element> rootEditableElement = innerFrame->selection()->rootEditableElement();

    // For range to be null a WebKit client must have done something bad while
    // manually controlling drag behaviour
    if (!range)
        return false;
    CachedResourceLoader* cachedResourceLoader = range->ownerDocument()->cachedResourceLoader();
    ResourceCacheValidationSuppressor validationSuppressor(cachedResourceLoader);
    if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) {
        bool chosePlainText = false;
        RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, innerFrame, range, true, chosePlainText);
        if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) {
            return false;
        }

        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
        if (dragIsMove(innerFrame->selection(), dragData)) {
            // NSTextView behavior is to always smart delete on moving a selection,
            // but only to smart insert if the selection granularity is word granularity.
            bool smartDelete = innerFrame->editor()->smartInsertDeleteEnabled();
            bool smartInsert = smartDelete && innerFrame->selection()->granularity() == WordGranularity && dragData->canSmartReplace();
            applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartInsert, smartDelete));
        } else {
            if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) {
                ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::PreventNesting;
                if (dragData->canSmartReplace())
                    options |= ReplaceSelectionCommand::SmartReplace;
                if (chosePlainText)
                    options |= ReplaceSelectionCommand::MatchStyle;
                applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), fragment, options));
            }
        }
    } else {
        String text = dragData->asPlainText(innerFrame);
        if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) {
            return false;
        }

        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
        if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
            applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), createFragmentFromText(range.get(), text),  ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting));
    }

    if (rootEditableElement) {
        if (Frame* frame = rootEditableElement->document()->frame())
            frame->eventHandler()->updateDragStateAfterEditDragIfNeeded(rootEditableElement.get());
    }

    return true;
}
Exemple #4
0
bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask, DragSession& dragSession)
{
    ASSERT(dragData);

    if (!m_documentUnderMouse)
        return false;

    if (m_dragInitiator && !m_documentUnderMouse->securityOrigin()->canReceiveDragData(m_dragInitiator->securityOrigin()))
        return false;

    m_isHandlingDrag = false;
    if (actionMask & DragDestinationActionDHTML) {
        m_isHandlingDrag = tryDHTMLDrag(dragData, dragSession.operation);
        // Do not continue if m_documentUnderMouse has been reset by tryDHTMLDrag.
        // tryDHTMLDrag fires dragenter event. The event listener that listens
        // to this event may create a nested message loop (open a modal dialog),
        // which could process dragleave event and reset m_documentUnderMouse in
        // dragExited.
        if (!m_documentUnderMouse)
            return false;
    }

    // It's unclear why this check is after tryDHTMLDrag.
    // We send drag events in tryDHTMLDrag and that may be the reason.
    RefPtr<FrameView> frameView = m_documentUnderMouse->view();
    if (!frameView)
        return false;

    if (m_isHandlingDrag) {
        m_page->dragCaretController()->clear();
        return true;
    } else if ((actionMask & DragDestinationActionEdit) && canProcessDrag(dragData)) {
        if (dragData->containsColor()) {
            dragSession.operation = DragOperationGeneric;
            return true;
        }

        IntPoint point = frameView->windowToContents(dragData->clientPosition());
        Element* element = elementUnderMouse(m_documentUnderMouse.get(), point);
        if (!element)
            return false;

        HTMLInputElement* elementAsFileInput = asFileInput(element);
        if (m_fileInputElementUnderMouse != elementAsFileInput) {
            if (m_fileInputElementUnderMouse)
                m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false);
            m_fileInputElementUnderMouse = elementAsFileInput;
        }

        if (!m_fileInputElementUnderMouse)
            m_page->dragCaretController()->setCaretPosition(m_documentUnderMouse->frame()->visiblePositionForPoint(point));

        Frame* innerFrame = element->document()->frame();
        dragSession.operation = dragIsMove(innerFrame->selection(), dragData) ? DragOperationMove : DragOperationCopy;
        dragSession.mouseIsOverFileInput = m_fileInputElementUnderMouse;
        dragSession.numberOfItemsToBeAccepted = 0;

        unsigned numberOfFiles = dragData->numberOfFiles();
        if (m_fileInputElementUnderMouse) {
            if (m_fileInputElementUnderMouse->disabled())
                dragSession.numberOfItemsToBeAccepted = 0;
            else if (m_fileInputElementUnderMouse->multiple())
                dragSession.numberOfItemsToBeAccepted = numberOfFiles;
            else if (numberOfFiles > 1)
                dragSession.numberOfItemsToBeAccepted = 0;
            else
                dragSession.numberOfItemsToBeAccepted = 1;

            if (!dragSession.numberOfItemsToBeAccepted)
                dragSession.operation = DragOperationNone;
            m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(dragSession.numberOfItemsToBeAccepted);
        } else {
            // We are not over a file input element. The dragged item(s) will only
            // be loaded into the view the number of dragged items is 1.
            dragSession.numberOfItemsToBeAccepted = numberOfFiles != 1 ? 0 : 1;
        }

        return true;
    }

    // We are not over an editable region. Make sure we're clearing any prior drag cursor.
    m_page->dragCaretController()->clear();
    if (m_fileInputElementUnderMouse)
        m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false);
    m_fileInputElementUnderMouse = 0;
    return false;
}
bool DragController::concludeEditDrag(DragData* dragData)
{
    ASSERT(dragData);
    ASSERT(!m_isHandlingDrag);

    if (!m_documentUnderMouse)
        return false;

    IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition());
    Element* element = elementUnderMouse(m_documentUnderMouse, point);
    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_documentUnderMouse->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->isEnabledFormControl())
            return false;

        if (!dragData->containsFiles())
            return false;

        Vector<String> filenames;
        dragData->asFilenames(filenames);
        if (filenames.isEmpty())
            return false;

        // Ugly. For security none of the APIs available to us can 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 = toRenderFileUploadControl(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)
        return false;
    DocLoader* loader = range->ownerDocument()->docLoader();
    loader->setAllowStaleResources(true);
    if (dragIsMove(innerFrame->selection()) || dragCaret.isContentRichlyEditable()) {
        bool chosePlainText = false;
        RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText);
        if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) {
            loader->setAllowStaleResources(false);
            return false;
        }

        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
        if (dragIsMove(innerFrame->selection())) {
            bool smartMove = innerFrame->selectionGranularity() == WordGranularity
                          && innerFrame->editor()->smartInsertDeleteEnabled()
                          && dragData->canSmartReplace();
            applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartMove));
        } else {
            if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
                applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, fragment, true, dragData->canSmartReplace(), chosePlainText));
        }
    } else {
        String text = dragData->asPlainText();
        if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) {
            loader->setAllowStaleResources(false);
            return false;
        }

        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
        if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
            applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, createFragmentFromText(range.get(), text), true, false, true));
    }
    loader->setAllowStaleResources(false);

    return true;
}