55230fdc1154e23e758c8840b8938d0c2ede72bf
[WebKit-https.git] / WebCore / page / FrameView.cpp
1 /* This file is part of the KDE project
2  *
3  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4  *                     1999 Lars Knoll <knoll@kde.org>
5  *                     1999 Antti Koivisto <koivisto@kde.org>
6  *                     2000 Dirk Mueller <mueller@kde.org>
7  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "config.h"
26 #include "FrameView.h"
27
28 #include "CachedImage.h"
29 #include "Cursor.h"
30 #include "EventNames.h"
31 #include "Frame.h"
32 #include "HTMLInputElement.h"
33 #include "Image.h"
34 #include "AccessibilityObjectCache.h"
35 #include "PlatformKeyboardEvent.h"
36 #include "PlatformMouseEvent.h"
37 #include "MouseEventWithHitTestResults.h"
38 #include "RenderText.h"
39 #include "SelectionController.h"
40 #include "PlatformWheelEvent.h"
41 #include "cssstyleselector.h"
42 #include "dom2_eventsimpl.h"
43 #include "HTMLDocument.h"
44 #include "html_inlineimpl.h"
45 #include "HTMLNames.h"
46 #include "khtml_settings.h"
47 #include "RenderArena.h"
48 #include "RenderCanvas.h"
49 #include "render_frames.h"
50 #include "render_line.h"
51 #include "render_replaced.h"
52 #include "render_style.h"
53
54 namespace WebCore {
55
56 using namespace EventNames;
57 using namespace HTMLNames;
58
59 class FrameViewPrivate {
60 public:
61     FrameViewPrivate(FrameView* view)
62         : m_hasBorder(false)
63         , layoutTimer(view, &FrameView::layoutTimerFired)
64         , hoverTimer(view, &FrameView::hoverTimerFired)
65     {
66         repaintRects = 0;
67         isTransparent = false;
68         vmode = hmode = ScrollBarAuto;
69         needToInitScrollBars = true;
70         reset();
71     }
72     ~FrameViewPrivate()
73     {
74         delete repaintRects;
75     }
76     void reset()
77     {
78         underMouse = 0;
79         linkPressed = false;
80         useSlowRepaints = false;
81         dragTarget = 0;
82         borderTouched = false;
83         scrollBarMoved = false;
84         ignoreWheelEvents = false;
85         borderX = 30;
86         borderY = 30;
87         prevMouseX = -1;
88         prevMouseY = -1;
89         clickCount = 0;
90         clickNode = 0;
91         scrollingSelf = false;
92         layoutTimer.stop();
93         delayedLayout = false;
94         mousePressed = false;
95         doFullRepaint = true;
96         layoutSchedulingEnabled = true;
97         layoutSuppressed = false;
98         layoutCount = 0;
99         firstLayout = true;
100         hoverTimer.stop();
101         if (repaintRects)
102             repaintRects->clear();
103         resizingFrameSet = 0;
104     }
105
106     RefPtr<Node> underMouse;
107
108     bool borderTouched : 1;
109     bool borderStart : 1;
110     bool scrollBarMoved : 1;
111     bool doFullRepaint : 1;
112     bool m_hasBorder : 1;
113     
114     ScrollBarMode vmode;
115     ScrollBarMode hmode;
116     bool linkPressed;
117     bool useSlowRepaints;
118     bool ignoreWheelEvents;
119
120     int borderX, borderY;
121     int clickCount;
122     RefPtr<Node> clickNode;
123
124     int prevMouseX, prevMouseY;
125     bool scrollingSelf;
126     Timer<FrameView> layoutTimer;
127     bool delayedLayout;
128     
129     bool layoutSchedulingEnabled;
130     bool layoutSuppressed;
131     int layoutCount;
132
133     bool firstLayout;
134     bool needToInitScrollBars;
135     bool mousePressed;
136     bool isTransparent;
137     
138     Timer<FrameView> hoverTimer;
139     
140     // Used by objects during layout to communicate repaints that need to take place only
141     // after all layout has been completed.
142     DeprecatedPtrList<RenderObject::RepaintInfo>* repaintRects;
143     
144     RefPtr<Node> dragTarget;
145     RefPtr<HTMLFrameSetElement> resizingFrameSet;
146 };
147
148 FrameView::FrameView(Frame *frame)
149     : _refCount(1)
150     , m_frame(frame)
151     , d(new FrameViewPrivate(this))
152     , m_medium("screen")
153 {
154     init();
155
156     show();
157 }
158
159 FrameView::~FrameView()
160 {
161     resetScrollBars();
162
163     ASSERT(_refCount == 0);
164
165     if (d->hoverTimer.isActive())
166         d->hoverTimer.stop();
167     if (m_frame) {
168         // FIXME: Is this really the right place to call detach on the document?
169         if (Document* doc = m_frame->document())
170             doc->detach();
171         if (RenderPart* renderer = m_frame->ownerRenderer())
172             renderer->setWidget(0);
173     }
174
175     delete d;
176     d = 0;
177 }
178
179 void FrameView::clearPart()
180 {
181     m_frame = 0;
182 }
183
184 void FrameView::resetScrollBars()
185 {
186     // Reset the document's scrollbars back to our defaults before we yield the floor.
187     d->firstLayout = true;
188     suppressScrollBars(true);
189     ScrollView::setVScrollBarMode(d->vmode);
190     ScrollView::setHScrollBarMode(d->hmode);
191     suppressScrollBars(false);
192 }
193
194 void FrameView::init()
195 {
196     _marginWidth = -1; // undefined
197     _marginHeight = -1;
198     _width = 0;
199     _height = 0;
200 }
201
202 void FrameView::clear()
203 {
204     setStaticBackground(false);
205     
206     // FIXME: 6498 Should just be able to call m_frame->selection().clear()
207     m_frame->setSelection(SelectionController());
208
209     d->reset();
210
211 #if INSTRUMENT_LAYOUT_SCHEDULING
212     if (d->layoutTimer.isActive() && m_frame->document() && !m_frame->document()->ownerElement())
213         printf("Killing the layout timer from a clear at %d\n", m_frame->document()->elapsedTime());
214 #endif    
215     d->layoutTimer.stop();
216
217     cleared();
218
219     suppressScrollBars(true);
220 }
221
222 void FrameView::initScrollBars()
223 {
224     if (!d->needToInitScrollBars)
225         return;
226     d->needToInitScrollBars = false;
227     setScrollBarsMode(hScrollBarMode());
228 }
229
230 void FrameView::setMarginWidth(int w)
231 {
232     // make it update the rendering area when set
233     _marginWidth = w;
234 }
235
236 void FrameView::setMarginHeight(int h)
237 {
238     // make it update the rendering area when set
239     _marginHeight = h;
240 }
241
242 void FrameView::adjustViewSize()
243 {
244     if (m_frame->document()) {
245         Document *document = m_frame->document();
246
247         RenderCanvas* root = static_cast<RenderCanvas *>(document->renderer());
248         if ( !root )
249             return;
250         
251         int docw = root->docWidth();
252         int doch = root->docHeight();
253     
254         resizeContents(docw, doch);
255     }
256 }
257
258 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollBarMode& hMode, ScrollBarMode& vMode)
259 {
260     // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
261     // overflow:hidden and overflow:scroll on <body> as applying to the document's
262     // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
263     // use the root element.
264     switch(o->style()->overflow()) {
265         case OHIDDEN:
266             hMode = vMode = ScrollBarAlwaysOff;
267             break;
268         case OSCROLL:
269             hMode = vMode = ScrollBarAlwaysOn;
270             break;
271         case OAUTO:
272             hMode = vMode = ScrollBarAuto;
273             break;
274         default:
275             // Don't set it at all.
276             ;
277     }
278 }
279
280 bool FrameView::inLayout() const
281 {
282     return d->layoutSuppressed;
283 }
284
285 int FrameView::layoutCount() const
286 {
287     return d->layoutCount;
288 }
289
290 bool FrameView::needsFullRepaint() const
291 {
292     return d->doFullRepaint;
293 }
294
295 void FrameView::addRepaintInfo(RenderObject* o, const IntRect& r)
296 {
297     if (!d->repaintRects) {
298         d->repaintRects = new DeprecatedPtrList<RenderObject::RepaintInfo>;
299         d->repaintRects->setAutoDelete(true);
300     }
301     
302     d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
303 }
304
305 void FrameView::layout()
306 {
307     if (d->layoutSuppressed)
308         return;
309     
310     d->layoutTimer.stop();
311     d->delayedLayout = false;
312
313     if (!m_frame) {
314         // FIXME: Do we need to set _width here?
315         // FIXME: Should we set _height here too?
316         _width = visibleWidth();
317         return;
318     }
319
320     Document* document = m_frame->document();
321     if (!document) {
322         // FIXME: Should we set _height here too?
323         _width = visibleWidth();
324         return;
325     }
326
327     d->layoutSchedulingEnabled = false;
328
329     // Always ensure our style info is up-to-date.  This can happen in situations where
330     // the layout beats any sort of style recalc update that needs to occur.
331     if (document->hasChangedChild())
332         document->recalcStyle();
333
334     RenderCanvas* root = static_cast<RenderCanvas*>(document->renderer());
335     if (!root) {
336         // FIXME: Do we need to set _width or _height here?
337         d->layoutSchedulingEnabled = true;
338         return;
339     }
340
341     ScrollBarMode hMode = d->hmode;
342     ScrollBarMode vMode = d->vmode;
343     
344     RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
345     if (document->isHTMLDocument()) {
346         Node *body = static_cast<HTMLDocument*>(document)->body();
347         if (body && body->renderer()) {
348             if (body->hasTagName(framesetTag)) {
349                 body->renderer()->setNeedsLayout(true);
350                 vMode = ScrollBarAlwaysOff;
351                 hMode = ScrollBarAlwaysOff;
352             }
353             else if (body->hasTagName(bodyTag)) {
354                 RenderObject* o = (rootRenderer->style()->overflow() == OVISIBLE) ? body->renderer() : rootRenderer;
355                 applyOverflowToViewport(o, hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
356             }
357         }
358     }
359     else if (rootRenderer)
360         applyOverflowToViewport(rootRenderer, hMode, vMode); // XML/XHTML UAs use the root element.
361
362 #if INSTRUMENT_LAYOUT_SCHEDULING
363     if (d->firstLayout && !document->ownerElement())
364         printf("Elapsed time before first layout: %d\n", document->elapsedTime());
365 #endif
366
367     d->doFullRepaint = d->firstLayout || root->printingMode();
368     if (d->repaintRects)
369         d->repaintRects->clear();
370
371     // Now set our scrollbar state for the layout.
372     ScrollBarMode currentHMode = hScrollBarMode();
373     ScrollBarMode currentVMode = vScrollBarMode();
374
375     bool didFirstLayout = false;
376     if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
377         suppressScrollBars(true);
378         if (d->firstLayout) {
379             d->firstLayout = false;
380             didFirstLayout = true;
381             
382             // Set the initial vMode to AlwaysOn if we're auto.
383             if (vMode == ScrollBarAuto)
384                 ScrollView::setVScrollBarMode(ScrollBarAlwaysOn); // This causes a vertical scrollbar to appear.
385             // Set the initial hMode to AlwaysOff if we're auto.
386             if (hMode == ScrollBarAuto)
387                 ScrollView::setHScrollBarMode(ScrollBarAlwaysOff); // This causes a horizontal scrollbar to disappear.
388         }
389         
390         if (hMode == vMode)
391             ScrollView::setScrollBarsMode(hMode);
392         else {
393             ScrollView::setHScrollBarMode(hMode);
394             ScrollView::setVScrollBarMode(vMode);
395         }
396
397         suppressScrollBars(false, true);
398     }
399
400     int oldHeight = _height;
401     int oldWidth = _width;
402     
403     _height = visibleHeight();
404     _width = visibleWidth();
405
406     if (oldHeight != _height || oldWidth != _width)
407         d->doFullRepaint = true;
408     
409     RenderLayer* layer = root->layer();
410      
411     if (!d->doFullRepaint) {
412         layer->computeRepaintRects();
413         root->repaintObjectsBeforeLayout();
414     }
415
416     root->layout();
417
418     m_frame->invalidateSelection();
419    
420     d->layoutSchedulingEnabled=true;
421     d->layoutSuppressed = false;
422
423     if (!root->printingMode())
424         resizeContents(layer->width(), layer->height());
425
426     // Now update the positions of all layers.
427     layer->updateLayerPositions(d->doFullRepaint);
428
429     // We update our widget positions right after doing a layout.
430     root->updateWidgetPositions();
431     
432     if (d->repaintRects && !d->repaintRects->isEmpty()) {
433         // FIXME: Could optimize this and have objects removed from this list
434         // if they ever do full repaints.
435         RenderObject::RepaintInfo* r;
436         DeprecatedPtrListIterator<RenderObject::RepaintInfo> it(*d->repaintRects);
437         for ( ; (r = it.current()); ++it)
438             r->m_object->repaintRectangle(r->m_repaintRect);
439         d->repaintRects->clear();
440     }
441     
442     d->layoutCount++;
443
444 #if __APPLE__
445     if (AccessibilityObjectCache::accessibilityEnabled())
446         root->document()->getAccObjectCache()->postNotification(root, "AXLayoutComplete");
447     updateDashboardRegions();
448 #endif
449
450     if (root->needsLayout()) {
451         //qDebug("needs layout, delaying repaint");
452         scheduleRelayout();
453         return;
454     }
455     setStaticBackground(d->useSlowRepaints);
456
457     if (didFirstLayout)
458         m_frame->didFirstLayout();
459 }
460
461 //
462 // Event Handling
463 //
464 /////////////////
465
466 void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
467 {
468     if (!m_frame->document())
469         return;
470
471     RefPtr<FrameView> protector(this);
472
473     int xm, ym;
474     viewportToContents(mouseEvent.x(), mouseEvent.y(), xm, ym);
475
476     d->mousePressed = true;
477
478     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(false, true, false, xm, ym, mouseEvent);
479
480     if (m_frame->passSubframeEventToSubframe(mev)) {
481         invalidateClick();
482         return;
483     }
484
485     d->clickCount = mouseEvent.clickCount();
486     d->clickNode = mev.innerNode();
487
488     bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.innerNode(), true, d->clickCount, mouseEvent, true);
489
490     if (!swallowEvent) {
491         m_frame->handleMousePressEvent(mev);
492         // Many AK widgets run their own event loops and consume events while the mouse is down.
493         // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
494         // the khtml state with this mouseUp, which khtml never saw.
495         // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
496         // is a hole here if the widget consumes the mouseUp and subsequent events.
497         if (m_frame->lastEventIsMouseUp())
498             d->mousePressed = false;
499     }
500 }
501
502 void FrameView::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
503 {
504     if (!m_frame->document())
505         return;
506
507     RefPtr<FrameView> protector(this);
508
509     int xm, ym;
510     viewportToContents(mouseEvent.x(), mouseEvent.y(), xm, ym);
511
512     // We get this instead of a second mouse-up 
513     d->mousePressed = false;
514
515     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(false, true, false, xm, ym, mouseEvent);
516
517     if (m_frame->passSubframeEventToSubframe(mev))
518         return;
519
520     d->clickCount = mouseEvent.clickCount();
521     bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.innerNode(), true, d->clickCount, mouseEvent, false);
522
523     if (mev.innerNode() == d->clickNode)
524         dispatchMouseEvent(clickEvent, mev.innerNode(), true, d->clickCount, mouseEvent, true);
525
526     // Qt delivers a release event AND a double click event.
527     if (!swallowEvent) {
528         m_frame->handleMouseReleaseEvent(mev);
529         m_frame->handleMouseReleaseDoubleClickEvent(mev);
530     }
531
532     invalidateClick();
533 }
534
535 static bool isSubmitImage(Node *node)
536 {
537     return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE;
538 }
539
540 static Cursor selectCursor(const MouseEventWithHitTestResults& event, Frame* frame, bool mousePressed)
541 {
542     // During selection, use an I-beam no matter what we're over.
543     if (mousePressed && frame->hasSelection())
544         return iBeamCursor();
545
546     Node* node = event.innerNode();
547     RenderObject* renderer = node ? node->renderer() : 0;
548     RenderStyle* style = renderer ? renderer->style() : 0;
549
550     if (style && style->cursorImage() && !style->cursorImage()->image()->isNull())
551         return style->cursorImage()->image();
552
553     switch (style ? style->cursor() : CURSOR_AUTO) {
554         case CURSOR_AUTO:
555             if (!event.url().isNull() || isSubmitImage(node))
556                 return handCursor();
557             if ((node && node->isContentEditable()) || (renderer && renderer->isText() && renderer->canSelect()))
558                 return iBeamCursor();
559             return pointerCursor();
560         case CURSOR_CROSS:
561             return crossCursor();
562         case CURSOR_POINTER:
563             return handCursor();
564         case CURSOR_MOVE:
565             return moveCursor();
566         case CURSOR_E_RESIZE:
567             return eastResizeCursor();
568         case CURSOR_W_RESIZE:
569             return westResizeCursor();
570         case CURSOR_N_RESIZE:
571             return northResizeCursor();
572         case CURSOR_S_RESIZE:
573             return southResizeCursor();
574         case CURSOR_NE_RESIZE:
575             return northEastResizeCursor();
576         case CURSOR_SW_RESIZE:
577             return southWestResizeCursor();
578         case CURSOR_NW_RESIZE:
579             return northWestResizeCursor();
580         case CURSOR_SE_RESIZE:
581             return southEastResizeCursor();
582         case CURSOR_TEXT:
583             return iBeamCursor();
584         case CURSOR_WAIT:
585             return waitCursor();
586         case CURSOR_HELP:
587             return helpCursor();
588         case CURSOR_DEFAULT:
589             return pointerCursor();
590     }
591     return pointerCursor();
592 }
593
594 void FrameView::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent)
595 {
596     // in Radar 3703768 we saw frequent crashes apparently due to the
597     // part being null here, which seems impossible, so check for nil
598     // but also assert so that we can try to figure this out in debug
599     // builds, if it happens.
600     ASSERT(m_frame);
601     if (!m_frame || !m_frame->document())
602         return;
603
604     if (d->hoverTimer.isActive())
605         d->hoverTimer.stop();
606
607     int xm, ym;
608     viewportToContents(mouseEvent.x(), mouseEvent.y(), xm, ym);
609
610     if (d->resizingFrameSet) {
611         dispatchMouseEvent(mousemoveEvent, d->resizingFrameSet.get(), false, 0, mouseEvent, false);
612         return;
613     }
614
615     // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
616     // if we are allowed to select.
617     // This means that :hover and :active freeze in the state they were in when the mouse
618     // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
619     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(d->mousePressed && m_frame->mouseDownMayStartSelect(),
620         d->mousePressed, true, xm, ym, mouseEvent);
621
622     if (!m_frame->passSubframeEventToSubframe(mev))
623         setCursor(selectCursor(mev, m_frame.get(), d->mousePressed));
624         
625     bool swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.innerNode(), false, 0, mouseEvent, true);
626     if (!swallowEvent)
627         m_frame->handleMouseMoveEvent(mev);
628 }
629
630 void FrameView::invalidateClick()
631 {
632     d->clickCount = 0;
633     d->clickNode = 0;
634 }
635
636 void FrameView::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
637 {
638     if (!m_frame->document())
639         return;
640
641     RefPtr<FrameView> protector(this);
642
643     int xm, ym;
644     viewportToContents(mouseEvent.x(), mouseEvent.y(), xm, ym);
645
646     d->mousePressed = false;
647
648     if (d->resizingFrameSet) {
649         dispatchMouseEvent(mouseupEvent, d->resizingFrameSet.get(), true, d->clickCount, mouseEvent, false);
650         return;
651     }
652
653     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(false, false, false, xm, ym, mouseEvent);
654
655     if (m_frame->passSubframeEventToSubframe(mev))
656         return;
657
658     bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.innerNode(), true, d->clickCount, mouseEvent, false);
659
660     if (d->clickCount > 0 && mev.innerNode() == d->clickNode)
661         dispatchMouseEvent(clickEvent, mev.innerNode(), true, d->clickCount, mouseEvent, true);
662
663     if (!swallowEvent)
664         m_frame->handleMouseReleaseEvent(mev);
665
666     invalidateClick();
667 }
668
669 bool FrameView::dispatchDragEvent(const AtomicString &eventType, Node *dragTarget, const PlatformMouseEvent& event, Clipboard *clipboard)
670 {
671     int clientX, clientY;
672     viewportToContents(event.x(), event.y(), clientX, clientY);
673     
674     RefPtr<MouseEvent> me = new MouseEvent(eventType,
675         true, true, m_frame->document()->defaultView(),
676         0, event.globalX(), event.globalY(), clientX, clientY,
677         event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
678         0, 0, clipboard);
679
680     ExceptionCode ec = 0;
681     EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec, true);
682     return me->defaultPrevented();
683 }
684
685 bool FrameView::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
686 {
687     bool accept = false;
688     int xm, ym;
689     viewportToContents(event.x(), event.y(), xm, ym);
690     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(true, false, false, xm, ym, PlatformMouseEvent());
691
692     // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
693     Node* newTarget = mev.innerNode();
694     if (newTarget && newTarget->isTextNode())
695         newTarget = newTarget->parentNode();
696
697     if (d->dragTarget != newTarget) {
698         // note this ordering is explicitly chosen to match WinIE
699         if (newTarget)
700             accept = dispatchDragEvent(dragenterEvent, newTarget, event, clipboard);
701         if (d->dragTarget)
702             dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
703     } else {
704         if (newTarget)
705             accept = dispatchDragEvent(dragoverEvent, newTarget, event, clipboard);
706     }
707     d->dragTarget = newTarget;
708
709     return accept;
710 }
711
712 void FrameView::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
713 {
714     if (d->dragTarget)
715         dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
716     d->dragTarget = 0;
717 }
718
719 bool FrameView::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
720 {
721     bool accept = false;
722     if (d->dragTarget)
723         accept = dispatchDragEvent(dropEvent, d->dragTarget.get(), event, clipboard);
724     d->dragTarget = 0;
725     return accept;
726 }
727
728 Node* FrameView::nodeUnderMouse() const
729 {
730     return d->underMouse.get();
731 }
732
733 bool FrameView::scrollTo(const IntRect &bounds)
734 {
735     d->scrollingSelf = true; // so scroll events get ignored
736
737     int x, y, xe, ye;
738     x = bounds.x();
739     y = bounds.y();
740     xe = bounds.right() - 1;
741     ye = bounds.bottom() - 1;
742     
743     int deltax;
744     int deltay;
745
746     int curHeight = visibleHeight();
747     int curWidth = visibleWidth();
748
749     if (ye - y>curHeight-d->borderY)
750         ye = y + curHeight - d->borderY;
751
752     if (xe - x>curWidth-d->borderX)
753         xe = x + curWidth - d->borderX;
754
755     // is xpos of target left of the view's border?
756     if (x < contentsX() + d->borderX )
757         deltax = x - contentsX() - d->borderX;
758     // is xpos of target right of the view's right border?
759     else if (xe + d->borderX > contentsX() + curWidth)
760         deltax = xe + d->borderX - ( contentsX() + curWidth );
761     else
762         deltax = 0;
763
764     // is ypos of target above upper border?
765     if (y < contentsY() + d->borderY)
766         deltay = y - contentsY() - d->borderY;
767     // is ypos of target below lower border?
768     else if (ye + d->borderY > contentsY() + curHeight)
769         deltay = ye + d->borderY - ( contentsY() + curHeight );
770     else
771         deltay = 0;
772
773     int maxx = curWidth - d->borderX;
774     int maxy = curHeight - d->borderY;
775
776     int scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax > -maxx ? deltax : -maxx);
777     int scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay > -maxy ? deltay : -maxy);
778
779     if (contentsX() + scrollX < 0)
780         scrollX = -contentsX();
781     else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
782         scrollX = contentsWidth() - visibleWidth() - contentsX();
783
784     if (contentsY() + scrollY < 0)
785         scrollY = -contentsY();
786     else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
787         scrollY = contentsHeight() - visibleHeight() - contentsY();
788
789     scrollBy(scrollX, scrollY);
790
791     // generate abs(scroll.)
792     if (scrollX < 0)
793         scrollX = -scrollX;
794     if (scrollY < 0)
795         scrollY = -scrollY;
796
797     d->scrollingSelf = false;
798
799     return scrollX != maxx && scrollY != maxy;
800 }
801
802 void FrameView::focusNextPrevNode(bool next)
803 {
804     // Sets the focus node of the document to be the node after (or if next is false, before) the current focus node.
805     // Only nodes that are selectable (i.e. for which isSelectable() returns true) are taken into account, and the order
806     // used is that specified in the HTML spec (see Document::nextFocusNode() and Document::previousFocusNode()
807     // for details).
808
809     Document *doc = m_frame->document();
810     Node *oldFocusNode = doc->focusNode();
811     Node *newFocusNode;
812
813     // Find the next/previous node from the current one
814     if (next)
815         newFocusNode = doc->nextFocusNode(oldFocusNode);
816     else
817         newFocusNode = doc->previousFocusNode(oldFocusNode);
818
819     // If there was previously no focus node and the user has scrolled the document, then instead of picking the first
820     // focusable node in the document, use the first one that lies within the visible area (if possible).
821     if (!oldFocusNode && newFocusNode && d->scrollBarMoved) {
822         bool visible = false;
823         Node *toFocus = newFocusNode;
824         while (!visible && toFocus) {
825             if (toFocus->getRect().intersects(IntRect(contentsX(), contentsY(), visibleWidth(), visibleHeight()))) {
826                 // toFocus is visible in the contents area
827                 visible = true;
828             } else {
829                 // toFocus is _not_ visible in the contents area, pick the next node
830                 if (next)
831                     toFocus = doc->nextFocusNode(toFocus);
832                 else
833                     toFocus = doc->previousFocusNode(toFocus);
834             }
835         }
836
837         if (toFocus)
838             newFocusNode = toFocus;
839     }
840
841     d->scrollBarMoved = false;
842
843     if (!newFocusNode)
844       {
845         // No new focus node, scroll to bottom or top depending on next
846         if (next)
847             scrollTo(IntRect(contentsX()+visibleWidth()/2,contentsHeight(),0,0));
848         else
849             scrollTo(IntRect(contentsX()+visibleWidth()/2,0,0,0));
850     }
851     else {
852         // EDIT FIXME: if it's an editable element, activate the caret
853         // otherwise, hide it
854         if (newFocusNode->isContentEditable()) {
855             // make caret visible
856         } 
857         else {
858             // hide caret
859         }
860
861         // Scroll the view as necessary to ensure that the new focus node is visible
862         if (oldFocusNode) {
863             if (!scrollTo(newFocusNode->getRect()))
864                 return;
865         }
866         else {
867             if (doc->renderer()) {
868                 doc->renderer()->enclosingLayer()->scrollRectToVisible(IntRect(contentsX(), next ? 0: contentsHeight(), 0, 0));
869             }
870         }
871     }
872     // Set focus node on the document
873     m_frame->document()->setFocusNode(newFocusNode);
874 }
875
876 void FrameView::setMediaType( const DeprecatedString &medium )
877 {
878     m_medium = medium;
879 }
880
881 DeprecatedString FrameView::mediaType() const
882 {
883     // See if we have an override type.
884     DeprecatedString overrideType = m_frame->overrideMediaType();
885     if (!overrideType.isNull())
886         return overrideType;
887     return m_medium;
888 }
889
890
891 void FrameView::useSlowRepaints()
892 {
893     d->useSlowRepaints = true;
894     setStaticBackground(true);
895 }
896
897 void FrameView::setScrollBarsMode(ScrollBarMode mode)
898 {
899     d->vmode = mode;
900     d->hmode = mode;
901     
902     ScrollView::setScrollBarsMode(mode);
903 }
904
905 void FrameView::setVScrollBarMode(ScrollBarMode mode)
906 {
907     d->vmode = mode;
908     ScrollView::setVScrollBarMode(mode);
909 }
910
911 void FrameView::setHScrollBarMode(ScrollBarMode mode)
912 {
913     d->hmode = mode;
914     ScrollView::setHScrollBarMode(mode);
915 }
916
917 void FrameView::restoreScrollBar()
918 {
919     suppressScrollBars(false);
920 }
921
922 void FrameView::setResizingFrameSet(HTMLFrameSetElement *frameSet)
923 {
924     d->resizingFrameSet = frameSet;
925 }
926
927 bool FrameView::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool cancelable,
928     int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
929 {
930     // if the target node is a text node, dispatch on the parent node - rdar://4196646
931     if (targetNode && targetNode->isTextNode())
932         targetNode = targetNode->parentNode();
933     d->underMouse = targetNode;
934
935     // mouseout/mouseover
936     if (setUnder) {
937         int clientX, clientY;
938         viewportToContents(mouseEvent.x(), mouseEvent.y(), clientX, clientY);
939         if (d->prevMouseX != clientX || d->prevMouseY != clientY) {
940             // ### this code sucks. we should save the oldUnder instead of calculating
941             // it again. calculating is expensive! (Dirk)
942             // Also, there's no guarantee that the old under node is even around any more,
943             // so we could be sending a mouseout to a node that never got a mouseover.
944             RefPtr<Node> oldUnder;
945             if (d->prevMouseX >= 0) {
946                 oldUnder = m_frame->document()->prepareMouseEvent(true, false, true,
947                     d->prevMouseX, d->prevMouseY, mouseEvent).innerNode();
948                 if (oldUnder && oldUnder->isTextNode())
949                     oldUnder = oldUnder->parentNode();
950             }
951             d->prevMouseX = clientX;
952             d->prevMouseY = clientY;
953             if (oldUnder != targetNode) {
954                 // send mouseout event to the old node
955                 if (oldUnder)
956                     EventTargetNodeCast(oldUnder.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, targetNode);
957                 // send mouseover event to the new node
958                 if (targetNode)
959                     EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, oldUnder.get());
960             }
961         }
962     }
963
964     bool swallowEvent = false;
965
966     if (targetNode)
967         swallowEvent = EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, eventType, clickCount);
968     
969     if (!swallowEvent && eventType == mousedownEvent) {
970         // Focus should be shifted on mouse down, not on a click.  -dwh
971         // Blur current focus node when a link/button is clicked; this
972         // is expected by some sites that rely on onChange handlers running
973         // from form fields before the button click is processed.
974         Node* node = targetNode;
975         RenderObject* renderer = node ? node->renderer() : 0;
976                 
977         // Walk up the render tree to search for a node to focus.
978         // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
979         while (renderer) {
980             node = renderer->element();
981             if (node && node->isFocusable())
982                 break;
983             renderer = renderer->parent();
984         }
985         // If focus shift is blocked, we eat the event.  Note we should never clear swallowEvent
986         // if the page already set it (e.g., by canceling default behavior).
987         if (node && node->isMouseFocusable()) {
988             if (!m_frame->document()->setFocusNode(node))
989                 swallowEvent = true;
990         } else if (!node || !node->focused()) {
991             if (!m_frame->document()->setFocusNode(0))
992                 swallowEvent = true;
993         }
994     }
995
996     return swallowEvent;
997 }
998
999 void FrameView::setIgnoreWheelEvents( bool e )
1000 {
1001     d->ignoreWheelEvents = e;
1002 }
1003
1004 void FrameView::handleWheelEvent(PlatformWheelEvent& e)
1005 {
1006     Document *doc = m_frame->document();
1007     if (doc) {
1008         RenderObject *docRenderer = doc->renderer();
1009         if (docRenderer) {
1010             int x, y;
1011             viewportToContents(e.x(), e.y(), x, y);
1012
1013             RenderObject::NodeInfo hitTestResult(true, false);
1014             doc->renderer()->layer()->hitTest(hitTestResult, x, y); 
1015             Node *node = hitTestResult.innerNode();
1016
1017            if (m_frame->passWheelEventToChildWidget(node)) {
1018                 e.accept();
1019                 return;
1020             }
1021             if (node) {
1022                 EventTargetNodeCast(node)->dispatchWheelEvent(e);
1023                 if (e.isAccepted())
1024                     return;
1025             }
1026         }
1027     }
1028 }
1029
1030 void FrameView::scrollBarMoved()
1031 {
1032     // FIXME: Need to arrange for this to be called when the view is scrolled!
1033     if (!d->scrollingSelf)
1034         d->scrollBarMoved = true;
1035 }
1036
1037 void FrameView::repaintRectangle(const IntRect& r, bool immediate)
1038 {
1039     updateContents(r, immediate);
1040 }
1041
1042 void FrameView::layoutTimerFired(Timer<FrameView>*)
1043 {
1044 #if INSTRUMENT_LAYOUT_SCHEDULING
1045     if (m_frame->document() && !m_frame->document()->ownerElement())
1046         printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
1047 #endif
1048     layout();
1049 }
1050
1051 void FrameView::hoverTimerFired(Timer<FrameView>*)
1052 {
1053     d->hoverTimer.stop();
1054     m_frame->document()->prepareMouseEvent(false, false, true, d->prevMouseX, d->prevMouseY, PlatformMouseEvent());
1055 }
1056
1057 void FrameView::scheduleRelayout()
1058 {
1059     if (!d->layoutSchedulingEnabled)
1060         return;
1061
1062     if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
1063         return;
1064
1065     int delay = m_frame->document()->minimumLayoutDelay();
1066     if (d->layoutTimer.isActive() && d->delayedLayout && !delay)
1067         unscheduleRelayout();
1068     if (d->layoutTimer.isActive())
1069         return;
1070
1071     d->delayedLayout = delay != 0;
1072
1073 #if INSTRUMENT_LAYOUT_SCHEDULING
1074     if (!m_frame->document()->ownerElement())
1075         printf("Scheduling layout for %d\n", delay);
1076 #endif
1077
1078     d->layoutTimer.startOneShot(delay * 0.001);
1079 }
1080
1081 bool FrameView::layoutPending()
1082 {
1083     return d->layoutTimer.isActive();
1084 }
1085
1086 bool FrameView::haveDelayedLayoutScheduled()
1087 {
1088     return d->layoutTimer.isActive() && d->delayedLayout;
1089 }
1090
1091 void FrameView::unscheduleRelayout()
1092 {
1093     if (!d->layoutTimer.isActive())
1094         return;
1095
1096 #if INSTRUMENT_LAYOUT_SCHEDULING
1097     if (m_frame->document() && !m_frame->document()->ownerElement())
1098         printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
1099 #endif
1100     
1101     d->layoutTimer.stop();
1102     d->delayedLayout = false;
1103 }
1104
1105 bool FrameView::isTransparent() const
1106 {
1107     return d->isTransparent;
1108 }
1109
1110 void FrameView::setTransparent(bool isTransparent)
1111 {
1112     d->isTransparent = isTransparent;
1113 }
1114
1115 void FrameView::scheduleHoverStateUpdate()
1116 {
1117     if (!d->hoverTimer.isActive())
1118         d->hoverTimer.startOneShot(0);
1119 }
1120
1121 void FrameView::setHasBorder(bool b)
1122 {
1123     d->m_hasBorder = b;
1124     updateBorder();
1125 }
1126
1127 bool FrameView::hasBorder() const
1128 {
1129     return d->m_hasBorder;
1130 }
1131
1132 void FrameView::cleared()
1133 {
1134     if (m_frame)
1135         if (RenderPart* renderer = m_frame->ownerRenderer())
1136             renderer->viewCleared();
1137 }
1138
1139 }