~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/WebCore/page/DragController.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2007 Apple Inc. All rights reserved.
 
2
 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3
3
 *
4
4
 * Redistribution and use in source and binary forms, with or without
5
5
 * modification, are permitted provided that the following conditions
26
26
#include "config.h"
27
27
#include "DragController.h"
28
28
 
 
29
#if ENABLE(DRAG_SUPPORT)
29
30
#include "CSSStyleDeclaration.h"
30
31
#include "Clipboard.h"
31
32
#include "ClipboardAccessPolicy.h"
46
47
#include "HTMLAnchorElement.h"
47
48
#include "HTMLInputElement.h"
48
49
#include "HTMLNames.h"
 
50
#include "HitTestRequest.h"
49
51
#include "HitTestResult.h"
50
52
#include "Image.h"
51
53
#include "MoveSelectionCommand.h"
53
55
#include "Page.h"
54
56
#include "RenderFileUploadControl.h"
55
57
#include "RenderImage.h"
 
58
#include "RenderView.h"
56
59
#include "ReplaceSelectionCommand.h"
57
60
#include "ResourceRequest.h"
58
 
#include "SecurityOrigin.h"
59
61
#include "SelectionController.h"
60
62
#include "Settings.h"
61
 
#include "SystemTime.h"
62
63
#include "Text.h"
63
64
#include "htmlediting.h"
64
65
#include "markup.h"
 
66
#include <wtf/CurrentTime.h>
65
67
#include <wtf/RefPtr.h>
66
68
 
67
69
namespace WebCore {
73
75
                              LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime());
74
76
 
75
77
}
76
 
    
 
78
 
77
79
DragController::DragController(Page* page, DragClient* client)
78
80
    : m_page(page)
79
81
    , m_client(client)
80
 
    , m_document(0)
 
82
    , m_documentUnderMouse(0)
81
83
    , m_dragInitiator(0)
82
84
    , m_dragDestinationAction(DragDestinationActionNone)
83
85
    , m_dragSourceAction(DragSourceActionNone)
84
86
    , m_didInitiateDrag(false)
85
87
    , m_isHandlingDrag(false)
86
 
    , m_dragOperation(DragOperationNone)
 
88
    , m_sourceDragOperation(DragOperationNone)
87
89
{
88
90
}
89
 
    
 
91
 
90
92
DragController::~DragController()
91
 
{   
 
93
{
92
94
    m_client->dragControllerDestroyed();
93
95
}
94
 
    
 
96
 
95
97
static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragData, RefPtr<Range> context,
96
98
                                          bool allowPlainText, bool& chosePlainText)
97
99
{
108
110
            String title;
109
111
            String url = dragData->asURL(&title);
110
112
            if (!url.isEmpty()) {
 
113
                RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(document);
 
114
                anchor->setHref(url);
111
115
                ExceptionCode ec;
112
 
                RefPtr<HTMLAnchorElement> anchor = static_cast<HTMLAnchorElement*>(document->createElement("a", ec).get());
113
 
                anchor->setHref(url);
114
116
                RefPtr<Node> anchorText = document->createTextNode(title);
115
117
                anchor->appendChild(anchorText, ec);
116
118
                RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
123
125
        chosePlainText = true;
124
126
        return createFragmentFromText(context.get(), dragData->asPlainText()).get();
125
127
    }
126
 
    
 
128
 
127
129
    return 0;
128
130
}
129
131
 
130
 
bool DragController::dragIsMove(SelectionController* selection, DragData* dragData) 
 
132
bool DragController::dragIsMove(SelectionController* selection)
131
133
{
132
 
    return m_document == m_dragInitiator
133
 
        && selection->isContentEditable()
134
 
        && !isCopyKeyDown();
 
134
    return m_documentUnderMouse == m_dragInitiator && selection->isContentEditable() && !isCopyKeyDown();
135
135
}
136
136
 
 
137
// FIXME: This method is poorly named.  We're just clearing the selection from the document this drag is exiting.
137
138
void DragController::cancelDrag()
138
139
{
139
140
    m_page->dragCaretController()->clear();
142
143
void DragController::dragEnded()
143
144
{
144
145
    m_dragInitiator = 0;
145
 
    m_didInitiateDrag = false; 
146
 
    m_page->dragCaretController()->clear(); 
147
 
}    
 
146
    m_didInitiateDrag = false;
 
147
    m_page->dragCaretController()->clear();
 
148
}
148
149
 
149
 
DragOperation DragController::dragEntered(DragData* dragData) 
 
150
DragOperation DragController::dragEntered(DragData* dragData)
150
151
{
151
152
    return dragEnteredOrUpdated(dragData);
152
153
}
153
 
    
154
 
void DragController::dragExited(DragData* dragData) 
155
 
