Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: webkit/pending/DragController.cpp

Issue 6500: Cleaning up the unfork (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/pending/Document.cpp ('k') | webkit/pending/EmptyClients.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2007 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 #include "CSSStyleDeclaration.h"
30 #include "Clipboard.h"
31 #include "ClipboardAccessPolicy.h"
32 #include "DocLoader.h"
33 #include "Document.h"
34 #include "DocumentFragment.h"
35 #include "DragActions.h"
36 #include "DragClient.h"
37 #include "DragData.h"
38 #include "Editor.h"
39 #include "EditorClient.h"
40 #include "Element.h"
41 #include "EventHandler.h"
42 #include "FloatRect.h"
43 #include "Frame.h"
44 #include "FrameLoader.h"
45 #include "FrameView.h"
46 #include "HTMLAnchorElement.h"
47 #include "HTMLInputElement.h"
48 #include "HTMLNames.h"
49 #include "HitTestResult.h"
50 #include "Image.h"
51 #include "MoveSelectionCommand.h"
52 #include "Node.h"
53 #include "Page.h"
54 #include "RenderFileUploadControl.h"
55 #include "RenderImage.h"
56 #include "ReplaceSelectionCommand.h"
57 #include "ResourceRequest.h"
58 #include "SelectionController.h"
59 #include "Settings.h"
60 #include "SystemTime.h"
61 #include "Text.h"
62 #include "markup.h"
63 #include <wtf/RefPtr.h>
64
65 namespace WebCore {
66
67 static PlatformMouseEvent createMouseEvent(DragData* dragData)
68 {
69 // FIXME: We should fake modifier keys here.
70 return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPositi on(),
71 LeftButton, MouseEventMoved, 0, false, false, fals e, false, currentTime());
72
73 }
74
75 DragController::DragController(Page* page, DragClient* client)
76 : m_page(page)
77 , m_client(client)
78 , m_document(0)
79 , m_dragInitiator(0)
80 , m_dragDestinationAction(DragDestinationActionNone)
81 , m_dragSourceAction(DragSourceActionNone)
82 , m_didInitiateDrag(false)
83 , m_isHandlingDrag(false)
84 , m_dragOperation(DragOperationNone)
85 {
86 }
87
88 DragController::~DragController()
89 {
90 m_client->dragControllerDestroyed();
91 }
92
93 static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragD ata, RefPtr<Range> context,
94 bool allowPlainText, bool& chosePlainT ext)
95 {
96 ASSERT(dragData);
97 chosePlainText = false;
98
99 Document* document = context->ownerDocument();
100 ASSERT(document);
101 if (document && dragData->containsCompatibleContent()) {
102 if (PassRefPtr<DocumentFragment> fragment = dragData->asFragment(documen t))
103 return fragment;
104
105 if (dragData->containsURL()) {
106 String title;
107 String url = dragData->asURL(&title);
108 if (!url.isEmpty()) {
109 ExceptionCode ec;
110 RefPtr<HTMLAnchorElement> anchor = static_cast<HTMLAnchorElement *>(document->createElement("a", ec).get());
111 anchor->setHref(url);
112 RefPtr<Node> anchorText = document->createTextNode(title);
113 anchor->appendChild(anchorText, ec);
114 RefPtr<DocumentFragment> fragment = document->createDocumentFrag ment();
115 fragment->appendChild(anchor, ec);
116 return fragment.get();
117 }
118 }
119 }
120 if (allowPlainText && dragData->containsPlainText()) {
121 chosePlainText = true;
122 return createFragmentFromText(context.get(), dragData->asPlainText()).ge t();
123 }
124
125 return 0;
126 }
127
128 bool DragController::dragIsMove(SelectionController* selection, DragData* dragDa ta)
129 {
130 return m_document == m_dragInitiator
131 && selection->isContentEditable()
132 && !isCopyKeyDown();
133 }
134
135 void DragController::cancelDrag()
136 {
137 m_page->dragCaretController()->clear();
138 }
139
140 void DragController::dragEnded()
141 {
142 m_dragInitiator = 0;
143 m_didInitiateDrag = false;
144 m_page->dragCaretController()->clear();
145 }
146
147 DragOperation DragController::dragEntered(DragData* dragData)
148 {
149 return dragEnteredOrUpdated(dragData);
150 }
151
152 void DragController::dragExited(DragData* dragData)
153 {
154 ASSERT(dragData);
155 Frame* mainFrame = m_page->mainFrame();
156
157 if (RefPtr<FrameView> v = mainFrame->view()) {
158 ClipboardAccessPolicy policy = mainFrame->loader()->baseURL().isLocalFil e() ? ClipboardReadable : ClipboardTypesReadable;
159 RefPtr<Clipboard> clipboard = dragData->createClipboard(policy);
160 clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
161 mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get());
162 clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard he re for security
163 }
164
165 cancelDrag();
166 m_document = 0;
167 }
168
169 DragOperation DragController::dragUpdated(DragData* dragData)
170 {
171 return dragEnteredOrUpdated(dragData);
172 }
173
174 bool DragController::performDrag(DragData* dragData)
175 {
176 ASSERT(dragData);
177 m_document = m_page->mainFrame()->documentAtPoint(dragData->clientPosition() );
178 if (m_isHandlingDrag) {
179 ASSERT(m_dragDestinationAction & DragDestinationActionDHTML);
180 m_client->willPerformDragDestinationAction(DragDestinationActionDHTML, d ragData);
181 RefPtr<Frame> mainFrame = m_page->mainFrame();
182 if (mainFrame->view()) {
183 // Sending an event can result in the destruction of the view and pa rt.
184 RefPtr<Clipboard> clipboard = dragData->createClipboard(ClipboardRea dable);
185 clipboard->setSourceOperation(dragData->draggingSourceOperationMask( ));
186 mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragD ata), clipboard.get());
187 clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboar d here for security
188 }
189 m_document = 0;
190 return true;
191 }
192
193 if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeDrag(dr agData, m_dragDestinationAction)) {
194 m_document = 0;
195 return true;
196 }
197
198 m_document = 0;
199
200 if (operationForLoad(dragData) == DragOperationNone)
201 return false;
202
203 m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragDa ta);
204 m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL()));
205 return true;
206 }
207
208 DragOperation DragController::dragEnteredOrUpdated(DragData* dragData)
209 {
210 ASSERT(dragData);
211 IntPoint windowPoint = dragData->clientPosition();
212
213 Document* newDraggingDoc = 0;
214 if (Frame* frame = m_page->mainFrame())
215 newDraggingDoc = frame->documentAtPoint(windowPoint);
216 if (m_document != newDraggingDoc) {
217 if (m_document)
218 cancelDrag();
219 m_document = newDraggingDoc;
220 }
221
222 m_dragDestinationAction = m_client->actionMaskForDrag(dragData);
223
224 DragOperation operation = DragOperationNone;
225
226 if (m_dragDestinationAction == DragDestinationActionNone)
227 cancelDrag();
228 else {
229 operation = tryDocumentDrag(dragData, m_dragDestinationAction);
230 if (operation == DragOperationNone && (m_dragDestinationAction & DragDes tinationActionLoad))
231 return operationForLoad(dragData);
232 }
233
234 return operation;
235 }
236
237 static HTMLInputElement* asFileInput(Node* node)
238 {
239 ASSERT(node);
240
241 // The button for a FILE input is a sub element with no set input type
242 // In order to get around this problem we assume any non-FILE input element
243 // is this internal button, and try querying the shadow parent node.
244 if (node->hasTagName(HTMLNames::inputTag) && node->isShadowNode() && static_ cast<HTMLInputElement*>(node)->inputType() != HTMLInputElement::FILE)
245 node = node->shadowParentNode();
246
247 if (!node || !node->hasTagName(HTMLNames::inputTag))
248 return 0;
249
250 HTMLInputElement* inputElem = static_cast<HTMLInputElement*>(node);
251 if (inputElem->inputType() == HTMLInputElement::FILE)
252 return inputElem;
253
254 return 0;
255 }
256
257 DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinatio nAction actionMask)
258 {
259 ASSERT(dragData);
260
261 if (!m_document)
262 return DragOperationNone;
263
264 DragOperation operation = DragOperationNone;
265 if (actionMask & DragDestinationActionDHTML)
266 operation = tryDHTMLDrag(dragData);
267 m_isHandlingDrag = operation != DragOperationNone;
268
269 RefPtr<FrameView> frameView = m_document->view();
270 if (!frameView)
271 return operation;
272
273 if ((actionMask & DragDestinationActionEdit) && !m_isHandlingDrag && canProc essDrag(dragData)) {
274 if (dragData->containsColor())
275 return DragOperationGeneric;
276
277 IntPoint dragPos = dragData->clientPosition();
278 IntPoint point = frameView->windowToContents(dragPos);
279 Element* element = m_document->elementFromPoint(point.x(), point.y());
280 ASSERT(element);
281 Frame* innerFrame = element->document()->frame();
282 ASSERT(innerFrame);
283 if (!asFileInput(element)) {
284 Selection dragCaret;
285 if (Frame* frame = m_document->frame())
286 dragCaret = frame->visiblePositionForPoint(point);
287 m_page->dragCaretController()->setSelection(dragCaret);
288 }
289
290 return dragIsMove(innerFrame->selection(), dragData) ? DragOperationMove : DragOperationCopy;
291 }
292
293 m_page->dragCaretController()->clear();
294 return operation;
295 }
296
297 DragSourceAction DragController::delegateDragSourceAction(const IntPoint& window Point)
298 {
299 m_dragSourceAction = m_client->dragSourceActionMaskForPoint(windowPoint);
300 return m_dragSourceAction;
301 }
302
303 DragOperation DragController::operationForLoad(DragData* dragData)
304 {
305 ASSERT(dragData);
306 Document* doc = 0;
307 doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
308 if (doc && (m_didInitiateDrag || doc->isPluginDocument() || (doc->frame() && doc->frame()->editor()->clientIsEditable())))
309 return DragOperationNone;
310 return dragOperation(dragData);
311 }
312
313 static bool setSelectionToDragCaret(Frame* frame, Selection& dragCaret, RefPtr<R ange>& range, const IntPoint& point)
314 {
315 frame->selection()->setSelection(dragCaret);
316 if (frame->selection()->isNone()) {
317 dragCaret = frame->visiblePositionForPoint(point);
318 frame->selection()->setSelection(dragCaret);
319 range = dragCaret.toRange();
320 }
321 return !frame->selection()->isNone() && frame->selection()->isContentEditabl e();
322 }
323
324 bool DragController::concludeDrag(DragData* dragData, DragDestinationAction acti onMask)
325 {
326 ASSERT(dragData);
327 ASSERT(!m_isHandlingDrag);
328 ASSERT(actionMask & DragDestinationActionEdit);
329
330 if (!m_document)
331 return false;
332
333 IntPoint point = m_document->view()->windowToContents(dragData->clientPositi on());
334 Element* element = m_document->elementFromPoint(point.x(), point.y());
335 ASSERT(element);
336 Frame* innerFrame = element->ownerDocument()->frame();
337 ASSERT(innerFrame);
338
339 if (dragData->containsColor()) {
340 Color color = dragData->asColor();
341 if (!color.isValid())
342 return false;
343 if (!innerFrame)
344 return false;
345 RefPtr<Range> innerRange = innerFrame->selection()->toRange();
346 RefPtr<CSSStyleDeclaration> style = m_document->createCSSStyleDeclaratio n();
347 ExceptionCode ec;
348 style->setProperty("color", color.name(), ec);
349 if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get( )))
350 return false;
351 m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dr agData);
352 innerFrame->editor()->applyStyle(style.get(), EditActionSetColor);
353 return true;
354 }
355
356 if (!m_page->dragController()->canProcessDrag(dragData)) {
357 m_page->dragCaretController()->clear();
358 return false;
359 }
360
361 if (HTMLInputElement* fileInput = asFileInput(element)) {
362
363 if (!fileInput->isEnabled())
364 return false;
365
366 if (!dragData->containsFiles())
367 return false;
368
369 Vector<String> filenames;
370 dragData->asFilenames(filenames);
371 if (filenames.isEmpty())
372 return false;
373
374 // Ugly. For security none of the API's available to us to set the inpu t value
375 // on file inputs. Even forcing a change in HTMLInputElement doesn't wo rk as
376 // RenderFileUploadControl clears the file when doing updateFromElement( )
377 RenderFileUploadControl* renderer = static_cast<RenderFileUploadControl* >(fileInput->renderer());
378
379 if (!renderer)
380 return false;
381
382 // Only take the first filename as <input type="file" /> can only accept one
383 renderer->receiveDroppedFile(filenames[0]);
384 return true;
385 }
386
387 Selection dragCaret(m_page->dragCaretController()->selection());
388 m_page->dragCaretController()->clear();
389 RefPtr<Range> range = dragCaret.toRange();
390
391 // For range to be null a WebKit client must have done something bad while
392 // manually controlling drag behaviour
393 if (!range)
394 return false;
395 DocLoader* loader = range->ownerDocument()->docLoader();
396 loader->setAllowStaleResources(true);
397 if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRich lyEditable()) {
398 bool chosePlainText = false;
399 RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragDat a, range, true, chosePlainText);
400 if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, r ange, EditorInsertActionDropped)) {
401 loader->setAllowStaleResources(false);
402 return false;
403 }
404
405 m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dr agData);
406 if (dragIsMove(innerFrame->selection(), dragData)) {
407 bool smartMove = innerFrame->selectionGranularity() == WordGranulari ty
408 && innerFrame->editor()->smartInsertDeleteEnabled()
409 && dragData->canSmartReplace();
410 applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base() , smartMove));
411 } else {
412 if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
413 applyCommand(ReplaceSelectionCommand::create(m_document, fragmen t, true, dragData->canSmartReplace(), chosePlainText));
414 }
415 } else {
416 String text = dragData->asPlainText();
417 if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, rang e.get(), EditorInsertActionDropped)) {
418 loader->setAllowStaleResources(false);
419 return false;
420 }
421
422 m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dr agData);
423 if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
424 applyCommand(ReplaceSelectionCommand::create(m_document, createFragm entFromText(range.get(), text), true, false, true));
425 }
426 loader->setAllowStaleResources(false);
427
428 return true;
429 }
430
431
432 bool DragController::canProcessDrag(DragData* dragData)
433 {
434 ASSERT(dragData);
435
436 if (!dragData->containsCompatibleContent())
437 return false;
438
439 IntPoint point = m_page->mainFrame()->view()->windowToContents(dragData->cli entPosition());
440 HitTestResult result = HitTestResult(point);
441 if (!m_page->mainFrame()->contentRenderer())
442 return false;
443
444 result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, tr ue);
445
446 if (!result.innerNonSharedNode())
447 return false;
448
449 if (dragData->containsFiles() && asFileInput(result.innerNonSharedNode()))
450 return true;
451
452 if (!result.innerNonSharedNode()->isContentEditable())
453 return false;
454
455 if (m_didInitiateDrag && m_document == m_dragInitiator && result.isSelected( ))
456 return false;
457
458 return true;
459 }
460
461 DragOperation DragController::tryDHTMLDrag(DragData* dragData)
462 {
463 ASSERT(dragData);
464 ASSERT(m_document);
465 DragOperation op = DragOperationNone;
466 RefPtr<Frame> frame = m_page->mainFrame();
467 RefPtr<FrameView> viewProtector = frame->view();
468 if (!viewProtector)
469 return DragOperationNone;
470
471 ClipboardAccessPolicy policy = frame->loader()->baseURL().isLocalFile() ? Cl ipboardReadable : ClipboardTypesReadable;
472 RefPtr<Clipboard> clipboard = dragData->createClipboard(policy);
473 DragOperation srcOp = dragData->draggingSourceOperationMask();
474 clipboard->setSourceOperation(srcOp);
475
476 PlatformMouseEvent event = createMouseEvent(dragData);
477 if (frame->eventHandler()->updateDragAndDrop(event, clipboard.get())) {
478 // *op unchanged if no source op was set
479 if (!clipboard->destinationOperation(op)) {
480 // The element accepted but they didn't pick an operation, so we pic k one for them
481 // (as does WinIE).
482 if (srcOp & DragOperationCopy)
483 op = DragOperationCopy;
484 else if (srcOp & DragOperationMove || srcOp & DragOperationGeneric)
485 op = DragOperationMove;
486 else if (srcOp & DragOperationLink)
487 op = DragOperationLink;
488 else
489 op = DragOperationGeneric;
490 } else if (!(op & srcOp)) {
491 op = DragOperationNone;
492 }
493
494 clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard he re for security
495 return op;
496 }
497 return op;
498 }
499
500 bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPo int& framePos)
501 {
502 ASSERT(frame);
503 ASSERT(frame->settings());
504
505 if (!frame->view() || !frame->contentRenderer())
506 return false;
507
508 HitTestResult mouseDownTarget = HitTestResult(framePos);
509
510 mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true );
511
512 if (mouseDownTarget.image()
513 && !mouseDownTarget.absoluteImageURL().isEmpty()
514 && frame->settings()->loadsImagesAutomatically()
515 && m_dragSourceAction & DragSourceActionImage)
516 return true;
517
518 if (!mouseDownTarget.absoluteLinkURL().isEmpty()
519 && m_dragSourceAction & DragSourceActionLink
520 && mouseDownTarget.isLiveLink())
521 return true;
522
523 if (mouseDownTarget.isSelected()
524 && m_dragSourceAction & DragSourceActionSelection)
525 return true;
526
527 return false;
528
529 }
530
531 static CachedImage* getCachedImage(Element* element)
532 {
533 ASSERT(element);
534 RenderObject* renderer = element->renderer();
535 if (!renderer || !renderer->isImage())
536 return 0;
537 RenderImage* image = static_cast<RenderImage*>(renderer);
538 return image->cachedImage();
539 }
540
541 static Image* getImage(Element* element)
542 {
543 ASSERT(element);
544 RenderObject* renderer = element->renderer();
545 if (!renderer || !renderer->isImage())
546 return 0;
547
548 RenderImage* image = static_cast<RenderImage*>(renderer);
549 if (image->cachedImage() && !image->cachedImage()->errorOccurred())
550 return image->cachedImage()->image();
551 return 0;
552 }
553
554 static void prepareClipboardForImageDrag(Frame* src, Clipboard* clipboard, Eleme nt* node, const KURL& linkURL, const KURL& imageURL, const String& label)
555 {
556 RefPtr<Range> range = src->document()->createRange();
557 ExceptionCode ec = 0;
558 range->selectNode(node, ec);
559 ASSERT(ec == 0);
560 src->selection()->setSelection(Selection(range.get(), DOWNSTREAM));
561 clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : ima geURL, label, src);
562 }
563
564 static IntPoint dragLocForDHTMLDrag(const IntPoint& mouseDraggedPoint, const Int Point& dragOrigin, const IntPoint& dragImageOffset, bool isLinkImage)
565 {
566 // dragImageOffset is the cursor position relative to the lower-left corner of the image.
567 #if PLATFORM(MAC)
568 // We add in the Y dimension because we are a flipped view, so adding moves the image down.
569 const int yOffset = dragImageOffset.y();
570 #else
571 const int yOffset = -dragImageOffset.y();
572 #endif
573
574 if (isLinkImage)
575 return IntPoint(mouseDraggedPoint.x() - dragImageOffset.x(), mouseDragge dPoint.y() + yOffset);
576
577 return IntPoint(dragOrigin.x() - dragImageOffset.x(), dragOrigin.y() + yOffs et);
578 }
579
580 static IntPoint dragLocForSelectionDrag(Frame* src)
581 {
582 IntRect draggingRect = enclosingIntRect(src->selectionRect());
583 int xpos = draggingRect.right();
584 xpos = draggingRect.x() < xpos ? draggingRect.x() : xpos;
585 int ypos = draggingRect.bottom();
586 #if PLATFORM(MAC)
587 // Deal with flipped coordinates on Mac
588 ypos = draggingRect.y() > ypos ? draggingRect.y() : ypos;
589 #else
590 ypos = draggingRect.y() < ypos ? draggingRect.y() : ypos;
591 #endif
592 return IntPoint(xpos, ypos);
593 }
594
595 bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s rcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDH TMLDrag)
596 {
597 ASSERT(src);
598 ASSERT(clipboard);
599
600 if (!src->view() || !src->contentRenderer())
601 return false;
602
603 HitTestResult dragSource = HitTestResult(dragOrigin);
604 dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true);
605 KURL linkURL = dragSource.absoluteLinkURL();
606 KURL imageURL = dragSource.absoluteImageURL();
607 bool isSelected = dragSource.isSelected();
608
609 IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos());
610
611 m_draggingImageURL = KURL();
612 m_dragOperation = srcOp;
613
614 DragImageRef dragImage = 0;
615 IntPoint dragLoc(0, 0);
616 IntPoint dragImageOffset(0, 0);
617
618 if (isDHTMLDrag)
619 dragImage = clipboard->createDragImage(dragImageOffset);
620
621 // We allow DHTML/JS to set the drag image, even if its a link, image or tex t we're dragging.
622 // This is in the spirit of the IE API, which allows overriding of pasteboar d data and DragOp.
623 if (dragImage) {
624 dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOf fset, !linkURL.isEmpty());
625 m_dragOffset = dragImageOffset;
626 }
627
628 bool startedDrag = true; // optimism - we almost always manage to start the drag
629
630 Node* node = dragSource.innerNonSharedNode();
631
632 if (!imageURL.isEmpty() && node && node->isElementNode()
633 && getImage(static_cast<Element*>(node))
634 && (m_dragSourceAction & DragSourceActionImage)) {
635 Element* element = static_cast<Element*>(node);
636 if (!clipboard->hasData()) {
637 m_draggingImageURL = imageURL;
638 prepareClipboardForImageDrag(src, clipboard, element, linkURL, image URL, dragSource.altDisplayString());
639 }
640
641 m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard);
642
643 if (!dragImage) {
644 IntRect imageRect = dragSource.imageRect();
645 imageRect.setLocation(m_page->mainFrame()->view()->windowToContents( src->view()->contentsToWindow(imageRect.location())));
646 doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset);
647 } else
648 // DHTML defined drag image
649 doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
650
651 } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink) ) {
652 if (!clipboard->hasData())
653 // Simplify whitespace so the title put on the clipboard resembles w hat the user sees
654 // on the web page. This includes replacing newlines with spaces.
655 clipboard->writeURL(linkURL, dragSource.textContent().simplifyWhiteS pace(), src);
656
657 m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard);
658 if (!dragImage) {
659 dragImage = m_client->createDragImageForLink(linkURL, dragSource.tex tContent(), src);
660 IntSize size = dragImageSize(dragImage);
661 m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset);
662 dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDr aggedPoint.y() + m_dragOffset.y());
663 }
664 doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true );
665 } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) {
666 RefPtr<Range> selectionRange = src->selection()->toRange();
667 ASSERT(selectionRange);
668 if (!clipboard->hasData())
669 clipboard->writeRange(selectionRange.get(), src);
670 m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOri gin, clipboard);
671 if (!dragImage) {
672 dragImage = createDragImageForSelection(src);
673 dragLoc = dragLocForSelectionDrag(src);
674 m_dragOffset = IntPoint((int)(dragOrigin.x() - dragLoc.x()), (int)(d ragOrigin.y() - dragLoc.y()));
675 }
676 doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
677 } else if (isDHTMLDrag) {
678 ASSERT(m_dragSourceAction & DragSourceActionDHTML);
679 m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard);
680 doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
681 } else {
682 // Only way I know to get here is if to get here is if the original elem ent clicked on in the mousedown is no longer
683 // under the mousedown point, so linkURL, imageURL and isSelected are al l false/empty.
684 startedDrag = false;
685 }
686
687 if (dragImage)
688 deleteDragImage(dragImage);
689 return startedDrag;
690 }
691
692 void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, c onst IntRect& rect, Clipboard* clipboard, Frame* frame, IntPoint& dragImageOffse t)
693 {
694 IntPoint mouseDownPoint = dragOrigin;
695 DragImageRef dragImage;
696 IntPoint origin;
697
698 Image* image = getImage(element);
699 if (image && image->size().height() * image->size().width() <= MaxOriginalIm ageArea
700 && (dragImage = createDragImageFromImage(image))) {
701 IntSize originalSize = rect.size();
702 origin = rect.location();
703
704 dragImage = fitDragImageToMaxSize(dragImage, rect.size(), maxDragImageSi ze());
705 dragImage = dissolveDragImageToFraction(dragImage, DragImageAlpha);
706 IntSize newSize = dragImageSize(dragImage);
707
708 // Properly orient the drag image and orient it differently if it's smal ler than the original
709 float scale = newSize.width() / (float)originalSize.width();
710 float dx = origin.x() - mouseDownPoint.x();
711 dx *= scale;
712 origin.setX((int)(dx + 0.5));
713 #if PLATFORM(MAC)
714 //Compensate for accursed flipped coordinates in cocoa
715 origin.setY(origin.y() + originalSize.height());
716 #endif
717 float dy = origin.y() - mouseDownPoint.y();
718 dy *= scale;
719 origin.setY((int)(dy + 0.5));
720 } else {
721 dragImage = createDragImageIconForCachedImage(getCachedImage(element));
722 if (dragImage)
723 origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).widt h(), DragIconBottomInset);
724 }
725
726 dragImageOffset.setX(mouseDownPoint.x() + origin.x());
727 dragImageOffset.setY(mouseDownPoint.y() + origin.y());
728 doSystemDrag(dragImage, dragImageOffset, dragOrigin, clipboard, frame, false );
729
730 deleteDragImage(dragImage);
731 }
732
733 void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, c onst IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool forLink)
734 {
735 m_didInitiateDrag = true;
736 m_dragInitiator = frame->document();
737 // Protect this frame and view, as a load may occur mid drag and attempt to unload this frame
738 RefPtr<Frame> frameProtector = m_page->mainFrame();
739 RefPtr<FrameView> viewProtector = frameProtector->view();
740 m_client->startDrag(image, viewProtector->windowToContents(frame->view()->co ntentsToWindow(dragLoc)),
741 viewProtector->windowToContents(frame->view()->contentsToWindow(eventPos )), clipboard, frameProtector.get(), forLink);
742
743 // Drag has ended, dragEnded *should* have been called, however it is possib le
744 // for the UIDelegate to take over the drag, and fail to send the appropriat e
745 // drag termination event. As dragEnded just resets drag variables, we just
746 // call it anyway to be on the safe side
747 // Except if drag and drop happens asynchronously, in which case dragging
748 // has not ended.
749 //dragEnded();
750 }
751
752 // Manual drag caret manipulation
753 void DragController::placeDragCaret(const IntPoint& windowPoint)
754 {
755 Frame* mainFrame = m_page->mainFrame();
756 Document* newDraggingDoc = mainFrame->documentAtPoint(windowPoint);
757 if (m_document != newDraggingDoc) {
758 if (m_document)
759 cancelDrag();
760 m_document = newDraggingDoc;
761 }
762 if (!m_document)
763 return;
764 Frame* frame = m_document->frame();
765 ASSERT(frame);
766 FrameView* frameView = frame->view();
767 if (!frameView)
768 return;
769 IntPoint framePoint = frameView->windowToContents(windowPoint);
770 Selection dragCaret(frame->visiblePositionForPoint(framePoint));
771 m_page->dragCaretController()->setSelection(dragCaret);
772 }
773
774 }
OLDNEW
« no previous file with comments | « webkit/pending/Document.cpp ('k') | webkit/pending/EmptyClients.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698