~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/page/DragController.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 
24
 */
 
25
 
 
26
#include "config.h"
 
27
#include "DragController.h"
 
28
 
 
29
#if ENABLE(DRAG_SUPPORT)
 
30
#include "Clipboard.h"
 
31
#include "ClipboardAccessPolicy.h"
 
32
#include "CachedResourceLoader.h"
 
33
#include "Document.h"
 
34
#include "DocumentFragment.h"
 
35
#include "DragActions.h"
 
36
#include "DragClient.h"
 
37
#include "DragData.h"
 
38
#include "DragSession.h"
 
39
#include "Editor.h"
 
40
#include "EditorClient.h"
 
41
#include "Element.h"
 
42
#include "EventHandler.h"
 
43
#include "FloatRect.h"
 
44
#include "Frame.h"
 
45
#include "FrameLoadRequest.h"
 
46
#include "FrameLoader.h"
 
47
#include "FrameSelection.h"
 
48
#include "FrameView.h"
 
49
#include "HTMLAnchorElement.h"
 
50
#include "HTMLInputElement.h"
 
51
#include "HTMLNames.h"
 
52
#include "HTMLPlugInElement.h"
 
53
#include "HitTestRequest.h"
 
54
#include "HitTestResult.h"
 
55
#include "Image.h"
 
56
#include "ImageOrientation.h"
 
57
#include "MoveSelectionCommand.h"
 
58
#include "Node.h"
 
59
#include "Page.h"
 
60
#include "PlatformKeyboardEvent.h"
 
61
#include "RenderFileUploadControl.h"
 
62
#include "RenderImage.h"
 
63
#include "RenderView.h"
 
64
#include "ReplaceSelectionCommand.h"
 
65
#include "ResourceRequest.h"
 
66
#include "SecurityOrigin.h"
 
67
#include "Settings.h"
 
68
#include "ShadowRoot.h"
 
69
#include "StylePropertySet.h"
 
70
#include "Text.h"
 
71
#include "TextEvent.h"
 
72
#include "htmlediting.h"
 
73
#include "markup.h"
 
74
#include <wtf/CurrentTime.h>
 
75
#include <wtf/RefPtr.h>
 
76
 
 
77
namespace WebCore {
 
78
 
 
79
static PlatformMouseEvent createMouseEvent(DragData* dragData)
 
80
{
 
81
    bool shiftKey, ctrlKey, altKey, metaKey;
 
82
    shiftKey = ctrlKey = altKey = metaKey = false;
 
83
    int keyState = dragData->modifierKeyState();
 
84
    shiftKey = static_cast<bool>(keyState & PlatformEvent::ShiftKey);
 
85
    ctrlKey = static_cast<bool>(keyState & PlatformEvent::CtrlKey);
 
86
    altKey = static_cast<bool>(keyState & PlatformEvent::AltKey);
 
87
    metaKey = static_cast<bool>(keyState & PlatformEvent::MetaKey);
 
88
 
 
89
    return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPosition(),
 
90
                              LeftButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey,
 
91
                              metaKey, currentTime());
 
92
}
 
93
 
 
94
DragController::DragController(Page* page, DragClient* client)
 
95
    : m_page(page)
 
96
    , m_client(client)
 
97
    , m_documentUnderMouse(0)
 
98
    , m_dragInitiator(0)
 
99
    , m_fileInputElementUnderMouse(0)
 
100
    , m_documentIsHandlingDrag(false)
 
101
    , m_dragDestinationAction(DragDestinationActionNone)
 
102
    , m_dragSourceAction(DragSourceActionNone)
 
103
    , m_didInitiateDrag(false)
 
104
    , m_sourceDragOperation(DragOperationNone)
 
105
{
 
106
    ASSERT(m_client);
 
107
}
 
108
 
 
109
DragController::~DragController()
 
110
{
 
111
    m_client->dragControllerDestroyed();
 
112
}
 
113
 
 
114
PassOwnPtr<DragController> DragController::create(Page* page, DragClient* client)
 
115
{
 
116
    return adoptPtr(new DragController(page, client));
 
117
}
 
118
 
 
119
static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragData, Frame* frame, RefPtr<Range> context,
 
120
                                          bool allowPlainText, bool& chosePlainText)
 
121
{
 
122
    ASSERT(dragData);
 
123
    chosePlainText = false;
 
124
 
 
125
    Document* document = context->ownerDocument();
 
126
    ASSERT(document);
 
127
    if (document && dragData->containsCompatibleContent()) {
 
128
        if (PassRefPtr<DocumentFragment> fragment = dragData->asFragment(frame, context, allowPlainText, chosePlainText))
 
129
            return fragment;
 
130
 
 
131
        if (dragData->containsURL(frame, DragData::DoNotConvertFilenames)) {
 
132
            String title;
 
133
            String url = dragData->asURL(frame, DragData::DoNotConvertFilenames, &title);
 
134
            if (!url.isEmpty()) {
 
135
                RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(document);
 
136
                anchor->setHref(url);
 
137
                if (title.isEmpty()) {
 
138
                    // Try the plain text first because the url might be normalized or escaped.
 
139
                    if (dragData->containsPlainText())
 
140
                        title = dragData->asPlainText(frame);
 
141
                    if (title.isEmpty())
 
142
                        title = url;
 
143
                }
 
144
                RefPtr<Node> anchorText = document->createTextNode(title);
 
145
                ExceptionCode ec;
 
146
                anchor->appendChild(anchorText, ec);
 
147
                RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
 
148
                fragment->appendChild(anchor, ec);
 
149
                return fragment.get();
 
150
            }
 
151
        }
 
152
    }
 
153
    if (allowPlainText && dragData->containsPlainText()) {
 
154
        chosePlainText = true;
 
155
        return createFragmentFromText(context.get(), dragData->asPlainText(frame)).get();
 
156
    }
 
157
 
 
158
    return 0;
 
159
}
 