{   
 
154
 
 
155
void DragController::dragExited(DragData* dragData)
 
156
{
156
157
    ASSERT(dragData);
157
158
    Frame* mainFrame = m_page->mainFrame();
158
 
    
 
159
 
159
160
    if (RefPtr<FrameView> v = mainFrame->view()) {
160
 
        ClipboardAccessPolicy policy = m_document->securityOrigin()->isLocal() ? ClipboardReadable : ClipboardTypesReadable;
 
161
        ClipboardAccessPolicy policy = (!m_documentUnderMouse || m_documentUnderMouse->securityOrigin()->isLocal()) ? ClipboardReadable : ClipboardTypesReadable;
161
162
        RefPtr<Clipboard> clipboard = dragData->createClipboard(policy);
162
163
        clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
163
164
        mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get());
164
165
        clipboard->setAccessPolicy(ClipboardNumb);    // invalidate clipboard here for security
165
166
    }
166
 
 
167
 
    cancelDrag();
168
 
    m_document = 0;
 
167
    mouseMovedIntoDocument(0);
169
168
}
170
169
 
171
 
    
172
 
DragOperation DragController::dragUpdated(DragData* dragData) 
 
170
DragOperation DragController::dragUpdated(DragData* dragData)
173
171
{
174
172
    return dragEnteredOrUpdated(dragData);
175
173
}
176
 
    
 
174
 
177
175
bool DragController::performDrag(DragData* dragData)
178
 
{   
 
176
{
179
177
    ASSERT(dragData);
180
 
    m_document = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
 
178
    m_documentUnderMouse = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
181
179
    if (m_isHandlingDrag) {
182
180
        ASSERT(m_dragDestinationAction & DragDestinationActionDHTML);
183
181
        m_client->willPerformDragDestinationAction(DragDestinationActionDHTML, dragData);
189
187
            mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get());
190
188
            clipboard->setAccessPolicy(ClipboardNumb);    // invalidate clipboard here for security
191
189
        }
192
 
        m_document = 0;
193
 
        return true;
194
 
    } 
195
 
    
196
 
    if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeDrag(dragData, m_dragDestinationAction)) {
197
 
        m_document = 0;
198
 
        return true;
199
 
    }
200
 
    
201
 
    m_document = 0;
 
190
        m_documentUnderMouse = 0;
 
191
        return true;
 
192
    }
 
193
 
 
194
    if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeEditDrag(dragData)) {
 
195
        m_documentUnderMouse = 0;
 
196
        return true;
 
197
    }
 
198
 
 
199
    m_documentUnderMouse = 0;
202
200
 
203
201
    if (operationForLoad(dragData) == DragOperationNone)
204
202
        return false;
205
203
 
206
204
    m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragData);
207
 
    m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL()));
 
205
    m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL()), false);
208
206
    return true;
209
207
}
210
 
    
 
208
 
 
209
void DragController::mouseMovedIntoDocument(Document* newDocument)
 
210
{
 
211
    if (m_documentUnderMouse == newDocument)
 
212
        return;
 
213
 
 
214
    // If we were over another document clear the selection
 
215
    if (m_documentUnderMouse)
 
216
        cancelDrag();
 
217
    m_documentUnderMouse = newDocument;
 
218
}
 
219
 
211
220
DragOperation DragController::dragEnteredOrUpdated(DragData* dragData)
212
221
{
213
222
    ASSERT(dragData);
214
 
    IntPoint windowPoint = dragData->clientPosition();
215
 
    
216
 
    Document* newDraggingDoc = 0;
217
 
    if (Frame* frame = m_page->mainFrame())
218
 
        newDraggingDoc = frame->documentAtPoint(windowPoint);
219
 
    if (m_document != newDraggingDoc) {
220
 
        if (m_document)
221
 
            cancelDrag();
222
 
        m_document = newDraggingDoc;
223
 
    }
224
 
    
 
223
    ASSERT(m_page->mainFrame()); // It is not possible in Mac WebKit to have a Page without a mainFrame()
 
224
    mouseMovedIntoDocument(m_page->mainFrame()->documentAtPoint(dragData->clientPosition()));
 
225
 
225
226
    m_dragDestinationAction = m_client->actionMaskForDrag(dragData);
226
 
    
 
227
    if (m_dragDestinationAction == DragDestinationActionNone) {
 
228
        cancelDrag(); // FIXME: Why not call mouseMovedIntoDocument(0)?
 
229
        return DragOperationNone;
 
230
    }
 
231
 
227
232
    DragOperation operation = DragOperationNone;
228
 
    
229
 
    if (m_dragDestinationAction == DragDestinationActionNone)
230
 
        cancelDrag();
231
 
    else {
232
 
        operation = tryDocumentDrag(dragData, m_dragDestinationAction);
233
 
        if (operation == DragOperationNone && (m_dragDestinationAction & DragDestinationActionLoad))
234
 
            return operationForLoad(dragData);
235
 
    }
236
 
    
 
233
    bool handledByDocument = tryDocumentDrag(dragData, m_dragDestinationAction, operation);
 
234
    if (!handledByDocument && (m_dragDestinationAction & DragDestinationActionLoad))
 
235
        return operationForLoad(dragData);
237
236
    return operation;
238
237
}
239
238
 
