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