160
 
 
161
bool DragController::dragIsMove(FrameSelection* selection, DragData* dragData)
 
162
{
 
163
    return m_documentUnderMouse == m_dragInitiator && selection->isContentEditable() && selection->isRange() && !isCopyKeyDown(dragData);
 
164
}
 
165
 
 
166
// FIXME: This method is poorly named.  We're just clearing the selection from the document this drag is exiting.
 
167
void DragController::cancelDrag()
 
168
{
 
169
    m_page->dragCaretController()->clear();
 
170
}
 
171
 
 
172
void DragController::dragEnded()
 
173
{
 
174
    m_dragInitiator = 0;
 
175
    m_didInitiateDrag = false;
 
176
    m_page->dragCaretController()->clear();
 
177
    
 
178
    m_client->dragEnded();
 
179
}
 
180
 
 
181
DragSession DragController::dragEntered(DragData* dragData)
 
182
{
 
183
    return dragEnteredOrUpdated(dragData);
 
184
}
 
185
 
 
186
void DragController::dragExited(DragData* dragData)
 
187
{
 
188
    ASSERT(dragData);
 
189
    Frame* mainFrame = m_page->mainFrame();
 
190
 
 
191
    if (RefPtr<FrameView> v = mainFrame->view()) {
 
192
        ClipboardAccessPolicy policy = (!m_documentUnderMouse || m_documentUnderMouse->securityOrigin()->isLocal()) ? ClipboardReadable : ClipboardTypesReadable;
 
193
        RefPtr<Clipboard> clipboard = Clipboard::create(policy, dragData, mainFrame);
 
194
        clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
 
195
        mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get());
 
196
        clipboard->setAccessPolicy(ClipboardNumb);    // invalidate clipboard here for security
 
197
    }
 
198
    mouseMovedIntoDocument(0);
 
199
    if (m_fileInputElementUnderMouse)
 
200
        m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false);
 
201
    m_fileInputElementUnderMouse = 0;
 
202
}
 
203
 
 
204
DragSession DragController::dragUpdated(DragData* dragData)
 
205
{
 
206
    return dragEnteredOrUpdated(dragData);
 
207
}
 
208
 
 
209
bool DragController::performDrag(DragData* dragData)
 
210
{
 
211
    ASSERT(dragData);
 
212
    m_documentUnderMouse = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
 
213
    if ((m_dragDestinationAction & DragDestinationActionDHTML) && m_documentIsHandlingDrag) {
 
214
        m_client->willPerformDragDestinationAction(DragDestinationActionDHTML, dragData);
 
215
        RefPtr<Frame> mainFrame = m_page->mainFrame();
 
216
        bool preventedDefault = false;
 
217
        if (mainFrame->view()) {
 
218
            // Sending an event can result in the destruction of the view and part.
 
219
            RefPtr<Clipboard> clipboard = Clipboard::create(ClipboardReadable, dragData, mainFrame.get());
 
220
            clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
 
221
            preventedDefault = mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get());
 
222
            clipboard->setAccessPolicy(ClipboardNumb); // Invalidate clipboard here for security
 
223
        }
 
224
        if (preventedDefault) {
 
225
            m_documentUnderMouse = 0;
 
226
            return true;
 
227
        }
 
228
    }
 
229
 
 
230
    if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeEditDrag(dragData)) {
 
231
        m_documentUnderMouse = 0;
 
232
        return true;
 
233
    }
 
234
 
 
235
    m_documentUnderMouse = 0;
 
236
 
 
237
    if (operationForLoad(dragData) == DragOperationNone)
 
238
        return false;
 
239
 
 
240
    m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragData);
 
241
    m_page->mainFrame()->loader()->load(FrameLoadRequest(m_page->mainFrame(), ResourceRequest(dragData->asURL(m_page->mainFrame()))));
 
242
    return true;
 
243
}
 
244
 
 
245
void DragController::mouseMovedIntoDocument(Document* newDocument)
 
246
{
 
247
    if (m_documentUnderMouse == newDocument)
 
248
        return;
 
249
 
 
250
    // If we were over another document clear the selection
 
251
    if (m_documentUnderMouse)
 
252
        cancelDrag();
 
253
    m_documentUnderMouse = newDocument;
 
254
}
 
255
 
 
256
DragSession DragController::dragEnteredOrUpdated(DragData* dragData)
 
257
{
 
258
    ASSERT(dragData);
 
259
    ASSERT(m_page->mainFrame());
 
260
    mouseMovedIntoDocument(m_page->mainFrame()->documentAtPoint(dragData->clientPosition()));
 
261
 
 
262
    m_dragDestinationAction = m_client->actionMaskForDrag(dragData);
 
263
    if (m_dragDestinationAction == DragDestinationActionNone) {
 
264
        cancelDrag(); // FIXME: Why not call mouseMovedIntoDocument(0)?
 
265
        return DragSession();
 
266
    }
 
267
 
 
268
    DragSession dragSession;
 
269
    m_documentIsHandlingDrag = tryDocumentDrag(dragData, m_dragDestinationAction, dragSession);
 
270
    if (!m_documentIsHandlingDrag && (m_dragDestinationAction & DragDestinationActionLoad))
 
271
        dragSession.operation = operationForLoad(dragData);
 
272
    return dragSession;
 
273
}
 