240
239
static HTMLInputElement* asFileInput(Node* node)
241
240
{
242
241
    ASSERT(node);
243
 
    
 
242
 
244
243
    // The button for a FILE input is a sub element with no set input type
245
244
    // In order to get around this problem we assume any non-FILE input element
246
245
    // is this internal button, and try querying the shadow parent node.
247
246
    if (node->hasTagName(HTMLNames::inputTag) && node->isShadowNode() && static_cast<HTMLInputElement*>(node)->inputType() != HTMLInputElement::FILE)
248
247
      node = node->shadowParentNode();
249
 
    
 
248
 
250
249
    if (!node || !node->hasTagName(HTMLNames::inputTag))
251
250
        return 0;
252
 
    
 
251
 
253
252
    HTMLInputElement* inputElem = static_cast<HTMLInputElement*>(node);
254
253
    if (inputElem->inputType() == HTMLInputElement::FILE)
255
254
        return inputElem;
256
 
    
 
255
 
257
256
    return 0;
258
257
}
259
 
    
260
 
DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask)
 
258
 
 
259
static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint& p)
 
260
{
 
261
    float zoomFactor = documentUnderMouse->frame()->pageZoomFactor();
 
262
    IntPoint point = roundedIntPoint(FloatPoint(p.x() * zoomFactor, p.y() * zoomFactor));
 
263
 
 
264
    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
 
265
    HitTestResult result(point);
 
266
    documentUnderMouse->renderView()->layer()->hitTest(request, result);
 
267
 
 
268
    Node* n = result.innerNode();
 
269
    while (n && !n->isElementNode())
 
270
        n = n->parentNode();
 
271
    if (n)
 
272
        n = n->shadowAncestorNode();
 
273
 
 
274
    ASSERT(n);
 
275
    return static_cast<Element*>(n);
 
276
}
 
277
 
 
278
bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask, DragOperation& operation)
261
279
{
262
280
    ASSERT(dragData);
263
 
    
264
 
    if (!m_document)
265
 
        return DragOperationNone;
266
 
    
267
 
    DragOperation operation = DragOperationNone;
268
 
    if (actionMask & DragDestinationActionDHTML)
269
 
        operation = tryDHTMLDrag(dragData);
270
 
    m_isHandlingDrag = operation != DragOperationNone; 
271
 
 
272
 
    RefPtr<FrameView> frameView = m_document->view();
 
281
 
 
282
    if (!m_documentUnderMouse)
 
283
        return false;
 
284
 
 
285
    m_isHandlingDrag = false;
 
286
    if (actionMask & DragDestinationActionDHTML) {
 
287
        m_isHandlingDrag = tryDHTMLDrag(dragData, operation);
 
288
        // Do not continue if m_documentUnderMouse has been reset by tryDHTMLDrag.
 
289
        // tryDHTMLDrag fires dragenter event. The event listener that listens
 
290
        // to this event may create a nested message loop (open a modal dialog),
 
291
        // which could process dragleave event and reset m_documentUnderMouse in
 
292
        // dragExited.
 
293
        if (!m_documentUnderMouse)
 
294
            return false;
 
295
    }
 
296
 
 
297
    // It's unclear why this check is after tryDHTMLDrag.
 
298
    // We send drag events in tryDHTMLDrag and that may be the reason.
 
299
    RefPtr<FrameView> frameView = m_documentUnderMouse->view();
273
300
    if (!frameView)
274
 
        return operation;
275
 
    
276
 
    if ((actionMask & DragDestinationActionEdit) && !m_isHandlingDrag && canProcessDrag(dragData)) {
277
 
        if (dragData->containsColor()) 
278
 
            return DragOperationGeneric;
279
 
        
280
 
        IntPoint dragPos = dragData->clientPosition();
281
 
        IntPoint point = frameView->windowToContents(dragPos);
282
 
        Element* element = m_document->elementFromPoint(point.x(), point.y());
283
 
        ASSERT(element);
284
 
        Frame* innerFrame = element->document()->frame();
285
 
        ASSERT(innerFrame);
 
301
        return false;
 
302
 
 
303
    if (m_isHandlingDrag) {
 
304
        m_page->dragCaretController()->clear();
 
305
        return true;
 
306
    } else if ((actionMask & DragDestinationActionEdit) && canProcessDrag(dragData)) {
 
307
        if (dragData->containsColor()) {
 
308
            operation = DragOperationGeneric;
 
309
            return true;
 
310
        }
 
311
 
 
312
        IntPoint point = frameView->windowToContents(dragData->clientPosition());
 
313
        Element* element = elementUnderMouse(m_documentUnderMouse, point);
286
314
        if (!asFileInput(element)) {
287
 
            Selection dragCaret;
288
 
            if (Frame* frame = m_document->frame())
289
 
                dragCaret = frame->visiblePositionForPoint(point);
 
315
            VisibleSelection dragCaret = m_documentUnderMouse->frame()->visiblePositionForPoint(point);
290
316
            m_page->dragCaretController()->setSelection(dragCaret);
291
317
        }
292
 
        
293
 
        return dragIsMove(innerFrame->selection(), dragData) ? DragOperationMove : DragOperationCopy;
294
 
    } 
295
 
    
 
318
 
 
319
        Frame* innerFrame = element->document()->frame();
 
320
        operation = dragIsMove(innerFrame->selection()) ? DragOperationMove : DragOperationCopy;
 
321
        return true;
 
322
    }
 
323
    // If we're not over an editable region, make sure we're clearing any prior drag cursor.
296
324
    m_page->dragCaretController()->clear();
297
 
    return operation;
 
325
    return false;
298
326
}
299
327
 