274
 
 
275
static HTMLInputElement* asFileInput(Node* node)
 
276
{
 
277
    ASSERT(node);
 
278
 
 
279
    HTMLInputElement* inputElement = node->toInputElement();
 
280
 
 
281
    // If this is a button inside of the a file input, move up to the file input.
 
282
    if (inputElement && inputElement->isTextButton() && inputElement->treeScope()->rootNode()->isShadowRoot())
 
283
        inputElement = toShadowRoot(inputElement->treeScope()->rootNode())->host()->toInputElement();
 
284
 
 
285
    return inputElement && inputElement->isFileUpload() ? inputElement : 0;
 
286
}
 
287
 
 
288
// This can return null if an empty document is loaded.
 
289
static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint& p)
 
290
{
 
291
    Frame* frame = documentUnderMouse->frame();
 
292
    float zoomFactor = frame ? frame->pageZoomFactor() : 1;
 
293
    LayoutPoint point = roundedLayoutPoint(FloatPoint(p.x() * zoomFactor, p.y() * zoomFactor));
 
294
 
 
295
    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
 
296
    HitTestResult result(point);
 
297
    documentUnderMouse->renderView()->hitTest(request, result);
 
298
 
 
299
    Node* n = result.innerNode();
 
300
    while (n && !n->isElementNode())
 
301
        n = n->parentNode();
 
302
    if (n)
 
303
        n = n->shadowAncestorNode();
 
304
 
 
305
    return static_cast<Element*>(n);
 
306
}
 
307
 
 
308
bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask, DragSession& dragSession)
 
309
{
 
310
    ASSERT(dragData);
 
311
 
 
312
    if (!m_documentUnderMouse)
 
313
        return false;
 
314
 
 
315
    if (m_dragInitiator && !m_documentUnderMouse->securityOrigin()->canReceiveDragData(m_dragInitiator->securityOrigin()))
 
316
        return false;
 
317
 
 
318
    bool isHandlingDrag = false;
 
319
    if (actionMask & DragDestinationActionDHTML) {
 
320
        isHandlingDrag = tryDHTMLDrag(dragData, dragSession.operation);
 
321
        // Do not continue if m_documentUnderMouse has been reset by tryDHTMLDrag.
 
322
        // tryDHTMLDrag fires dragenter event. The event listener that listens
 
323
        // to this event may create a nested message loop (open a modal dialog),
 
324
        // which could process dragleave event and reset m_documentUnderMouse in
 
325
        // dragExited.
 
326
        if (!m_documentUnderMouse)
 
327
            return false;
 
328
    }
 
329
 
 
330
    // It's unclear why this check is after tryDHTMLDrag.
 
331
    // We send drag events in tryDHTMLDrag and that may be the reason.
 
332
    RefPtr<FrameView> frameView = m_documentUnderMouse->view();
 
333
    if (!frameView)
 
334
        return false;
 
335
 
 
336
    if (isHandlingDrag) {
 
337
        m_page->dragCaretController()->clear();
 
338
        return true;
 
339
    }
 
340
 
 
341
    if ((actionMask & DragDestinationActionEdit) && canProcessDrag(dragData)) {
 
342
        if (dragData->containsColor()) {
 
343
            dragSession.operation = DragOperationGeneric;
 
344
            return true;
 
345
        }
 
346
 
 
347
        IntPoint point = frameView->windowToContents(dragData->clientPosition());
 
348
        Element* element = elementUnderMouse(m_documentUnderMouse.get(), point);
 
349
        if (!element)
 
350
            return false;
 
351
        
 
352
        HTMLInputElement* elementAsFileInput = asFileInput(element);
 
353
        if (m_fileInputElementUnderMouse != elementAsFileInput) {
 
354
            if (m_fileInputElementUnderMouse)
 
355
                m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false);
 
356
            m_fileInputElementUnderMouse = elementAsFileInput;
 
357
        }
 
358
        
 
359
        if (!m_fileInputElementUnderMouse)
 
360
            m_page->dragCaretController()->setCaretPosition(m_documentUnderMouse->frame()->visiblePositionForPoint(point));
 
361
 
 
362
        Frame* innerFrame = element->document()->frame();
 
363
        dragSession.operation = dragIsMove(innerFrame->selection(), dragData) ? DragOperationMove : DragOperationCopy;
 
364
        dragSession.mouseIsOverFileInput = m_fileInputElementUnderMouse;
 
365
        dragSession.numberOfItemsToBeAccepted = 0;
 
366
 
 
367
        unsigned numberOfFiles = dragData->numberOfFiles();
 
368
        if (m_fileInputElementUnderMouse) {
 
369
            if (m_fileInputElementUnderMouse->disabled())
 
370
                dragSession.numberOfItemsToBeAccepted = 0;
 
371
            else if (m_fileInputElementUnderMouse->multiple())
 
372
                dragSession.numberOfItemsToBeAccepted = numberOfFiles;
 
373
            else if (numberOfFiles > 1)
 
374
                dragSession.numberOfItemsToBeAccepted = 0;
 
375
            else
 
376
                dragSession.numberOfItemsToBeAccepted = 1;
 
377
            
 
378
            if (!dragSession.numberOfItemsToBeAccepted)
 
379
                dragSession.operation = DragOperationNone;
 
380
            m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(dragSession.numberOfItemsToBeAccepted);
 
381
        } else {
 
382
            // We are not over a file input element. The dragged item(s) will only
 
383
            // be loaded into the view the number of dragged items is 1.
 
384
            dragSession.numberOfItemsToBeAccepted = numberOfFiles != 1 ? 0 : 1;
 
385
        }
 
386
        
 
387
        return true;
 
388
    }
 
389
    
 
390
    // We are not over an editable region. Make sure we're clearing any prior drag cursor.
 
391
    m_page->dragCaretController()->clear();
 
392
    if (m_fileInputElementUnderMouse)
 
393
        m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false);
 
394
    m_fileInputElementUnderMouse = 0;
 
395
    return false;
 
396
}
 
397
 
 
398
DragSourceAction DragController::delegateDragSourceAction(const IntPoint& rootViewPoint)
 
399
{
 
400
    m_dragSourceAction = m_client->dragSourceActionMaskForPoint(rootViewPoint);
 
401
    return m_dragSourceAction;
 
402
}
 
403
 
 
404
DragOperation DragController::operationForLoad(DragData* dragData)
 
405
{
 
406
    ASSERT(dragData);
 
407
    Document* doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
 
408
    if (doc && (m_didInitiateDrag || doc->isPluginDocument() || doc->rendererIsEditable()))
 
409
        return DragOperationNone;
 
410
    return dragOperation(dragData);
 
411
}
 
412
 
 
413
static bool setSelectionToDragCaret(Frame* frame, VisibleSelection& dragCaret, RefPtr<Range>& range, const IntPoint& point)
 
414
{
 
415
    frame->selection()->setSelection(dragCaret);
 
416
    if (frame->selection()->isNone()) {
 
417
        dragCaret = frame->visiblePositionForPoint(point);
 
418
        frame->selection()->setSelection(dragCaret);
 
419
        range = dragCaret.toNormalizedRange();
 
420
    }
 
421
    return !frame->selection()->isNone() && frame->selection()->isContentEditable();
 
422
}
 
423
 
 
424
bool DragController::dispatchTextInputEventFor(Frame* innerFrame, DragData* dragData)
 
425
{
 
426
    ASSERT(m_page->dragCaretController()->hasCaret());
 
427
    String text = m_page->dragCaretController()->isContentRichlyEditable() ? "" : dragData->asPlainText(innerFrame);
 
428
    Node* target = innerFrame->editor()->findEventTargetFrom(m_page->dragCaretController()->caretPosition());
 
429
    ExceptionCode ec = 0;
 
430
    return target->dispatchEvent(TextEvent::createForDrop(innerFrame->document()->domWindow(), text), ec);
 
431
}
 
432
 
 
433
bool DragController::concludeEditDrag(DragData* dragData)
 
434
{
 
435
    ASSERT(dragData);
 
436
 
 
437
    RefPtr<HTMLInputElement> fileInput = m_fileInputElementUnderMouse;
 
438
    if (m_fileInputElementUnderMouse) {
 
439
        m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false);
 
440
        m_fileInputElementUnderMouse = 0;
 
441
    }
 
442
 
 
443
    if (!m_documentUnderMouse)
 
444
        return false;
 
445
 
 
446
    IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition());
 
447
    Element* element = elementUnderMouse(m_documentUnderMouse.get(), point);
 
448
    if (!element)
 
449
        return false;
 
450
    RefPtr<Frame> innerFrame = element->ownerDocument()->frame();
 
451
    ASSERT(innerFrame);
 
452
 
 
453
    if (m_page->dragCaretController()->hasCaret() && !dispatchTextInputEventFor(innerFrame.get(), dragData))
 
454
        return true;
 
455
 
 
456
    if (dragData->containsColor()) {
 
457
        Color color = dragData->asColor();
 
458
        if (!color.isValid())
 
459
            return false;
 
460
        RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange();
 
461
        RefPtr<StylePropertySet> style = StylePropertySet::create();
 
462
        style->setProperty(CSSPropertyColor, color.serialized(), false);
 
463
        if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get()))
 
464
            return false;
 
465
        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
 
466
        innerFrame->editor()->applyStyle(style.get(), EditActionSetColor);
 
467
        return true;
 
468
    }
 
469
 
 
470
    if (dragData->containsFiles() && fileInput) {
 
471
        // fileInput should be the element we hit tested for, unless it was made
 
472
        // display:none in a drop event handler.
 
473
        ASSERT(fileInput == element || !fileInput->renderer());
 
474
        if (fileInput->disabled())
 
475
            return false;
 
476
 
 
477
        return fileInput->receiveDroppedFiles(dragData);
 
478
    }
 
479
 
 
480
    if (!m_page->dragController()->canProcessDrag(dragData)) {
 
481
        m_page->dragCaretController()->clear();
 
482
        return false;
 
483
    }
 
484
 
 
485
    VisibleSelection dragCaret = m_page->dragCaretController()->caretPosition();
 
486
    m_page->dragCaretController()->clear();
 
487
    RefPtr<Range> range = dragCaret.toNormalizedRange();
 
488
    RefPtr<Element> rootEditableElement = innerFrame->selection()->rootEditableElement();
 
489
 
 
490
    // For range to be null a WebKit client must have done something bad while
 
491
    // manually controlling drag behaviour
 
492
    if (!range)
 
493
        return false;
 