300
328
DragSourceAction DragController::delegateDragSourceAction(const IntPoint& windowPoint)
301
 
{  
 
329
{
302
330
    m_dragSourceAction = m_client->dragSourceActionMaskForPoint(windowPoint);
303
331
    return m_dragSourceAction;
304
332
}
305
 
    
 
333
 
306
334
DragOperation DragController::operationForLoad(DragData* dragData)
307
335
{
308
336
    ASSERT(dragData);
309
 
    Document* doc = 0;
310
 
    doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
 
337
    Document* doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
311
338
    if (doc && (m_didInitiateDrag || doc->isPluginDocument() || (doc->frame() && doc->frame()->editor()->clientIsEditable())))
312
339
        return DragOperationNone;
313
340
    return dragOperation(dragData);
314
341
}
315
342
 
316
 
static bool setSelectionToDragCaret(Frame* frame, Selection& dragCaret, RefPtr<Range>& range, const IntPoint& point)
 
343
static bool setSelectionToDragCaret(Frame* frame, VisibleSelection& dragCaret, RefPtr<Range>& range, const IntPoint& point)
317
344
{
318
345
    frame->selection()->setSelection(dragCaret);
319
346
    if (frame->selection()->isNone()) {
320
347
        dragCaret = frame->visiblePositionForPoint(point);
321
348
        frame->selection()->setSelection(dragCaret);
322
 
        range = dragCaret.toRange();
 
349
        range = dragCaret.toNormalizedRange();
323
350
    }
324
351
    return !frame->selection()->isNone() && frame->selection()->isContentEditable();
325
352
}
326
353
 
327
 
bool DragController::concludeDrag(DragData* dragData, DragDestinationAction actionMask)
 
354
bool DragController::concludeEditDrag(DragData* dragData)
328
355
{
329
356
    ASSERT(dragData);
330
357
    ASSERT(!m_isHandlingDrag);
331
 
    ASSERT(actionMask & DragDestinationActionEdit);
332
 
    
333
 
    if (!m_document)
 
358
 
 
359
    if (!m_documentUnderMouse)
334
360
        return false;
335
 
    
336
 
    IntPoint point = m_document->view()->windowToContents(dragData->clientPosition());
337
 
    Element* element =  m_document->elementFromPoint(point.x(), point.y());
338
 
    ASSERT(element);
 
361
 
 
362
    IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition());
 
363
    Element* element = elementUnderMouse(m_documentUnderMouse, point);
339
364
    Frame* innerFrame = element->ownerDocument()->frame();
340
 
    ASSERT(innerFrame);    
 
365
    ASSERT(innerFrame);
341
366
 
342
367
    if (dragData->containsColor()) {
343
368
        Color color = dragData->asColor();
345
370
            return false;
346
371
        if (!innerFrame)
347
372
            return false;
348
 
        RefPtr<Range> innerRange = innerFrame->selection()->toRange();
349
 
        RefPtr<CSSStyleDeclaration> style = m_document->createCSSStyleDeclaration();
 
373
        RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange();
 
374
        RefPtr<CSSStyleDeclaration> style = m_documentUnderMouse->createCSSStyleDeclaration();
350
375
        ExceptionCode ec;
351
376
        style->setProperty("color", color.name(), ec);
352
377
        if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get()))
355
380
        innerFrame->editor()->applyStyle(style.get(), EditActionSetColor);
356
381
        return true;
357
382
    }
358
 
    
 
383
 
359
384
    if (!m_page->dragController()->canProcessDrag(dragData)) {
360
385
        m_page->dragCaretController()->clear();
361
386
        return false;
362
387
    }
363
 
    
 
388
 
364
389
    if (HTMLInputElement* fileInput = asFileInput(element)) {
365
 
        
366
 
        if (!fileInput->isEnabled())
 
390
        if (!fileInput->isEnabledFormControl())
367
391
            return false;
368
 
        
 
392
 
369
393
        if (!dragData->containsFiles())
370
394
            return false;
371
 
        
 
395
 
372
396
        Vector<String> filenames;
373
397
        dragData->asFilenames(filenames);
374
398
        if (filenames.isEmpty())
375
399
            return false;
376
 
        
377
 
        // Ugly.  For security none of the API's available to us to set the input value 
378
 
        // on file inputs.  Even forcing a change in HTMLInputElement doesn't work as
379
 
        // RenderFileUploadControl clears the file when doing updateFromElement()
380
 
        RenderFileUploadControl* renderer = static_cast<RenderFileUploadControl*>(fileInput->renderer());
381
 
        
 
400
 
 
401
        // Ugly. For security none of the APIs available to us can set the input value
 
402
        // on file inputs. Even forcing a change in HTMLInputElement doesn't work as
 
403
        // RenderFileUploadControl clears the file when doing updateFromElement().
 
404
        RenderFileUploadControl* renderer = toRenderFileUploadControl(fileInput->renderer());
382
405
        if (!renderer)
383
406
            return false;
384
 
        
 
407
 
385
408
        renderer->receiveDroppedFiles(filenames);
386
409
        return true;
387
410
    }
388
411
 
389
 
    Selection dragCaret(m_page->dragCaretController()->selection());
 
412
    VisibleSelection dragCaret(m_page->dragCaretController()->selection());
390
413
    m_page->dragCaretController()->clear();
391
 
    RefPtr<Range> range = dragCaret.toRange();
392
 
    
 
414
    RefPtr<Range> range = dragCaret.toNormalizedRange();
 
415
 
393
416
    // For range to be null a WebKit client must have done something bad while
394
417
    // manually controlling drag behaviour
395
 
    if (!range)  
 
418
    if (!range)
396
419
        return false;
397
420
    DocLoader* loader = range->ownerDocument()->docLoader();
398
421
    loader->setAllowStaleResources(true);
399
 
    if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) { 
 
422
    if (dragIsMove(innerFrame->selection()) || dragCaret.isContentRichlyEditable()) {
400
423
        bool chosePlainText = false;
401
424
        RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText);
402
425
        if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) {
403
426
            loader->setAllowStaleResources(false);
404
427
            return false;
405
428
        }
406
 
        
 
429
 
407
430
        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
408
 
        if (dragIsMove(innerFrame->selection(), dragData)) {
409
 
            bool smartMove = innerFrame->selectionGranularity() == WordGranularity 
410
 
                          && innerFrame->editor()->smartInsertDeleteEnabled() 
 
431
        if (dragIsMove(innerFrame->selection())) {
 
432
            bool smartMove = innerFrame->selectionGranularity() == WordGranularity
 
433
                          && innerFrame->editor()->smartInsertDeleteEnabled()
411
434
                          && dragData->canSmartReplace();
412
435
            applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartMove));
413
436
        } else {
414
437
            if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
415
 
                applyCommand(ReplaceSelectionCommand::create(m_document, fragment, true, dragData->canSmartReplace(), chosePlainText)); 
416
 
        }    
 
438
                applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, fragment, true, dragData->canSmartReplace(), chosePlainText));
 
439
        }
417
440
    } else {
418
441
        String text = dragData->asPlainText();
419
442
        if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) {
420
443
            loader->setAllowStaleResources(false);
421
444
            return false;
422
445
        }
423
 
        
 
446
 
424
447
        m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
425
448
        if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
426
 
            applyCommand(ReplaceSelectionCommand::create(m_document, createFragmentFromText(range.get(), text), true, false, true)); 
 
449
            applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, createFragmentFromText(range.get(), text), true, false, true));
427
450
    }
428
451
    loader->setAllowStaleResources(false);
429
452
 
430
453
    return true;
431
454
}
432
 
    
433
 
    
434
 
bool DragController::canProcessDrag(DragData* dragData) 
 
455
 
 
456
bool DragController::canProcessDrag(DragData* dragData)
435
457
{
436
458
    ASSERT(dragData);
437
459
 
438
460
    if (!dragData->containsCompatibleContent())
439
461
        return false;
440
 
    
 
462
 
441
463
    IntPoint point = m_page->mainFrame()->view()->windowToContents(dragData->clientPosition());
442
464
    HitTestResult result = HitTestResult(point);
443
465
    if (!m_page->mainFrame()->contentRenderer())
444
466
        return false;
445
467
 
446
468
    result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, true);
447
 
    
448
 
    if (!result.innerNonSharedNode()) 
 
469
 
 
470
    if (!result.innerNonSharedNode())
449
471
        return false;
450
 
    
 
472
 
451
473
    if (dragData->containsFiles() && asFileInput(result.innerNonSharedNode()))
452
474
        return true;
453
 
        
 
475
 
454
476
    if (!result.innerNonSharedNode()->isContentEditable())
455
477
        return false;
456
 
        
457
 
    if (m_didInitiateDrag && m_document == m_dragInitiator && result.isSelected())
 
478
 
 
479
    if (m_didInitiateDrag && m_documentUnderMouse == m_dragInitiator && result.isSelected())
458
480
        return false;
459
481
 
460
482
    return true;
461
483
}
462
484
 
463
 
DragOperation DragController::tryDHTMLDrag(DragData* dragData)
464
 