494
    CachedResourceLoader* cachedResourceLoader = range->ownerDocument()->cachedResourceLoader();
 
495
    ResourceCacheValidationSuppressor validationSuppressor(cachedResourceLoader);
 
496
    if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) {
 
497
        bool chosePlainText = false;
 
498
        RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, innerFrame.get(), range, true, chosePlainText);
 
499
        if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) {
 
500
            return false;
 
501
        }
 
502
 
 
503
        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
 
504
        if (dragIsMove(innerFrame->selection(), dragData)) {
 
505
            // NSTextView behavior is to always smart delete on moving a selection,
 
506
            // but only to smart insert if the selection granularity is word granularity.
 
507
            bool smartDelete = innerFrame->editor()->smartInsertDeleteEnabled();
 
508
            bool smartInsert = smartDelete && innerFrame->selection()->granularity() == WordGranularity && dragData->canSmartReplace();
 
509
            applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartInsert, smartDelete));
 
510
        } else {
 
511
            if (setSelectionToDragCaret(innerFrame.get(), dragCaret, range, point)) {
 
512
                ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::PreventNesting;
 
513
                if (dragData->canSmartReplace())
 
514
                    options |= ReplaceSelectionCommand::SmartReplace;
 
515
                if (chosePlainText)
 
516
                    options |= ReplaceSelectionCommand::MatchStyle;
 
517
                applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), fragment, options));
 
518
            }
 
519
        }
 
520
    } else {
 
521
        String text = dragData->asPlainText(innerFrame.get());
 
522
        if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) {
 
523
            return false;
 
524
        }
 
525
 
 
526
        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
 
527
        if (setSelectionToDragCaret(innerFrame.get(), dragCaret, range, point))
 
528
            applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), createFragmentFromText(range.get(), text),  ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting));
 
529
    }
 
530
 
 
531
    if (rootEditableElement) {
 
532
        if (Frame* frame = rootEditableElement->document()->frame())
 
533
            frame->eventHandler()->updateDragStateAfterEditDragIfNeeded(rootEditableElement.get());
 
534
    }
 
535
 
 
536
    return true;
 
537
}
 
538
 
 
539
bool DragController::canProcessDrag(DragData* dragData)
 
540
{
 
541
    ASSERT(dragData);
 
542
 
 
543
    if (!dragData->containsCompatibleContent())
 
544
        return false;
 
545
 
 
546
    IntPoint point = m_page->mainFrame()->view()->windowToContents(dragData->clientPosition());
 
547
    HitTestResult result = HitTestResult(point);
 
548
    if (!m_page->mainFrame()->contentRenderer())
 
549
        return false;
 
550
 
 
551
    result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, true);
 
552
 
 
553
    if (!result.innerNonSharedNode())
 
554
        return false;
 
555
 
 
556
    if (dragData->containsFiles() && asFileInput(result.innerNonSharedNode()))
 
557
        return true;
 
558
 
 
559
    if (result.innerNonSharedNode()->isPluginElement()) {
 
560
        HTMLPlugInElement* plugin = static_cast<HTMLPlugInElement*>(result.innerNonSharedNode());
 
561
        if (!plugin->canProcessDrag() && !result.innerNonSharedNode()->rendererIsEditable())
 
562
            return false;
 
563
    } else if (!result.innerNonSharedNode()->rendererIsEditable())
 
564
        return false;
 
565
 
 
566
    if (m_didInitiateDrag && m_documentUnderMouse == m_dragInitiator && result.isSelected())
 
567
        return false;
 
568
 
 
569
    return true;
 
570
}
 
571
 
 
572
static DragOperation defaultOperationForDrag(DragOperation srcOpMask)
 
573
{
 
574
    // This is designed to match IE's operation fallback for the case where
 
575
    // the page calls preventDefault() in a drag event but doesn't set dropEffect.
 
576
    if (srcOpMask == DragOperationEvery)
 
577
        return DragOperationCopy;
 
578
    if (srcOpMask == DragOperationNone)
 
579
        return DragOperationNone;
 
580
    if (srcOpMask & DragOperationMove || srcOpMask & DragOperationGeneric)
 
581
        return DragOperationMove;
 
582
    if (srcOpMask & DragOperationCopy)
 
583
        return DragOperationCopy;
 
584
    if (srcOpMask & DragOperationLink)
 
585
        return DragOperationLink;
 
586
    
 
587
    // FIXME: Does IE really return "generic" even if no operations were allowed by the source?
 
588
    return DragOperationGeneric;
 
589
}
 
590
 
 
591
bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation)
 
592
{
 
593
    ASSERT(dragData);
 
594
    ASSERT(m_documentUnderMouse);
 
595
    RefPtr<Frame> mainFrame = m_page->mainFrame();
 
596
    RefPtr<FrameView> viewProtector = mainFrame->view();
 
597
    if (!viewProtector)
 
598
        return false;
 
599
 
 
600
    ClipboardAccessPolicy policy = m_documentUnderMouse->securityOrigin()->isLocal() ? ClipboardReadable : ClipboardTypesReadable;
 
601
    RefPtr<Clipboard> clipboard = Clipboard::create(policy, dragData, mainFrame.get());
 
602
    DragOperation srcOpMask = dragData->draggingSourceOperationMask();
 
603
    clipboard->setSourceOperation(srcOpMask);
 
604
 
 
605
    PlatformMouseEvent event = createMouseEvent(dragData);
 
606
    if (!mainFrame->eventHandler()->updateDragAndDrop(event, clipboard.get())) {
 
607
        clipboard->setAccessPolicy(ClipboardNumb);    // invalidate clipboard here for security
 
608
        return false;
 
609
    }
 
610
 
 
611
    operation = clipboard->destinationOperation();
 
612
    if (clipboard->dropEffectIsUninitialized())
 
613
        operation = defaultOperationForDrag(srcOpMask);
 
614
    else if (!(srcOpMask & operation)) {
 
615
        // The element picked an operation which is not supported by the source
 
616
        operation = DragOperationNone;
 
617
    }
 
618
 
 
619
    clipboard->setAccessPolicy(ClipboardNumb);    // invalidate clipboard here for security
 
620
    return true;
 
621
}
 