{   
 
485
static DragOperation defaultOperationForDrag(DragOperation srcOpMask)
 
486
{
 
487
    // This is designed to match IE's operation fallback for the case where
 
488
    // the page calls preventDefault() in a drag event but doesn't set dropEffect.
 
489
    if (srcOpMask & DragOperationCopy)
 
490
         return DragOperationCopy;
 
491
    if (srcOpMask & DragOperationMove || srcOpMask & DragOperationGeneric)
 
492
        return DragOperationMove;
 
493
    if (srcOpMask & DragOperationLink)
 
494
        return DragOperationLink;
 
495
 
 
496
    // FIXME: Does IE really return "generic" even if no operations were allowed by the source?
 
497
    return DragOperationGeneric;
 
498
}
 
499
 
 
500
bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation)
 
501
{
465
502
    ASSERT(dragData);
466
 
    ASSERT(m_document);
467
 
    DragOperation op = DragOperationNone;
 
503
    ASSERT(m_documentUnderMouse);
468
504
    RefPtr<Frame> mainFrame = m_page->mainFrame();
469
505
    RefPtr<FrameView> viewProtector = mainFrame->view();
470
506
    if (!viewProtector)
471
 
        return DragOperationNone;
472
 
    
473
 
    ClipboardAccessPolicy policy = m_document->securityOrigin()->isLocal() ? ClipboardReadable : ClipboardTypesReadable;
 
507
        return false;
 
508
 
 
509
    ClipboardAccessPolicy policy = m_documentUnderMouse->securityOrigin()->isLocal() ? ClipboardReadable : ClipboardTypesReadable;
474
510
    RefPtr<Clipboard> clipboard = dragData->createClipboard(policy);
475
 
    DragOperation srcOp = dragData->draggingSourceOperationMask();
476
 
    clipboard->setSourceOperation(srcOp);
477
 
    
 
511
    DragOperation srcOpMask = dragData->draggingSourceOperationMask();
 
512
    clipboard->setSourceOperation(srcOpMask);
 
513
 
478
514
    PlatformMouseEvent event = createMouseEvent(dragData);
479
 
    if (mainFrame->eventHandler()->updateDragAndDrop(event, clipboard.get())) {
480
 
        // *op unchanged if no source op was set
481
 
        if (!clipboard->destinationOperation(op)) {
482
 
            // The element accepted but they didn't pick an operation, so we pick one for them
483
 
            // (as does WinIE).
484
 
            if (srcOp & DragOperationCopy)
485
 
                op = DragOperationCopy;
486
 
            else if (srcOp & DragOperationMove || srcOp & DragOperationGeneric)
487
 
                op = DragOperationMove;
488
 
            else if (srcOp & DragOperationLink)
489
 
                op = DragOperationLink;
490
 
            else
491
 
                op = DragOperationGeneric;
492
 
        } else if (!(op & srcOp)) {
493
 
            op = DragOperationNone;
494
 
        }
495
 
 
 
515
    if (!mainFrame->eventHandler()->updateDragAndDrop(event, clipboard.get())) {
496
516
        clipboard->setAccessPolicy(ClipboardNumb);    // invalidate clipboard here for security
497
 
        return op;
498
 
    }
499
 
    return op;
 
517
        return false;
 
518
    }
 
519
 
 
520
    if (!clipboard->destinationOperation(operation)) {
 
521
        // The element accepted but they didn't pick an operation, so we pick one (to match IE).
 
522
        operation = defaultOperationForDrag(srcOpMask);
 
523
    } else if (!(srcOpMask & operation)) {
 
524
        // The element picked an operation which is not supported by the source
 
525
        operation = DragOperationNone;
 
526
    }
 
527
 
 
528
    clipboard->setAccessPolicy(ClipboardNumb);    // invalidate clipboard here for security
 
529
    return true;
500
530
}
501
531
 
502
532
bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos)
511
541
 
512
542
    mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true);
513
543
 
514
 
    if (mouseDownTarget.image() 
 
544
    if (mouseDownTarget.image()
515
545
        && !mouseDownTarget.absoluteImageURL().isEmpty()
516
546
        && frame->settings()->loadsImagesAutomatically()
517
547
        && m_dragSourceAction & DragSourceActionImage)
529
559
    return false;
530
560
 
531
561
}
532
 
    
 
562
 
533
563
static CachedImage* getCachedImage(Element* element)
534
564
{
535
565
    ASSERT(element);
536
566
    RenderObject* renderer = element->renderer();
537
 
    if (!renderer || !renderer->isImage()) 
 
567
    if (!renderer || !renderer->isImage())
538
568
        return 0;
539
 
    RenderImage* image = static_cast<RenderImage*>(renderer);
 
569
    RenderImage* image = toRenderImage(renderer);
540
570
    return image->cachedImage();
541
571
}
542
 
    
 
572
 
543
573
static Image* getImage(Element* element)
544
574
{
545
575
    ASSERT(element);
546
576
    RenderObject* renderer = element->renderer();
547
 
    if (!renderer || !renderer->isImage()) 
 
577
    if (!renderer || !renderer->isImage())
548
578
        return 0;
549
 
    
550
 
    RenderImage* image = static_cast<RenderImage*>(renderer);
 
579
 
 
580
    RenderImage* image = toRenderImage(renderer);
551
581
    if (image->cachedImage() && !image->cachedImage()->errorOccurred())
552
582
        return image->cachedImage()->image();
553
583
    return 0;
554
584
}
555
 
    
 