622
 
 
623
Node* DragController::draggableNode(const Frame* src, Node* startNode, const IntPoint& dragOrigin, DragState& state) const
 
624
{
 
625
    state.m_dragType = (src->selection()->contains(dragOrigin)) ? DragSourceActionSelection : DragSourceActionNone;
 
626
 
 
627
    for (const RenderObject* renderer = startNode->renderer(); renderer; renderer = renderer->parent()) {
 
628
        Node* node = renderer->node();
 
629
        if (!node)
 
630
            // Anonymous render blocks don't correspond to actual DOM nodes, so we skip over them
 
631
            // for the purposes of finding a draggable node.
 
632
            continue;
 
633
        if (!(state.m_dragType & DragSourceActionSelection) && node->isTextNode() && node->canStartSelection())
 
634
            // In this case we have a click in the unselected portion of text. If this text is
 
635
            // selectable, we want to start the selection process instead of looking for a parent
 
636
            // to try to drag.
 
637
            return 0;
 
638
        if (node->isElementNode()) {
 
639
            EUserDrag dragMode = renderer->style()->userDrag();
 
640
            if ((m_dragSourceAction & DragSourceActionDHTML) && dragMode == DRAG_ELEMENT) {
 
641
                state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionDHTML);
 
642
                return node;
 
643
            }
 
644
            if (dragMode == DRAG_AUTO) {
 
645
                if ((m_dragSourceAction & DragSourceActionImage)
 
646
                    && node->hasTagName(HTMLNames::imgTag)
 
647
                    && src->settings()
 
648
                    && src->settings()->loadsImagesAutomatically()) {
 
649
                    state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionImage);
 
650
                    return node;
 
651
                }
 
652
                if ((m_dragSourceAction & DragSourceActionLink)
 
653
                    && node->hasTagName(HTMLNames::aTag)
 
654
                    && static_cast<HTMLAnchorElement*>(node)->isLiveLink()) {
 
655
                    state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionLink);
 
656
                    return node;
 
657
                }
 
658
            }
 
659
        }
 
660
    }
 
661
 
 
662
    // We either have nothing to drag or we have a selection and we're not over a draggable element.
 
663
    return (state.m_dragType & DragSourceActionSelection) ? startNode : 0;
 
664
}
 
665
 
 
666
static CachedImage* getCachedImage(Element* element)
 
667
{
 
668
    ASSERT(element);
 
669
    RenderObject* renderer = element->renderer();
 
670
    if (!renderer || !renderer->isImage())
 
671
        return 0;
 
672
    RenderImage* image = toRenderImage(renderer);
 
673
    return image->cachedImage();
 
674
}
 
675
 
 
676
static Image* getImage(Element* element)
 
677
{
 
678
    ASSERT(element);
 
679
    CachedImage* cachedImage = getCachedImage(element);
 
680
    // Don't use cachedImage->imageForRenderer() here as that may return BitmapImages for cached SVG Images.
 
681
    // Users of getImage() want access to the SVGImage, in order to figure out the filename extensions,
 
682
    // which would be empty when asking the cached BitmapImages.
 
683
    return (cachedImage && !cachedImage->errorOccurred()) ?
 
684
        cachedImage->image() : 0;
 
685
}
 
686
 
 
687
static void prepareClipboardForImageDrag(Frame* source, Clipboard* clipboard, Element* node, const KURL& linkURL, const KURL& imageURL, const String& label)
 
688
{
 
689
    if (node->isContentRichlyEditable()) {
 
690
        RefPtr<Range> range = source->document()->createRange();
 
691
        ExceptionCode ec = 0;
 
692
        range->selectNode(node, ec);
 
693
        ASSERT(!ec);
 
694
        source->selection()->setSelection(VisibleSelection(range.get(), DOWNSTREAM));
 
695
    }
 
696
    clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, source);
 
697
}
 
698
 
 
699
static IntPoint dragLocForDHTMLDrag(const IntPoint& mouseDraggedPoint, const IntPoint& dragOrigin, const IntPoint& dragImageOffset, bool isLinkImage)
 
700
{
 
701
    // dragImageOffset is the cursor position relative to the lower-left corner of the image.
 
702
#if PLATFORM(MAC)
 
703
    // We add in the Y dimension because we are a flipped view, so adding moves the image down.
 
704
    const int yOffset = dragImageOffset.y();
 
705
#else
 
706
    const int yOffset = -dragImageOffset.y();
 
707
#endif
 
708
 
 
709
    if (isLinkImage)
 
710
        return IntPoint(mouseDraggedPoint.x() - dragImageOffset.x(), mouseDraggedPoint.y() + yOffset);
 
711
 
 
712
    return IntPoint(dragOrigin.x() - dragImageOffset.x(), dragOrigin.y() + yOffset);
 
713
}
 
714
 
 
715
static IntPoint dragLocForSelectionDrag(Frame* src)
 
716
{
 
717
    IntRect draggingRect = enclosingIntRect(src->selection()->bounds());
 
718
    int xpos = draggingRect.maxX();
 
719
    xpos = draggingRect.x() < xpos ? draggingRect.x() : xpos;
 
720
    int ypos = draggingRect.maxY();
 
721
#if PLATFORM(MAC)
 
722
    // Deal with flipped coordinates on Mac
 
723
    ypos = draggingRect.y() > ypos ? draggingRect.y() : ypos;
 
724
#else
 
725
    ypos = draggingRect.y() < ypos ? draggingRect.y() : ypos;
 
726
#endif
 
727
    return IntPoint(xpos, ypos);
 
728
}
 
729
 
 
730
bool DragController::startDrag(Frame* src, const DragState& state, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin)
 
731
{
 
732
    ASSERT(src);
 
733
 
 
734
    if (!src->view() || !src->contentRenderer())
 
735
        return false;
 
736
 
 
737
    HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true);
 
738
    if (!state.m_dragSrc->contains(hitTestResult.innerNode()))
 
739
        // The original node being dragged isn't under the drag origin anymore... maybe it was
 
740
        // hidden or moved out from under the cursor. Regardless, we don't want to start a drag on
 
741
        // something that's not actually under the drag origin.
 
742
        return false;
 
743
    KURL linkURL = hitTestResult.absoluteLinkURL();
 
744
    KURL imageURL = hitTestResult.absoluteImageURL();
 
745
 
 
746
    IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.position());
 
747
 
 
748
    m_draggingImageURL = KURL();
 
749
    m_sourceDragOperation = srcOp;
 
750
 
 
751
    DragImageRef dragImage = 0;
 
752
    IntPoint dragLoc(0, 0);
 
753
    IntPoint dragImageOffset(0, 0);
 
754
 
 
755
    Clipboard* clipboard = state.m_dragClipboard.get();
 
756
    if (state.m_dragType == DragSourceActionDHTML)
 
757
        dragImage = clipboard->createDragImage(dragImageOffset);
 
758
    if (state.m_dragType == DragSourceActionSelection || !imageURL.isEmpty() || !linkURL.isEmpty())
 
759
        // Selection, image, and link drags receive a default set of allowed drag operations that
 
760
        // follows from:
 
761
        // http://trac.webkit.org/browser/trunk/WebKit/mac/WebView/WebHTMLView.mm?rev=48526#L3430
 
762
        m_sourceDragOperation = static_cast<DragOperation>(m_sourceDragOperation | DragOperationGeneric | DragOperationCopy);
 
763
 
 
764
    // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging.
 
765
    // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp.
 
766
    if (dragImage) {
 
767
        dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty());
 
768
        m_dragOffset = dragImageOffset;
 
769
    }
 
770
 
 
771
    bool startedDrag = true; // optimism - we almost always manage to start the drag
 
772
 
 
773
    Node* node = state.m_dragSrc.get();
 
774
 
 
775
    Image* image = getImage(static_cast<Element*>(node));
 
776
    if (state.m_dragType == DragSourceActionSelection) {
 
777
        if (!clipboard->hasData()) {
 
778
            if (enclosingTextFormControl(src->selection()->start()))
 
779
                clipboard->writePlainText(src->editor()->selectedText());
 
780
            else {
 
781
                RefPtr<Range> selectionRange = src->selection()->toNormalizedRange();
 
782
                ASSERT(selectionRange);
 
783
 
 
784
                clipboard->writeRange(selectionRange.get(), src);
 
785
            }
 
786
        }
 
787
        m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard);
 
788
        if (!dragImage) {
 
789
            dragImage = createDragImageForSelection(src);
 
790
            dragLoc = dragLocForSelectionDrag(src);
 
791
            m_dragOffset = IntPoint(dragOrigin.x() - dragLoc.x(), dragOrigin.y() - dragLoc.y());
 
792
        }
 
793
        doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
 
794
    } else if (!imageURL.isEmpty() && node && node->isElementNode() && image && !image->isNull()
 
795
               && (m_dragSourceAction & DragSourceActionImage)) {
 
796
        // We shouldn't be starting a drag for an image that can't provide an extension.
 
797
        // This is an early detection for problems encountered later upon drop.
 
798
        ASSERT(!image->filenameExtension().isEmpty());
 
799
        Element* element = static_cast<Element*>(node);
 
800
        if (!clipboard->hasData()) {
 
801
            m_draggingImageURL = imageURL;
 
802
            prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, hitTestResult.altDisplayString());
 
803
        }
 
804
 
 
805
        m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard);
 
806
 
 
807
        if (!dragImage) {
 
808
            IntRect imageRect = hitTestResult.imageRect();
 
809
            imageRect.setLocation(m_page->mainFrame()->view()->rootViewToContents(src->view()->contentsToRootView(imageRect.location())));
 
810
            doImageDrag(element, dragOrigin, hitTestResult.imageRect(), clipboard, src, m_dragOffset);
 
811
        } else
 
812
            // DHTML defined drag image
 
813
            doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
 