585
 
556
586
static void prepareClipboardForImageDrag(Frame* src, Clipboard* clipboard, Element* node, const KURL& linkURL, const KURL& imageURL, const String& label)
557
587
{
558
588
    RefPtr<Range> range = src->document()->createRange();
559
589
    ExceptionCode ec = 0;
560
590
    range->selectNode(node, ec);
561
 
    ASSERT(ec == 0);
562
 
    src->selection()->setSelection(Selection(range.get(), DOWNSTREAM));           
 
591
    ASSERT(!ec);
 
592
    src->selection()->setSelection(VisibleSelection(range.get(), DOWNSTREAM));
563
593
    clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, src);
564
594
}
565
 
    
 
595
 
566
596
static IntPoint dragLocForDHTMLDrag(const IntPoint& mouseDraggedPoint, const IntPoint& dragOrigin, const IntPoint& dragImageOffset, bool isLinkImage)
567
597
{
568
598
    // dragImageOffset is the cursor position relative to the lower-left corner of the image.
569
 
#if PLATFORM(MAC) 
570
 
    // We add in the Y dimension because we are a flipped view, so adding moves the image down. 
 
599
#if PLATFORM(MAC)
 
600
    // We add in the Y dimension because we are a flipped view, so adding moves the image down.
571
601
    const int yOffset = dragImageOffset.y();
572
602
#else
573
603
    const int yOffset = -dragImageOffset.y();
574
604
#endif
575
 
    
 
605
 
576
606
    if (isLinkImage)
577
607
        return IntPoint(mouseDraggedPoint.x() - dragImageOffset.x(), mouseDraggedPoint.y() + yOffset);
578
 
    
 
608
 
579
609
    return IntPoint(dragOrigin.x() - dragImageOffset.x(), dragOrigin.y() + yOffset);
580
610
}
581
 
    
 
611
 
582
612
static IntPoint dragLocForSelectionDrag(Frame* src)
583
613
{
584
614
    IntRect draggingRect = enclosingIntRect(src->selectionBounds());
593
623
#endif
594
624
    return IntPoint(xpos, ypos);
595
625
}
596
 
    
 
626
 
597
627
bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag)
598
 
{    
 
628
{
599
629
    ASSERT(src);
600
630
    ASSERT(clipboard);
601
 
    
 
631
 
602
632
    if (!src->view() || !src->contentRenderer())
603
633
        return false;
604
 
    
 
634
 
605
635
    HitTestResult dragSource = HitTestResult(dragOrigin);
606
636
    dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true);
607
637
    KURL linkURL = dragSource.absoluteLinkURL();
608
638
    KURL imageURL = dragSource.absoluteImageURL();
609
639
    bool isSelected = dragSource.isSelected();
610
 
    
 
640
 
611
641
    IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos());
612
 
    
 
642
 
613
643
    m_draggingImageURL = KURL();
614
 
    m_dragOperation = srcOp;
615
 
    
 
644
    m_sourceDragOperation = srcOp;
 
645
 
616
646
    DragImageRef dragImage = 0;
617
647
    IntPoint dragLoc(0, 0);
618
648
    IntPoint dragImageOffset(0, 0);
619
 
    
620
 
    if (isDHTMLDrag) 
 
649
 
 
650
    if (isDHTMLDrag)
621
651
        dragImage = clipboard->createDragImage(dragImageOffset);
622
 
    
 
652
 
623
653
    // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging.
624
654
    // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp.
625
655
    if (dragImage) {
626
656
        dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty());
627
657
        m_dragOffset = dragImageOffset;
628
658
    }
629
 
    
 
659
 
630
660
    bool startedDrag = true; // optimism - we almost always manage to start the drag
631
 
    
 
661
 
632
662
    Node* node = dragSource.innerNonSharedNode();
633
 
    
 
663
 
634
664
    Image* image = getImage(static_cast<Element*>(node));
635
665
    if (!imageURL.isEmpty() && node && node->isElementNode() && image
636
666
            && (m_dragSourceAction & DragSourceActionImage)) {
637
 
        // We shouldn't be starting a drag for an image that can't provide an extension. 
 
667
        // We shouldn't be starting a drag for an image that can't provide an extension.
638
668
        // This is an early detection for problems encountered later upon drop.
639
669
        ASSERT(!image->filenameExtension().isEmpty());
640
670
        Element* element = static_cast<Element*>(node);
641
671
        if (!clipboard->hasData()) {
642
 
            m_draggingImageURL = imageURL; 
 
672
            m_draggingImageURL = imageURL;
643
673
            prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, dragSource.altDisplayString());
644
674
        }
645
 
        
 
675
 
646
676
        m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard);
647
 
        
 
677
 
648
678
        if (!dragImage) {
649
679
            IntRect imageRect = dragSource.imageRect();
650
680
            imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location())));
651
681
            doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset);
652
 
        } else 
 
682
        } else
653
683
            // DHTML defined drag image
654
684
            doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
655
685
 
666
696
            Position pos = src->selection()->base();