814
 
 
815
    } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink)) {
 
816
        if (!clipboard->hasData())
 
817
            // Simplify whitespace so the title put on the clipboard resembles what the user sees
 
818
            // on the web page. This includes replacing newlines with spaces.
 
819
            clipboard->writeURL(linkURL, hitTestResult.textContent().simplifyWhiteSpace(), src);
 
820
 
 
821
        if (src->selection()->isCaret() && src->selection()->isContentEditable()) {
 
822
            // a user can initiate a drag on a link without having any text
 
823
            // selected.  In this case, we should expand the selection to
 
824
            // the enclosing anchor element
 
825
            Position pos = src->selection()->base();
 
826
            Node* node = enclosingAnchorElement(pos);
 
827
            if (node)
 
828
                src->selection()->setSelection(VisibleSelection::selectionFromContentsOfNode(node));
 
829
        }
 
830
 
 
831
        m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard);
 
832
        if (!dragImage) {
 
833
            dragImage = createDragImageForLink(linkURL, hitTestResult.textContent(), src);
 
834
            IntSize size = dragImageSize(dragImage);
 
835
            m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset);
 
836
            dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y());
 
837
        }
 
838
        doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true);
 
839
    } else if (state.m_dragType == DragSourceActionDHTML) {
 
840
        ASSERT(m_dragSourceAction & DragSourceActionDHTML);
 
841
        m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard);
 
842
        doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
 
843
    } else {
 
844
        // draggableNode() determined an image or link node was draggable, but it turns out the
 
845
        // image or link had no URL, so there is nothing to drag.
 
846
        startedDrag = false;
 
847
    }
 
848
 
 
849
    if (dragImage)
 
850
        deleteDragImage(dragImage);
 
851
    return startedDrag;
 
852
}
 
853
 
 
854
void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, const IntRect& rect, Clipboard* clipboard, Frame* frame, IntPoint& dragImageOffset)
 
855
{
 
856
    IntPoint mouseDownPoint = dragOrigin;
 
857
    DragImageRef dragImage;
 
858
    IntPoint origin;
 
859
 
 
860
    Image* image = getImage(element);
 
861
    if (image && image->size().height() * image->size().width() <= MaxOriginalImageArea
 
862
        && (dragImage = createDragImageFromImage(image, element->renderer() ? element->renderer()->shouldRespectImageOrientation() : DoNotRespectImageOrientation))) {
 
863
        IntSize originalSize = rect.size();
 
864
        origin = rect.location();
 
865
 
 
866
        dragImage = fitDragImageToMaxSize(dragImage, rect.size(), maxDragImageSize());
 
867
        dragImage = dissolveDragImageToFraction(dragImage, DragImageAlpha);
 
868
        IntSize newSize = dragImageSize(dragImage);
 
869
 
 
870
        // Properly orient the drag image and orient it differently if it's smaller than the original
 
871
        float scale = newSize.width() / (float)originalSize.width();
 
872
        float dx = origin.x() - mouseDownPoint.x();
 
873
        dx *= scale;
 
874
        origin.setX((int)(dx + 0.5));
 
875
#if PLATFORM(MAC)
 
876
        //Compensate for accursed flipped coordinates in cocoa
 
877
        origin.setY(origin.y() + originalSize.height());
 
878
#endif
 
879
        float dy = origin.y() - mouseDownPoint.y();
 
880
        dy *= scale;
 
881
        origin.setY((int)(dy + 0.5));
 
882
    } else {
 
883
        dragImage = createDragImageIconForCachedImage(getCachedImage(element));
 
884
        if (dragImage)
 
885
            origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).width(), DragIconBottomInset);
 
886
    }
 
887
 
 
888
    dragImageOffset = mouseDownPoint + origin;
 
889
    doSystemDrag(dragImage, dragImageOffset, dragOrigin, clipboard, frame, false);
 
890
 
 
891
    deleteDragImage(dragImage);
 
892
}
 
893
 
 
894
void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool forLink)
 
895
{
 
896
    m_didInitiateDrag = true;
 
897
    m_dragInitiator = frame->document();
 
898
    // Protect this frame and view, as a load may occur mid drag and attempt to unload this frame
 
899
    RefPtr<Frame> frameProtector = m_page->mainFrame();
 
900
    RefPtr<FrameView> viewProtector = frameProtector->view();
 
901
    m_client->startDrag(image, viewProtector->rootViewToContents(frame->view()->contentsToRootView(dragLoc)),
 
902
        viewProtector->rootViewToContents(frame->view()->contentsToRootView(eventPos)), clipboard, frameProtector.get(), forLink);
 
903
    // DragClient::startDrag can cause our Page to dispear, deallocating |this|.
 
904
    if (!frameProtector->page())
 
905
        return;
 
906
 
 
907
    cleanupAfterSystemDrag();
 
908
}
 
909
 
 
910
// Manual drag caret manipulation
 
911
void DragController::placeDragCaret(const IntPoint& windowPoint)
 
912
{
 
913
    mouseMovedIntoDocument(m_page->mainFrame()->documentAtPoint(windowPoint));
 
914
    if (!m_documentUnderMouse)
 
915
        return;
 
916
    Frame* frame = m_documentUnderMouse->frame();
 
917
    FrameView* frameView = frame->view();
 
918
    if (!frameView)
 
919
        return;
 
920
    IntPoint framePoint = frameView->windowToContents(windowPoint);
 
921
 
 
922
    m_page->dragCaretController()->setCaretPosition(frame->visiblePositionForPoint(framePoint));
 
923
}
 
924
 
 
925
} // namespace WebCore
 
926
 
 
927
#endif // ENABLE(DRAG_SUPPORT)