667
697
            Node* node = enclosingAnchorElement(pos);
668
698
            if (node)
669
 
                src->selection()->setSelection(Selection::selectionFromContentsOfNode(node));
 
699
                src->selection()->setSelection(VisibleSelection::selectionFromContentsOfNode(node));
670
700
        }
671
701
 
672
702
        m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard);
675
705
            IntSize size = dragImageSize(dragImage);
676
706
            m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset);
677
707
            dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y());
678
 
        } 
 
708
        }
679
709
        doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true);
680
710
    } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) {
681
 
        RefPtr<Range> selectionRange = src->selection()->toRange();
 
711
        RefPtr<Range> selectionRange = src->selection()->toNormalizedRange();
682
712
        ASSERT(selectionRange);
683
 
        if (!clipboard->hasData()) 
 
713
        if (!clipboard->hasData())
684
714
            clipboard->writeRange(selectionRange.get(), src);
685
715
        m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard);
686
716
        if (!dragImage) {
698
728
        // under the mousedown point, so linkURL, imageURL and isSelected are all false/empty.
699
729
        startedDrag = false;
700
730
    }
701
 
    
 
731
 
702
732
    if (dragImage)
703
733
        deleteDragImage(dragImage);
704
734
    return startedDrag;
705
735
}
706
 
    
 
736
 
707
737
void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, const IntRect& rect, Clipboard* clipboard, Frame* frame, IntPoint& dragImageOffset)
708
738
{
709
739
    IntPoint mouseDownPoint = dragOrigin;
710
740
    DragImageRef dragImage;
711
741
    IntPoint origin;
712
 
    
 
742
 
713
743
    Image* image = getImage(element);
714
744
    if (image && image->size().height() * image->size().width() <= MaxOriginalImageArea
715
745
        && (dragImage = createDragImageFromImage(image))) {
716
746
        IntSize originalSize = rect.size();
717
747
        origin = rect.location();
718
 
        
 
748
 
719
749
        dragImage = fitDragImageToMaxSize(dragImage, rect.size(), maxDragImageSize());
720
750
        dragImage = dissolveDragImageToFraction(dragImage, DragImageAlpha);
721
751
        IntSize newSize = dragImageSize(dragImage);
722
 
        
 
752
 
723
753
        // Properly orient the drag image and orient it differently if it's smaller than the original
724
754
        float scale = newSize.width() / (float)originalSize.width();
725
755
        float dx = origin.x() - mouseDownPoint.x();
737
767
        if (dragImage)
738
768
            origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).width(), DragIconBottomInset);
739
769
    }
740
 
    
 
770
 
741
771
    dragImageOffset.setX(mouseDownPoint.x() + origin.x());
742
772
    dragImageOffset.setY(mouseDownPoint.y() + origin.y());
743
773
    doSystemDrag(dragImage, dragImageOffset, dragOrigin, clipboard, frame, false);
744
 
    
 
774
 
745
775
    deleteDragImage(dragImage);
746
776
}
747
 
    
 
777
 
748
778
void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool forLink)
749
779
{
750
780
    m_didInitiateDrag = true;
754
784
    RefPtr<FrameView> viewProtector = frameProtector->view();
755
785
    m_client->startDrag(image, viewProtector->windowToContents(frame->view()->contentsToWindow(dragLoc)),
756
786
        viewProtector->windowToContents(frame->view()->contentsToWindow(eventPos)), clipboard, frameProtector.get(), forLink);
757
 
    
 
787
 
758
788
    cleanupAfterSystemDrag();
759
789
}
760
 
    
 
790
 
761
791
// Manual drag caret manipulation
762
792
void DragController::placeDragCaret(const IntPoint& windowPoint)
763
793
{
764
 
    Frame* mainFrame = m_page->mainFrame();    
765
 
    Document* newDraggingDoc = mainFrame->documentAtPoint(windowPoint);
766
 
    if (m_document != newDraggingDoc) {
767
 
        if (m_document)
768
 
            cancelDrag();
769
 
        m_document = newDraggingDoc;
770
 
    }
771
 
    if (!m_document)
 
794
    mouseMovedIntoDocument(m_page->mainFrame()->documentAtPoint(windowPoint));
 
795
    if (!m_documentUnderMouse)
772
796
        return;
773
 
    Frame* frame = m_document->frame();
774
 
    ASSERT(frame);
 
797
    Frame* frame = m_documentUnderMouse->frame();
775
798
    FrameView* frameView = frame->view();
776
799
    if (!frameView)
777
800
        return;
778
801
    IntPoint framePoint = frameView->windowToContents(windowPoint);
779
 
    Selection dragCaret(frame->visiblePositionForPoint(framePoint));  
 
802
    VisibleSelection dragCaret(frame->visiblePositionForPoint(framePoint));
780
803
    m_page->dragCaretController()->setSelection(dragCaret);
781
804
}
782
 
    
783
 
}
 
805
 
 
806
} // namespace WebCore
 
807
 
 
808
#endif // ENABLE(DRAG_SUPPORT)