Reviewed by Harrison.
[WebKit-https.git] / WebCore / khtml / khtmlview.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 "khtmlview.moc"
25
26 #include "khtmlview.h"
27
28 #include "khtml_part.h"
29 #include "khtml_events.h"
30
31 #include "html/html_documentimpl.h"
32 #include "html/html_inlineimpl.h"
33 #include "html/html_formimpl.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 "rendering/render_text.h"
41 #include "xml/dom_nodeimpl.h"
42 #include "xml/dom2_eventsimpl.h"
43 #include "css/cssstyleselector.h"
44 #include "misc/htmlhashes.h"
45 #include "misc/helper.h"
46 #include "khtml_settings.h"
47 #include "khtml_printsettings.h"
48 #include "khtmlpart_p.h"
49
50 #include <kcursor.h>
51 #include <ksimpleconfig.h>
52 #include <kstandarddirs.h>
53 #include <kprinter.h>
54
55 #include <qtooltip.h>
56 #include <qpainter.h>
57 #include <qpaintdevicemetrics.h>
58 #include <kapplication.h>
59
60 #include <kimageio.h>
61 #include <assert.h>
62 #include <kdebug.h>
63 #include <kurldrag.h>
64 #include <qobjectlist.h>
65
66 #if APPLE_CHANGES
67 #include "KWQAccObjectCache.h"
68 #endif
69
70 #define PAINT_BUFFER_HEIGHT 128
71
72 // #define INSTRUMENT_LAYOUT_SCHEDULING 1
73
74 using namespace DOM;
75 using namespace khtml;
76 class KHTMLToolTip;
77
78 #ifndef QT_NO_TOOLTIP
79
80 class KHTMLToolTip : public QToolTip
81 {
82 public:
83     KHTMLToolTip(KHTMLView *view,  KHTMLViewPrivate* vp) : QToolTip(view->viewport())
84     {
85         m_view = view;
86         m_viewprivate = vp;
87     };
88
89 protected:
90     virtual void maybeTip(const QPoint &);
91
92 private:
93
94     KHTMLView *m_view;
95     KHTMLViewPrivate* m_viewprivate;
96 };
97
98 #endif
99
100 class KHTMLViewPrivate {
101     friend class KHTMLToolTip;
102 public:
103     KHTMLViewPrivate()
104     {
105         repaintRects = 0;
106         underMouse = 0;
107         clickNode = 0;
108         reset();
109 #if !APPLE_CHANGES
110         tp=0;
111         paintBuffer=0;
112         formCompletions=0;
113 #endif
114         layoutTimerId = 0;
115         delayedLayout = false;
116         mousePressed = false;
117 #ifndef QT_NO_TOOLTIP
118         tooltip = 0;
119 #endif
120         doFullRepaint = true;
121         isTransparent = false;
122 #if APPLE_CHANGES
123         vmode = hmode = QScrollView::Auto;
124         firstLayout = true;
125         needToInitScrollBars = true;
126 #else
127         prevScrollbarVisible = true;
128 #endif
129     }
130     ~KHTMLViewPrivate()
131     {
132 #if !APPLE_CHANGES
133         delete formCompletions;
134         delete tp; tp = 0;
135         delete paintBuffer; paintBuffer =0;
136 #endif
137         
138         if (underMouse)
139             underMouse->deref();
140         if (clickNode)
141             clickNode->deref();
142 #ifndef QT_NO_TOOLTIP
143         delete tooltip;
144 #endif
145         delete repaintRects;
146     }
147     void reset()
148     {
149         if (underMouse)
150             underMouse->deref();
151         underMouse = 0;
152         linkPressed = false;
153         useSlowRepaints = false;
154         dragTarget = 0;
155         borderTouched = false;
156 #if !APPLE_CHANGES
157 #ifndef KHTML_NO_SCROLLBARS
158         vmode = QScrollView::Auto;
159         hmode = QScrollView::Auto;
160 #else
161         vmode = QScrollView::AlwaysOff;
162         hmode = QScrollView::AlwaysOff;
163 #endif
164 #endif
165         scrollBarMoved = false;
166         ignoreWheelEvents = false;
167         borderX = 30;
168         borderY = 30;
169 #if !APPLE_CHANGES
170         clickX = -1;
171         clickY = -1;
172 #endif
173         prevMouseX = -1;
174         prevMouseY = -1;
175         clickCount = 0;
176         if (clickNode)
177             clickNode->deref();
178         clickNode = 0;
179         isDoubleClick = false;
180         scrollingSelf = false;
181         layoutTimerId = 0;
182         delayedLayout = false;
183         mousePressed = false;
184         doFullRepaint = true;
185         layoutSchedulingEnabled = true;
186         layoutSuppressed = false;
187         layoutCount = 0;
188 #if APPLE_CHANGES
189         firstLayout = true;
190 #endif
191         if (repaintRects)
192             repaintRects->clear();
193     }
194
195 #if !APPLE_CHANGES
196     QPainter *tp;
197     QPixmap  *paintBuffer;
198 #endif
199     NodeImpl *underMouse;
200
201     bool borderTouched:1;
202     bool borderStart:1;
203     bool scrollBarMoved:1;
204     bool doFullRepaint:1;
205     
206     QScrollView::ScrollBarMode vmode;
207     QScrollView::ScrollBarMode hmode;
208 #if !APPLE_CHANGES
209     bool prevScrollbarVisible;
210 #endif
211     bool linkPressed;
212     bool useSlowRepaints;
213     bool ignoreWheelEvents;
214
215     int borderX, borderY;
216 #if !APPLE_CHANGES
217     KSimpleConfig *formCompletions;
218
219     int clickX, clickY;
220 #endif
221     int clickCount;
222     NodeImpl *clickNode;
223     bool isDoubleClick;
224
225     int prevMouseX, prevMouseY;
226     bool scrollingSelf;
227     int layoutTimerId;
228     bool delayedLayout;
229     
230     bool layoutSchedulingEnabled;
231     bool layoutSuppressed;
232     int layoutCount;
233
234 #if APPLE_CHANGES
235     bool firstLayout;
236     bool needToInitScrollBars;
237 #endif
238     bool mousePressed;
239     bool isTransparent;
240 #ifndef QT_NO_TOOLTIP
241     KHTMLToolTip *tooltip;
242 #endif
243     
244     // Used by objects during layout to communicate repaints that need to take place only
245     // after all layout has been completed.
246     QPtrList<RenderObject::RepaintInfo>* repaintRects;
247     
248     Node dragTarget;
249 };
250
251 #ifndef QT_NO_TOOLTIP
252
253 void KHTMLToolTip::maybeTip(const QPoint& /*p*/)
254 {
255     DOM::NodeImpl *node = m_viewprivate->underMouse;
256     while ( node ) {
257         if ( node->isElementNode() ) {
258             AtomicString s = static_cast<DOM::ElementImpl*>( node )->getAttribute(ATTR_TITLE);
259             if (!s.isEmpty()) {
260                 QRect r( m_view->contentsToViewport( node->getRect().topLeft() ), node->getRect().size() );
261                 tip( r,  s.string() );
262             }
263             break;
264         }
265         node = node->parentNode();
266     }
267 }
268 #endif
269
270 KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent, const char *name)
271     : QScrollView( parent, name, WResizeNoErase | WRepaintNoErase | WPaintUnclipped ),
272       _refCount(1)
273 {
274     m_medium = "screen";
275
276     m_part = part;
277 #if APPLE_CHANGES
278     m_part->ref();
279 #endif
280     d = new KHTMLViewPrivate;
281
282 #if !APPLE_CHANGES
283     QScrollView::setVScrollBarMode(d->vmode);
284     QScrollView::setHScrollBarMode(d->hmode);
285 #endif
286     
287     connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotPaletteChanged()));
288     connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotScrollBarMoved()));
289
290     // initialize QScrollview
291     enableClipper(true);
292     viewport()->setMouseTracking(true);
293     viewport()->setBackgroundMode(NoBackground);
294
295     KImageIO::registerFormats();
296
297 #ifndef QT_NO_TOOLTIP
298     d->tooltip = new KHTMLToolTip( this, d );
299 #endif
300
301     init();
302
303     viewport()->show();
304 }
305
306 KHTMLView::~KHTMLView()
307 {
308 #if APPLE_CHANGES
309     resetScrollBars();
310 #endif
311
312     assert(_refCount == 0);
313
314     if (m_part)
315     {
316         //WABA: Is this Ok? Do I need to deref it as well?
317         //Does this need to be done somewhere else?
318         DOM::DocumentImpl *doc = m_part->xmlDocImpl();
319         if (doc)
320             doc->detach();
321
322 #if APPLE_CHANGES
323         m_part->deref();
324 #endif
325     }
326
327     delete d; d = 0;
328 }
329
330 void KHTMLView::clearPart()
331 {
332     if (m_part){
333         m_part->deref();
334         m_part = 0;
335     }
336 }
337
338 #if APPLE_CHANGES
339 void KHTMLView::resetScrollBars()
340 {
341     // Reset the document's scrollbars back to our defaults before we yield the floor.
342     d->firstLayout = true;
343     suppressScrollBars(true);
344     QScrollView::setVScrollBarMode(d->vmode);
345     QScrollView::setHScrollBarMode(d->hmode);
346     suppressScrollBars(false);
347 }
348 #endif
349
350 void KHTMLView::init()
351 {
352 #if !APPLE_CHANGES
353     if(!d->paintBuffer) d->paintBuffer = new QPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT);
354     if(!d->tp) d->tp = new QPainter();
355 #endif
356
357     setFocusPolicy(QWidget::StrongFocus);
358     viewport()->setFocusPolicy( QWidget::WheelFocus );
359     viewport()->setFocusProxy(this);
360
361     _marginWidth = -1; // undefined
362     _marginHeight = -1;
363     _width = 0;
364     _height = 0;
365
366     setAcceptDrops(true);
367     
368 #if !APPLE_CHANGES
369     resizeContents(visibleWidth(), visibleHeight());
370 #endif
371 }
372
373 void KHTMLView::clear()
374 {
375 //    viewport()->erase();
376
377     setStaticBackground(false);
378     
379     m_part->clearSelection();
380
381     d->reset();
382
383 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
384     if (d->layoutTimerId && m_part->xmlDocImpl() && !m_part->xmlDocImpl()->ownerElement())
385         printf("Killing the layout timer from a clear at %d\n", m_part->xmlDocImpl()->elapsedTime());
386 #endif
387     
388     killTimers();
389     emit cleared();
390
391 #if APPLE_CHANGES
392     suppressScrollBars(true);
393 #else
394     QScrollView::setHScrollBarMode(d->hmode);
395     if (d->vmode==Auto)
396         QScrollView::setVScrollBarMode(d->prevScrollbarVisible?AlwaysOn:Auto);
397     else
398         QScrollView::setVScrollBarMode(d->vmode);
399     resizeContents(visibleWidth(), visibleHeight());
400 #endif
401 }
402
403 void KHTMLView::hideEvent(QHideEvent* e)
404 {
405 //    viewport()->setBackgroundMode(PaletteBase);
406     QScrollView::hideEvent(e);
407 }
408
409 void KHTMLView::showEvent(QShowEvent* e)
410 {
411 //    viewport()->setBackgroundMode(NoBackground);
412     QScrollView::showEvent(e);
413 }
414
415 void KHTMLView::resizeEvent (QResizeEvent* e)
416 {
417     QScrollView::resizeEvent(e);
418
419 #if !APPLE_CHANGES
420     int w = visibleWidth();
421     int h = visibleHeight();
422
423     layout();
424
425     //  this is to make sure we get the right width even if the scrolbar has dissappeared
426     // due to the size change.
427     if(visibleHeight() != h || visibleWidth() != w)
428         layout();
429 #endif
430     if ( m_part && m_part->xmlDocImpl() )
431         m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
432
433     KApplication::sendPostedEvents(viewport(), QEvent::Paint);
434 }
435
436 #if APPLE_CHANGES
437 void KHTMLView::initScrollBars()
438 {
439     if (!d->needToInitScrollBars)
440         return;
441     d->needToInitScrollBars = false;
442     setScrollBarsMode(hScrollBarMode());
443 }
444 #endif
445
446 #if !APPLE_CHANGES
447
448 // this is to get rid of a compiler virtual overload mismatch warning. do not remove
449 void KHTMLView::drawContents( QPainter*)
450 {
451 }
452
453 void KHTMLView::drawContents( QPainter *p, int ex, int ey, int ew, int eh )
454 {
455     //kdDebug( 6000 ) << "drawContents x=" << ex << ",y=" << ey << ",w=" << ew << ",h=" << eh << endl;
456     if(!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
457         p->fillRect(ex, ey, ew, eh, palette().normal().brush(QColorGroup::Base));
458         return;
459     }
460     if ( d->paintBuffer->width() < visibleWidth() )
461         d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT);
462
463     int py=0;
464     while (py < eh) {
465         int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT;
466         d->tp->begin(d->paintBuffer);
467         d->tp->translate(-ex, -ey-py);
468         d->tp->fillRect(ex, ey+py, ew, ph, palette().normal().brush(QColorGroup::Base));
469         m_part->xmlDocImpl()->renderer()->print(d->tp, ex, ey+py, ew, ph, 0, 0);
470 #ifdef BOX_DEBUG
471         if (m_part->xmlDocImpl()->focusNode())
472         {
473             d->tp->setBrush(Qt::NoBrush);
474             d->tp->drawRect(m_part->xmlDocImpl()->focusNode()->getRect());
475         }
476 #endif
477         d->tp->end();
478
479         p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph);
480         py += PAINT_BUFFER_HEIGHT;
481     }
482
483     // EDIT FIXME: KDE needs to draw the caret here.
484
485     khtml::DrawContentsEvent event( p, ex, ey, ew, eh );
486     QApplication::sendEvent( m_part, &event );
487
488 }
489
490 #endif // !APPLE_CHANGES
491
492 void KHTMLView::setMarginWidth(int w)
493 {
494     // make it update the rendering area when set
495     _marginWidth = w;
496 }
497
498 void KHTMLView::setMarginHeight(int h)
499 {
500     // make it update the rendering area when set
501     _marginHeight = h;
502 }
503
504
505 void KHTMLView::adjustViewSize()
506 {
507     if( m_part->xmlDocImpl() ) {
508         DOM::DocumentImpl *document = m_part->xmlDocImpl();
509
510         khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
511         if ( !root )
512             return;
513         
514         int docw = root->docWidth();
515         int doch = root->docHeight();
516     
517         resizeContents(docw, doch);
518     }
519 }
520
521 void KHTMLView::applyBodyScrollQuirk(khtml::RenderObject* o, ScrollBarMode& hMode, ScrollBarMode& vMode)
522 {
523     // Handle the overflow:hidden/scroll quirk for the body elements.  WinIE treats
524     // overflow:hidden and overflow:scroll on <body> as applying to the document's
525     // scrollbars.  The CSS2.1 draft has even added a sentence, "HTML UAs may apply overflow
526     // specified on the body or HTML elements to the viewport."  Since WinIE and Mozilla both
527     // do it, we will do it too for <body> elements.
528     switch(o->style()->overflow()) {
529         case OHIDDEN:
530             hMode = vMode = AlwaysOff;
531             break;
532         case OSCROLL:
533             hMode = vMode = AlwaysOn;
534             break;
535         case OAUTO:
536             hMode = vMode = Auto;
537             break;
538         default:
539             // Don't set it at all.
540             ;
541     }
542 }
543
544 bool KHTMLView::inLayout() const
545 {
546     return d->layoutSuppressed;
547 }
548
549 int KHTMLView::layoutCount() const
550 {
551     return d->layoutCount;
552 }
553
554 bool KHTMLView::needsFullRepaint() const
555 {
556     return d->doFullRepaint;
557 }
558
559 void KHTMLView::addRepaintInfo(RenderObject* o, const QRect& r)
560 {
561     if (!d->repaintRects) {
562         d->repaintRects = new QPtrList<RenderObject::RepaintInfo>;
563         d->repaintRects->setAutoDelete(true);
564     }
565     
566     d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
567 }
568
569 void KHTMLView::layout()
570 {
571     if (d->layoutSuppressed)
572         return;
573     
574     d->layoutSchedulingEnabled=false;
575     killTimer(d->layoutTimerId);
576     d->layoutTimerId = 0;
577     d->delayedLayout = false;
578
579     if (!m_part) {
580         // FIXME: Do we need to set _width here?
581         // FIXME: Should we set _height here too?
582         _width = visibleWidth();
583         return;
584     }
585
586     DOM::DocumentImpl* document = m_part->xmlDocImpl();
587     if (!document) {
588         // FIXME: Should we set _height here too?
589         _width = visibleWidth();
590         return;
591     }
592
593     // Always ensure our style info is up-to-date.  This can happen in situations where
594     // the layout beats any sort of style recalc update that needs to occur.
595     if (document->hasChangedChild())
596         document->recalcStyle();
597
598     khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas*>(document->renderer());
599     if (!root) {
600         // FIXME: Do we need to set _width or _height here?
601         return;
602     }
603
604     ScrollBarMode hMode = d->hmode;
605     ScrollBarMode vMode = d->vmode;
606     
607     if (document->isHTMLDocument()) {
608         NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
609         if (body && body->renderer()) {
610             if (body->id() == ID_FRAMESET) {
611                 body->renderer()->setNeedsLayout(true);
612                 vMode = AlwaysOff;
613                 hMode = AlwaysOff;
614             }
615             else if (body->id() == ID_BODY)
616                 applyBodyScrollQuirk(body->renderer(), hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
617         }
618     }
619
620 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
621     if (d->firstLayout && !document->ownerElement())
622         printf("Elapsed time before first layout: %d\n", document->elapsedTime());
623 #endif
624
625     d->doFullRepaint = d->firstLayout || root->printingMode();
626     if (d->repaintRects)
627         d->repaintRects->clear();
628
629 #if APPLE_CHANGES
630     // Now set our scrollbar state for the layout.
631     ScrollBarMode currentHMode = hScrollBarMode();
632     ScrollBarMode currentVMode = vScrollBarMode();
633
634     bool didFirstLayout = false;
635     if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
636         suppressScrollBars(true);
637         if (d->firstLayout) {
638             d->firstLayout = false;
639             didFirstLayout = true;
640             
641             // Set the initial vMode to AlwaysOn if we're auto.
642             if (vMode == Auto)
643                 QScrollView::setVScrollBarMode(AlwaysOn); // This causes a vertical scrollbar to appear.
644             // Set the initial hMode to AlwaysOff if we're auto.
645             if (hMode == Auto)
646                 QScrollView::setHScrollBarMode(AlwaysOff); // This causes a horizontal scrollbar to disappear.
647         }
648         
649         if (hMode == vMode)
650             QScrollView::setScrollBarsMode(hMode);
651         else {
652             QScrollView::setHScrollBarMode(hMode);
653             QScrollView::setVScrollBarMode(vMode);
654         }
655
656         suppressScrollBars(false, true);
657     }
658 #else
659     QScrollView::setHScrollBarMode(hMode);
660     QScrollView::setVScrollBarMode(vMode);
661 #endif
662
663     int oldHeight = _height;
664     int oldWidth = _width;
665     
666     _height = visibleHeight();
667     _width = visibleWidth();
668
669     if (oldHeight != _height || oldWidth != _width)
670         d->doFullRepaint = true;
671     
672     RenderLayer* layer = root->layer();
673      
674     if (!d->doFullRepaint) {
675         layer->computeRepaintRects();
676         root->repaintObjectsBeforeLayout();
677     }
678
679     root->layout();
680
681     m_part->invalidateSelection();
682         
683     //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
684    
685     d->layoutSchedulingEnabled=true;
686     d->layoutSuppressed = false;
687
688     if (!root->printingMode())
689         resizeContents(layer->width(), layer->height());
690
691     // Now update the positions of all layers.
692     layer->updateLayerPositions(d->doFullRepaint);
693
694 #if APPLE_CHANGES
695     // We update our widget positions right after doing a layout.
696     root->updateWidgetPositions();
697 #endif
698     
699     if (d->repaintRects && !d->repaintRects->isEmpty()) {
700         // FIXME: Could optimize this and have objects removed from this list
701         // if they ever do full repaints.
702         RenderObject::RepaintInfo* r;
703         QPtrListIterator<RenderObject::RepaintInfo> it(*d->repaintRects);
704         for ( ; (r = it.current()); ++it)
705             r->m_object->repaintRectangle(r->m_repaintRect);
706         d->repaintRects->clear();
707     }
708     
709     d->layoutCount++;
710 #if APPLE_CHANGES
711     if (KWQAccObjectCache::accessibilityEnabled())
712         root->document()->getAccObjectCache()->postNotification(root, "AXLayoutComplete");
713 #endif
714
715 #if APPLE_CHANGES
716     updateDashboardRegions();
717 #endif
718
719     if (root->needsLayout()) {
720         //qDebug("needs layout, delaying repaint");
721         scheduleRelayout();
722         return;
723     }
724     setStaticBackground(d->useSlowRepaints);
725
726 #if APPLE_CHANGES
727     if (didFirstLayout) {
728         m_part->didFirstLayout();
729     }
730 #endif
731 }
732
733 #if APPLE_CHANGES
734 void KHTMLView::updateDashboardRegions()
735 {
736     DOM::DocumentImpl* document = m_part->xmlDocImpl();
737     if (document->hasDashboardRegions()) {
738         QValueList<DashboardRegionValue> newRegions = document->renderer()->computeDashboardRegions();
739         QValueList<DashboardRegionValue> currentRegions = document->dashboardRegions();
740         if (!(newRegions == currentRegions)) {
741             document->setDashboardRegions(newRegions);
742             KWQ(m_part)->dashboardRegionsChanged();
743         }
744     }
745 }
746 #endif
747
748 //
749 // Event Handling
750 //
751 /////////////////
752
753 void KHTMLView::viewportMousePressEvent( QMouseEvent *_mouse )
754 {
755     if(!m_part->xmlDocImpl()) return;
756
757     SharedPtr<KHTMLView> protector(this);
758
759     int xm, ym;
760     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
761
762     //kdDebug( 6000 ) << "\nmousePressEvent: x=" << xm << ", y=" << ym << endl;
763
764     d->isDoubleClick = false;
765     d->mousePressed = true;
766
767     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress );
768     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
769
770 #if !APPLE_CHANGES
771     if (d->clickCount > 0 &&
772         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
773         d->clickCount++;
774     else {
775         d->clickCount = 1;
776         d->clickX = xm;
777         d->clickY = ym;
778     }
779 #else
780     if (KWQ(m_part)->passSubframeEventToSubframe(mev)) {
781         invalidateClick();
782         return;
783     }
784
785     d->clickCount = _mouse->clickCount();
786     if (d->clickNode)
787         d->clickNode->deref();
788     d->clickNode = mev.innerNode.handle();
789     if (d->clickNode)
790         d->clickNode->ref();
791 #endif    
792
793     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true,
794                                            d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
795
796     if (!swallowEvent) {
797         khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
798         QApplication::sendEvent( m_part, &event );
799 #if APPLE_CHANGES
800         // Many AK widgets run their own event loops and consume events while the mouse is down.
801         // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
802         // the khtml state with this mouseUp, which khtml never saw.
803         // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
804         // is a hole here if the widget consumes the mouseUp and subsequent events.
805         if (KWQ(m_part)->lastEventIsMouseUp()) {
806             d->mousePressed = false;
807         }
808 #endif        
809         emit m_part->nodeActivated(mev.innerNode);
810     }
811 }
812
813 void KHTMLView::viewportMouseDoubleClickEvent( QMouseEvent *_mouse )
814 {
815     if(!m_part->xmlDocImpl()) return;
816
817     SharedPtr<KHTMLView> protector(this);
818
819     int xm, ym;
820     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
821
822     //kdDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl;
823
824     d->isDoubleClick = true;
825 #if APPLE_CHANGES
826     // We get this instead of a second mouse-up 
827     d->mousePressed = false;
828 #endif
829
830     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick );
831     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
832
833 #if APPLE_CHANGES
834     if (KWQ(m_part)->passSubframeEventToSubframe(mev))
835         return;
836
837     d->clickCount = _mouse->clickCount();
838     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),true,
839                                            d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
840
841     if (mev.innerNode.handle() == d->clickNode)
842         dispatchMouseEvent(EventImpl::CLICK_EVENT,mev.innerNode.handle(),true,
843                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseRelease);
844
845     // Qt delivers a release event AND a double click event.
846     if (!swallowEvent) {
847         khtml::MouseReleaseEvent event1( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
848         QApplication::sendEvent( m_part, &event1 );
849
850         khtml::MouseDoubleClickEvent event2( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
851         QApplication::sendEvent( m_part, &event2 );
852     }
853 #else
854     // We do the same thing as viewportMousePressEvent() here, since the DOM does not treat
855     // single and double-click events as separate (only the detail, i.e. number of clicks differs)
856     // In other words an even detail value for a mouse click event means a double click, and an
857     // odd detail value means a single click
858     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true,
859                                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
860
861     if (!swallowEvent) {
862         khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
863         QApplication::sendEvent( m_part, &event );
864
865         // ###
866         //if ( url.length() )
867         //emit doubleClick( url.string(), _mouse->button() );
868     }
869 #endif    
870
871     invalidateClick();
872 }
873
874 static bool isSubmitImage(DOM::NodeImpl *node)
875 {
876     return node
877         && node->isHTMLElement()
878         && node->id() == ID_INPUT
879         && static_cast<HTMLInputElementImpl*>(node)->inputType() == HTMLInputElementImpl::IMAGE;
880 }
881
882 void KHTMLView::viewportMouseMoveEvent( QMouseEvent * _mouse )
883 {
884     // in Radar 3703768 we saw frequent crashes apparently due to the
885     // part being null here, which seems impossible, so check for nil
886     // but also assert so that we can try to figure this out in debug
887     // builds, if it happens.
888     assert(m_part);
889     if(!m_part || !m_part->xmlDocImpl()) return;
890
891     int xm, ym;
892     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
893
894     // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent.
895     // This means that :hover and :active freeze in the state they were in when the mouse
896     // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
897     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove );
898     m_part->xmlDocImpl()->prepareMouseEvent( d->mousePressed, xm, ym, &mev );
899 #if APPLE_CHANGES
900     if (KWQ(m_part)->passSubframeEventToSubframe(mev))
901         return;
902 #endif
903
904     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),false,
905                                            0,_mouse,true,DOM::NodeImpl::MouseMove);
906
907 #if !APPLE_CHANGES
908     if (d->clickCount > 0 &&
909         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
910         d->clickCount = 0;  // moving the mouse outside the threshold invalidates the click
911     }
912 #endif
913
914     // execute the scheduled script. This is to make sure the mouseover events come after the mouseout events
915     m_part->executeScheduledScript();
916
917     NodeImpl *node = mev.innerNode.handle();
918     RenderObject *renderer = node ? node->renderer() : 0;
919     RenderStyle *style = renderer ? renderer->style() : 0;
920
921     QCursor c;
922     if (style && style->cursor() == CURSOR_AUTO && style->cursorImage()
923         && !(style->cursorImage()->pixmap().isNull())) {
924         /* First of all it works: Check out http://www.iam.unibe.ch/~schlpbch/cursor.html
925          *
926          * But, I don't know what exactly we have to do here: rescale to 32*32, change to monochrome..
927          */
928         //kdDebug( 6000 ) << "using custom cursor" << endl;
929         const QPixmap p = style->cursorImage()->pixmap();
930         // ### fix
931         c = QCursor(p);
932     }
933
934     switch ( style ? style->cursor() : CURSOR_AUTO ) {
935     case CURSOR_AUTO:
936         if ( d->mousePressed && m_part->hasSelection() )
937             // during selection, use an IBeam no matter what we're over
938             c = KCursor::ibeamCursor();
939         else if ( (!mev.url.isNull() || isSubmitImage(node)) && m_part->settings()->changeCursor() )
940             c = m_part->urlCursor();
941         else if ( (node && node->isContentEditable()) || (renderer && renderer->isText() && renderer->canSelect()) )
942             c = KCursor::ibeamCursor();
943         break;
944     case CURSOR_CROSS:
945         c = KCursor::crossCursor();
946         break;
947     case CURSOR_POINTER:
948         c = m_part->urlCursor();
949         break;
950     case CURSOR_MOVE:
951         c = KCursor::sizeAllCursor();
952         break;
953     case CURSOR_E_RESIZE:
954 #if APPLE_CHANGES
955         c = KCursor::eastResizeCursor();
956         break;
957 #endif
958     case CURSOR_W_RESIZE:
959 #if APPLE_CHANGES
960         c = KCursor::westResizeCursor();
961 #else
962         c = KCursor::sizeHorCursor();
963 #endif
964         break;
965     case CURSOR_N_RESIZE:
966 #if APPLE_CHANGES
967         c = KCursor::northResizeCursor();
968         break;
969 #endif
970     case CURSOR_S_RESIZE:
971 #if APPLE_CHANGES
972         c = KCursor::southResizeCursor();
973 #else
974         c = KCursor::sizeVerCursor();
975 #endif
976         break;
977     case CURSOR_NE_RESIZE:
978 #if APPLE_CHANGES
979         c = KCursor::northEastResizeCursor();
980         break;
981 #endif
982     case CURSOR_SW_RESIZE:
983 #if APPLE_CHANGES
984         c = KCursor::southWestResizeCursor();
985 #else
986         c = KCursor::sizeBDiagCursor();
987 #endif
988         break;
989     case CURSOR_NW_RESIZE:
990 #if APPLE_CHANGES
991         c = KCursor::northWestResizeCursor();
992         break;
993 #endif
994     case CURSOR_SE_RESIZE:
995 #if APPLE_CHANGES
996         c = KCursor::southEastResizeCursor();
997 #else
998         c = KCursor::sizeFDiagCursor();
999 #endif
1000         break;
1001     case CURSOR_TEXT:
1002         c = KCursor::ibeamCursor();
1003         break;
1004     case CURSOR_WAIT:
1005         c = KCursor::waitCursor();
1006         break;
1007     case CURSOR_HELP:
1008         c = KCursor::whatsThisCursor();
1009         break;
1010     case CURSOR_DEFAULT:
1011         break;
1012     }
1013
1014     QWidget *vp = viewport();
1015     if ( vp->cursor().handle() != c.handle() ) {
1016         if( c.handle() == KCursor::arrowCursor().handle())
1017             vp->unsetCursor();
1018         else
1019             vp->setCursor( c );
1020     }
1021     d->prevMouseX = xm;
1022     d->prevMouseY = ym;
1023
1024     if (!swallowEvent) {
1025         khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1026         QApplication::sendEvent( m_part, &event );
1027     }
1028 }
1029
1030 void KHTMLView::resetCursor()
1031 {
1032     viewport()->unsetCursor();
1033 }
1034
1035 void KHTMLView::invalidateClick()
1036 {
1037     d->clickCount = 0;
1038     if (d->clickNode) {
1039         d->clickNode->deref();
1040         d->clickNode = 0;
1041     }
1042 }
1043
1044 void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse )
1045 {
1046     if ( !m_part->xmlDocImpl() ) return;
1047
1048     SharedPtr<KHTMLView> protector(this);
1049
1050     int xm, ym;
1051     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
1052
1053     d->mousePressed = false;
1054
1055     //kdDebug( 6000 ) << "\nmouseReleaseEvent: x=" << xm << ", y=" << ym << endl;
1056
1057     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease );
1058     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
1059
1060 #if APPLE_CHANGES
1061     if (KWQ(m_part)->passSubframeEventToSubframe(mev))
1062         return;
1063 #endif
1064
1065     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),true,
1066                                            d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
1067
1068     if (d->clickCount > 0 && mev.innerNode.handle() == d->clickNode
1069 #if !APPLE_CHANGES
1070             && QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()
1071 #endif
1072         )
1073         dispatchMouseEvent(EventImpl::CLICK_EVENT,mev.innerNode.handle(),true,
1074                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseRelease);
1075
1076     if (!swallowEvent) {
1077         khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1078         QApplication::sendEvent( m_part, &event );
1079     }
1080
1081     invalidateClick();
1082 }
1083
1084 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
1085 {
1086     if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()) {
1087         if (m_part->xmlDocImpl()->focusNode()->dispatchKeyEvent(_ke))
1088         {
1089             _ke->accept();
1090             return;
1091         }
1092     }
1093
1094 #if !APPLE_CHANGES
1095     int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
1096     if (_ke->state()&ShiftButton)
1097       switch(_ke->key())
1098         {
1099         case Key_Space:
1100             if ( d->vmode == QScrollView::AlwaysOff )
1101                 _ke->accept();
1102             else
1103                 scrollBy( 0, -clipper()->height() - offs );
1104             break;
1105         }
1106     else
1107         switch ( _ke->key() )
1108         {
1109         case Key_Down:
1110         case Key_J:
1111             if ( d->vmode == QScrollView::AlwaysOff )
1112                 _ke->accept();
1113             else
1114                 scrollBy( 0, 10 );
1115             break;
1116
1117         case Key_Space:
1118         case Key_Next:
1119             if ( d->vmode == QScrollView::AlwaysOff )
1120                 _ke->accept();
1121             else
1122                 scrollBy( 0, clipper()->height() - offs );
1123             break;
1124
1125         case Key_Up:
1126         case Key_K:
1127             if ( d->vmode == QScrollView::AlwaysOff )
1128                 _ke->accept();
1129             else
1130                 scrollBy( 0, -10 );
1131             break;
1132
1133         case Key_Prior:
1134             if ( d->vmode == QScrollView::AlwaysOff )
1135                 _ke->accept();
1136             else
1137                 scrollBy( 0, -clipper()->height() + offs );
1138             break;
1139         case Key_Right:
1140         case Key_L:
1141             if ( d->hmode == QScrollView::AlwaysOff )
1142                 _ke->accept();
1143             else
1144                 scrollBy( 10, 0 );
1145             break;
1146         case Key_Left:
1147         case Key_H:
1148             if ( d->hmode == QScrollView::AlwaysOff )
1149                 _ke->accept();
1150             else
1151                 scrollBy( -10, 0 );
1152             break;
1153         case Key_Enter:
1154         case Key_Return:
1155             // ### FIXME:
1156             // or even better to HTMLAnchorElementImpl::event()
1157             if (m_part->xmlDocImpl()) {
1158                 NodeImpl *n = m_part->xmlDocImpl()->focusNode();
1159                 if (n)
1160                     n->setActive();
1161             }
1162             break;
1163         case Key_Home:
1164             if ( d->vmode == QScrollView::AlwaysOff )
1165                 _ke->accept();
1166             else
1167                 setContentsPos( 0, 0 );
1168             break;
1169         case Key_End:
1170             if ( d->vmode == QScrollView::AlwaysOff )
1171                 _ke->accept();
1172             else
1173                 setContentsPos( 0, contentsHeight() - visibleHeight() );
1174             break;
1175         default:
1176             _ke->ignore();
1177             return;
1178         }
1179     _ke->accept();
1180 #endif
1181 }
1182
1183 void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
1184 {
1185     if(m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()) {
1186         // Qt is damn buggy. we receive release events from our child
1187         // widgets. therefore, do not support keyrelease event on generic
1188         // nodes for now until we found  a workaround for the Qt bugs. (Dirk)
1189 //         if (m_part->xmlDocImpl()->focusNode()->dispatchKeyEvent(_ke)) {
1190 //             _ke->accept();
1191 //             return;
1192 //         }
1193 //        QScrollView::keyReleaseEvent(_ke);
1194         Q_UNUSED(_ke);
1195     }
1196 }
1197
1198 void KHTMLView::contentsContextMenuEvent ( QContextMenuEvent *_ce )
1199 {
1200 // ### what kind of c*** is that ?
1201 #if 0
1202     if (!m_part->xmlDocImpl()) return;
1203     int xm = _ce->x();
1204     int ym = _ce->y();
1205
1206     DOM::NodeImpl::MouseEvent mev( _ce->state(), DOM::NodeImpl::MouseMove ); // ### not a mouse event!
1207     m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, &mev );
1208
1209     NodeImpl *targetNode = mev.innerNode.handle();
1210     if (targetNode && targetNode->renderer() && targetNode->renderer()->isWidget()) {
1211         int absx = 0;
1212         int absy = 0;
1213         targetNode->renderer()->absolutePosition(absx,absy);
1214         QPoint pos(xm-absx,ym-absy);
1215
1216         QWidget *w = static_cast<RenderWidget*>(targetNode->renderer())->widget();
1217         QContextMenuEvent cme(_ce->reason(),pos,_ce->globalPos(),_ce->state());
1218         setIgnoreEvents(true);
1219         QApplication::sendEvent(w,&cme);
1220         setIgnoreEvents(false);
1221     }
1222 #endif
1223 }
1224
1225 bool KHTMLView::dispatchDragEvent(int eventId, DOM::NodeImpl *dragTarget, const QPoint &loc, DOM::ClipboardImpl *clipboard)
1226 {
1227     int clientX, clientY;
1228     viewportToContents(loc.x(), loc.y(), clientX, clientY);
1229 #if APPLE_CHANGES
1230     QPoint screenLoc = viewportToGlobal(loc);
1231     int screenX = screenLoc.x();
1232     int screenY = screenLoc.y();
1233 #else
1234 #warning Need implementation of converting event location to screen location
1235     int screenX = loc.x();
1236     int screenY = loc.y();
1237 #endif
1238     bool ctrlKey = 0;   // FIXME - set up modifiers, grab from AK or CG
1239     bool altKey = 0;
1240     bool shiftKey = 0;
1241     bool metaKey = 0;
1242     
1243     MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
1244                                             true, true, m_part->xmlDocImpl()->defaultView(),
1245                                             0, screenX, screenY, clientX, clientY,
1246                                             ctrlKey, altKey, shiftKey, metaKey,
1247                                             0, 0, clipboard);
1248     me->ref();
1249     int exceptioncode = 0;
1250     dragTarget->dispatchEvent(me, exceptioncode, true);
1251     bool accept = me->defaultPrevented();
1252     me->deref();
1253     return accept;
1254 }
1255
1256 bool KHTMLView::updateDragAndDrop(const QPoint &loc, DOM::ClipboardImpl *clipboard)
1257 {
1258     bool accept = false;
1259     int xm, ym;
1260     viewportToContents(loc.x(), loc.y(), xm, ym);
1261     DOM::NodeImpl::MouseEvent mev(0, DOM::NodeImpl::MouseMove);
1262     m_part->xmlDocImpl()->prepareMouseEvent(true, xm, ym, &mev);
1263     DOM::Node newTarget = mev.innerNode;
1264
1265     // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1266     if (newTarget.nodeType() == Node::TEXT_NODE) {
1267         newTarget = newTarget.parentNode();
1268     }
1269
1270     if (d->dragTarget != newTarget) {
1271         // note this ordering is explicitly chosen to match WinIE
1272         if (!newTarget.isNull()) {
1273             accept = dispatchDragEvent(EventImpl::DRAGENTER_EVENT, newTarget.handle(), loc, clipboard);
1274         }
1275         if (!d->dragTarget.isNull()) {
1276             dispatchDragEvent(EventImpl::DRAGLEAVE_EVENT, d->dragTarget.handle(), loc, clipboard);
1277         }
1278     } else if (!newTarget.isNull()) {
1279         accept = dispatchDragEvent(EventImpl::DRAGOVER_EVENT, newTarget.handle(), loc, clipboard);
1280     }
1281     d->dragTarget = newTarget;
1282
1283     return accept;
1284 }
1285
1286 void KHTMLView::cancelDragAndDrop(const QPoint &loc, DOM::ClipboardImpl *clipboard)
1287 {
1288     if (!d->dragTarget.isNull()) {
1289         dispatchDragEvent(EventImpl::DRAGLEAVE_EVENT, d->dragTarget.handle(), loc, clipboard);
1290     }
1291     d->dragTarget = 0;
1292 }
1293
1294 bool KHTMLView::performDragAndDrop(const QPoint &loc, DOM::ClipboardImpl *clipboard)
1295 {
1296     bool accept = false;
1297     if (!d->dragTarget.isNull()) {
1298         accept = dispatchDragEvent(EventImpl::DROP_EVENT, d->dragTarget.handle(), loc, clipboard);
1299     }
1300     d->dragTarget = 0;
1301     return accept;
1302 }
1303
1304 #if !APPLE_CHANGES
1305
1306 bool KHTMLView::focusNextPrevChild( bool next )
1307 {
1308     // Now try to find the next child
1309     if (m_part->xmlDocImpl()) {
1310         focusNextPrevNode(next);
1311         if (m_part->xmlDocImpl()->focusNode() != 0)
1312             return true; // focus node found
1313     }
1314
1315     // If we get here, there is no next/previous child to go to, so pass up to the next/previous child in our parent
1316     if (m_part->parentPart() && m_part->parentPart()->view()) {
1317         return m_part->parentPart()->view()->focusNextPrevChild(next);
1318     }
1319
1320     return QWidget::focusNextPrevChild(next);
1321 }
1322
1323 void KHTMLView::doAutoScroll()
1324 {
1325     QPoint pos = QCursor::pos();
1326     pos = viewport()->mapFromGlobal( pos );
1327
1328     int xm, ym;
1329     viewportToContents(pos.x(), pos.y(), xm, ym);
1330
1331     pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
1332     if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
1333          (pos.x() < 0) || (pos.x() > visibleWidth()) )
1334     {
1335         ensureVisible( xm, ym, 0, 5 );
1336     }
1337 }
1338
1339 #endif
1340
1341 DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
1342 {
1343     return d->underMouse;
1344 }
1345
1346 bool KHTMLView::scrollTo(const QRect &bounds)
1347 {
1348     d->scrollingSelf = true; // so scroll events get ignored
1349
1350     int x, y, xe, ye;
1351     x = bounds.left();
1352     y = bounds.top();
1353     xe = bounds.right();
1354     ye = bounds.bottom();
1355
1356     //kdDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y<<endl;
1357
1358     int deltax;
1359     int deltay;
1360
1361     int curHeight = visibleHeight();
1362     int curWidth = visibleWidth();
1363
1364     if (ye-y>curHeight-d->borderY)
1365         ye  = y + curHeight - d->borderY;
1366
1367     if (xe-x>curWidth-d->borderX)
1368         xe = x + curWidth - d->borderX;
1369
1370     // is xpos of target left of the view's border?
1371     if (x < contentsX() + d->borderX )
1372             deltax = x - contentsX() - d->borderX;
1373     // is xpos of target right of the view's right border?
1374     else if (xe + d->borderX > contentsX() + curWidth)
1375             deltax = xe + d->borderX - ( contentsX() + curWidth );
1376     else
1377         deltax = 0;
1378
1379     // is ypos of target above upper border?
1380     if (y < contentsY() + d->borderY)
1381             deltay = y - contentsY() - d->borderY;
1382     // is ypos of target below lower border?
1383     else if (ye + d->borderY > contentsY() + curHeight)
1384             deltay = ye + d->borderY - ( contentsY() + curHeight );
1385     else
1386         deltay = 0;
1387
1388     int maxx = curWidth-d->borderX;
1389     int maxy = curHeight-d->borderY;
1390
1391     int scrollX,scrollY;
1392
1393     scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
1394     scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
1395
1396     if (contentsX() + scrollX < 0)
1397         scrollX = -contentsX();
1398     else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
1399         scrollX = contentsWidth() - visibleWidth() - contentsX();
1400
1401     if (contentsY() + scrollY < 0)
1402         scrollY = -contentsY();
1403     else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
1404         scrollY = contentsHeight() - visibleHeight() - contentsY();
1405
1406     scrollBy(scrollX, scrollY);
1407
1408
1409
1410     // generate abs(scroll.)
1411     if (scrollX<0)
1412         scrollX=-scrollX;
1413     if (scrollY<0)
1414         scrollY=-scrollY;
1415
1416     d->scrollingSelf = false;
1417
1418     if ( (scrollX!=maxx) && (scrollY!=maxy) )
1419         return true;
1420     else return false;
1421
1422 }
1423
1424 void KHTMLView::focusNextPrevNode(bool next)
1425 {
1426     // Sets the focus node of the document to be the node after (or if next is false, before) the current focus node.
1427     // Only nodes that are selectable (i.e. for which isSelectable() returns true) are taken into account, and the order
1428     // used is that specified in the HTML spec (see DocumentImpl::nextFocusNode() and DocumentImpl::previousFocusNode()
1429     // for details).
1430
1431     DocumentImpl *doc = m_part->xmlDocImpl();
1432     NodeImpl *oldFocusNode = doc->focusNode();
1433     NodeImpl *newFocusNode;
1434
1435     // Find the next/previous node from the current one
1436     if (next)
1437         newFocusNode = doc->nextFocusNode(oldFocusNode);
1438     else
1439         newFocusNode = doc->previousFocusNode(oldFocusNode);
1440
1441     // If there was previously no focus node and the user has scrolled the document, then instead of picking the first
1442     // focusable node in the document, use the first one that lies within the visible area (if possible).
1443     if (!oldFocusNode && newFocusNode && d->scrollBarMoved) {
1444
1445       kdDebug(6000) << " searching for visible link" << endl;
1446
1447         bool visible = false;
1448         NodeImpl *toFocus = newFocusNode;
1449         while (!visible && toFocus) {
1450             QRect focusNodeRect = toFocus->getRect();
1451             if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
1452                 (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
1453                 // toFocus is visible in the contents area
1454                 visible = true;
1455             }
1456             else {
1457                 // toFocus is _not_ visible in the contents area, pick the next node
1458                 if (next)
1459                     toFocus = doc->nextFocusNode(toFocus);
1460                 else
1461                     toFocus = doc->previousFocusNode(toFocus);
1462             }
1463         }
1464
1465         if (toFocus)
1466             newFocusNode = toFocus;
1467     }
1468
1469     d->scrollBarMoved = false;
1470
1471     if (!newFocusNode)
1472       {
1473         // No new focus node, scroll to bottom or top depending on next
1474         if (next)
1475             scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight(),0,0));
1476         else
1477             scrollTo(QRect(contentsX()+visibleWidth()/2,0,0,0));
1478     }
1479     else {
1480         // EDIT FIXME: if it's an editable element, activate the caret
1481         // otherwise, hide it
1482         if (newFocusNode->isContentEditable()) {
1483             // make caret visible
1484         } 
1485         else {
1486             // hide caret
1487         }
1488
1489         // Scroll the view as necessary to ensure that the new focus node is visible
1490         if (oldFocusNode) {
1491             if (!scrollTo(newFocusNode->getRect()))
1492                 return;
1493         }
1494         else {
1495             ensureVisible(contentsX(), next ? 0: contentsHeight());
1496         }
1497     }
1498     // Set focus node on the document
1499     m_part->xmlDocImpl()->setFocusNode(newFocusNode);
1500     emit m_part->nodeActivated(Node(newFocusNode));
1501
1502 #if 0
1503     if (newFocusNode) {
1504
1505         // this does not belong here. it should run a query on the tree (Dirk)
1506         // I'll fix this very particular part of the code soon when I cleaned
1507         // up the positioning code
1508         // If the newly focussed node is a link, notify the part
1509
1510         HTMLAnchorElementImpl *anchor = 0;
1511         if ((newFocusNode->id() == ID_A || newFocusNode->id() == ID_AREA))
1512             anchor = static_cast<HTMLAnchorElementImpl *>(newFocusNode);
1513
1514         if (anchor && !anchor->areaHref().isNull())
1515             m_part->overURL(anchor->areaHref().string(), 0);
1516         else
1517             m_part->overURL(QString(), 0);
1518     }
1519 #endif
1520 }
1521
1522 void KHTMLView::setMediaType( const QString &medium )
1523 {
1524     m_medium = medium;
1525 }
1526
1527 QString KHTMLView::mediaType() const
1528 {
1529 #if APPLE_CHANGES
1530     // See if we have an override type.
1531     QString overrideType = KWQ(m_part)->overrideMediaType();
1532     if (!overrideType.isNull())
1533         return overrideType;
1534 #endif
1535     return m_medium;
1536 }
1537
1538 #if !APPLE_CHANGES
1539
1540 void KHTMLView::print()
1541 {
1542     if(!m_part->xmlDocImpl()) return;
1543     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
1544     if(!root) return;
1545
1546     // this only works on Unix - we assume 72dpi
1547     KPrinter *printer = new KPrinter(QPrinter::PrinterResolution);
1548     printer->addDialogPage(new KHTMLPrintSettings());
1549     if(printer->setup(this)) {
1550         viewport()->setCursor( waitCursor ); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
1551         // set up KPrinter
1552         printer->setFullPage(false);
1553         printer->setCreator("KDE 3.0 HTML Library");
1554         QString docname = m_part->xmlDocImpl()->URL();
1555         if ( !docname.isEmpty() )
1556             printer->setDocName(docname);
1557
1558         QPainter *p = new QPainter;
1559         p->begin( printer );
1560         khtml::setPrintPainter( p );
1561
1562         m_part->xmlDocImpl()->setPaintDevice( printer );
1563         QString oldMediaType = mediaType();
1564         setMediaType( "print" );
1565         // We ignore margin settings for html and body when printing
1566         // and use the default margins from the print-system
1567         // (In Qt 3.0.x the default margins are hardcoded in Qt)
1568         m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("kde-khtml-printfriendly") == "true" ?
1569                                                   "* { background-image: none !important;"
1570                                                   "    background-color: white !important;"
1571                                                   "    color: black !important; }"
1572                                                   "body { margin: 0px !important; }"
1573                                                   "html { margin: 0px !important; }" :
1574                                                   "body { margin: 0px !important; }"
1575                                                   "html { margin: 0px !important; }"
1576                                                   );
1577
1578
1579         QPaintDeviceMetrics metrics( printer );
1580
1581         // this is a simple approximation... we layout the document
1582         // according to the width of the page, then just cut
1583         // pages without caring about the content. We should do better
1584         // in the future, but for the moment this is better than no
1585         // printing support
1586         kdDebug(6000) << "printing: physical page width = " << metrics.width()
1587                       << " height = " << metrics.height() << endl;
1588         root->setPrintingMode(true);
1589         root->setWidth(metrics.width());
1590
1591         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics);
1592         m_part->xmlDocImpl()->updateStyleSelector();
1593         root->setPrintImages( printer->option("kde-khtml-printimages") == "true");
1594         root->setNeedsLayoutAndMinMaxRecalc();
1595         root->layout();
1596
1597         // ok. now print the pages.
1598         kdDebug(6000) << "printing: html page width = " << root->docWidth()
1599                       << " height = " << root->docHeight() << endl;
1600         kdDebug(6000) << "printing: margins left = " << printer->margins().width()
1601                       << " top = " << printer->margins().height() << endl;
1602         kdDebug(6000) << "printing: paper width = " << metrics.width()
1603                       << " height = " << metrics.height() << endl;
1604         // if the width is too large to fit on the paper we just scale
1605         // the whole thing.
1606         int pageHeight = metrics.height();
1607         int pageWidth = metrics.width();
1608         p->setClipRect(0,0, pageWidth, pageHeight);
1609         if(root->docWidth() > metrics.width()) {
1610             double scale = ((double) metrics.width())/((double) root->docWidth());
1611 #ifndef QT_NO_TRANSFORMATIONS
1612             p->scale(scale, scale);
1613 #endif
1614             pageHeight = (int) (pageHeight/scale);
1615             pageWidth = (int) (pageWidth/scale);
1616         }
1617         kdDebug(6000) << "printing: scaled html width = " << pageWidth
1618                       << " height = " << pageHeight << endl;
1619         int top = 0;
1620         while(top < root->docHeight()) {
1621             if(top > 0) printer->newPage();
1622             root->setTruncatedAt(top+pageHeight);
1623
1624             root->print(p, 0, top, pageWidth, pageHeight, 0, 0);
1625             if (top + pageHeight >= root->docHeight())
1626                 break; // Stop if we have printed everything
1627
1628             p->translate(0, top - root->truncatedAt());
1629             top = root->truncatedAt();
1630         }
1631
1632         p->end();
1633         delete p;
1634
1635         // and now reset the layout to the usual one...
1636         root->setPrintingMode(false);
1637         khtml::setPrintPainter( 0 );
1638         setMediaType( oldMediaType );
1639         m_part->xmlDocImpl()->setPaintDevice( this );
1640         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics());
1641         m_part->xmlDocImpl()->updateStyleSelector();
1642         viewport()->unsetCursor();
1643     }
1644     delete printer;
1645 }
1646
1647 void KHTMLView::slotPaletteChanged()
1648 {
1649     if(!m_part->xmlDocImpl()) return;
1650     DOM::DocumentImpl *document = m_part->xmlDocImpl();
1651     if (!document->isHTMLDocument()) return;
1652     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
1653     if(!root) return;
1654     root->style()->resetPalette();
1655     NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
1656     if(!body) return;
1657     body->setChanged(true);
1658     body->recalcStyle( NodeImpl::Force );
1659 }
1660
1661 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
1662 {
1663     if(!m_part->xmlDocImpl()) return;
1664     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
1665     if(!root) return;
1666
1667     m_part->xmlDocImpl()->setPaintDevice(p->device());
1668     root->setPrintingMode(true);
1669     root->setWidth(rc.width());
1670
1671     p->save();
1672     p->setClipRect(rc);
1673     p->translate(rc.left(), rc.top());
1674     double scale = ((double) rc.width()/(double) root->docWidth());
1675     int height = (int) ((double) rc.height() / scale);
1676 #ifndef QT_NO_TRANSFORMATIONS
1677     p->scale(scale, scale);
1678 #endif
1679
1680     root->print(p, 0, yOff, root->docWidth(), height, 0, 0);
1681     if (more)
1682         *more = yOff + height < root->docHeight();
1683     p->restore();
1684
1685     root->setPrintingMode(false);
1686     m_part->xmlDocImpl()->setPaintDevice( this );
1687 }
1688
1689 #endif // !APPLE_CHANGES
1690
1691 void KHTMLView::useSlowRepaints()
1692 {
1693     kdDebug(0) << "slow repaints requested" << endl;
1694     d->useSlowRepaints = true;
1695     setStaticBackground(true);
1696 }
1697
1698 void KHTMLView::setScrollBarsMode ( ScrollBarMode mode )
1699 {
1700 #ifndef KHTML_NO_SCROLLBARS
1701     d->vmode = mode;
1702     d->hmode = mode;
1703     
1704 #if APPLE_CHANGES
1705     QScrollView::setScrollBarsMode(mode);
1706 #else
1707     QScrollView::setVScrollBarMode(mode);
1708     QScrollView::setHScrollBarMode(mode);
1709 #endif
1710 #else
1711     Q_UNUSED( mode );
1712 #endif
1713 }
1714
1715 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
1716 {
1717 #ifndef KHTML_NO_SCROLLBARS
1718     d->vmode = mode;
1719     QScrollView::setVScrollBarMode(mode);
1720 #else
1721     Q_UNUSED( mode );
1722 #endif
1723 }
1724
1725 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
1726 {
1727 #ifndef KHTML_NO_SCROLLBARS
1728     d->hmode = mode;
1729     QScrollView::setHScrollBarMode(mode);
1730 #else
1731     Q_UNUSED( mode );
1732 #endif
1733 }
1734
1735 void KHTMLView::restoreScrollBar ( )
1736 {
1737 #if APPLE_CHANGES
1738     suppressScrollBars(false);
1739 #else
1740     int ow = visibleWidth();
1741     QScrollView::setVScrollBarMode(d->vmode);
1742     if (visibleWidth() != ow)
1743         layout();
1744     d->prevScrollbarVisible = verticalScrollBar()->isVisible();
1745 #endif
1746 }
1747
1748 #if !APPLE_CHANGES
1749
1750 QStringList KHTMLView::formCompletionItems(const QString &name) const
1751 {
1752     if (!m_part->settings()->isFormCompletionEnabled())
1753         return QStringList();
1754     if (!d->formCompletions)
1755         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
1756     return d->formCompletions->readListEntry(name);
1757 }
1758
1759 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
1760 {
1761     if (!m_part->settings()->isFormCompletionEnabled())
1762         return;
1763     // don't store values that are all numbers or just numbers with
1764     // dashes or spaces as those are likely credit card numbers or
1765     // something similar
1766     bool cc_number(true);
1767     for (unsigned int i = 0; i < value.length(); ++i)
1768     {
1769       QChar c(value[i]);
1770       if (!c.isNumber() && c != '-' && !c.isSpace())
1771       {
1772         cc_number = false;
1773         break;
1774       }
1775     }
1776     if (cc_number)
1777       return;
1778     QStringList items = formCompletionItems(name);
1779     if (!items.contains(value))
1780         items.prepend(value);
1781     while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
1782         items.remove(items.fromLast());
1783     d->formCompletions->writeEntry(name, items);
1784 }
1785
1786 #endif
1787
1788 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode, bool cancelable,
1789                                    int detail,QMouseEvent *_mouse, bool setUnder,
1790                                    int mouseEventType)
1791 {
1792     if (d->underMouse)
1793         d->underMouse->deref();
1794     d->underMouse = targetNode;
1795     if (d->underMouse)
1796         d->underMouse->ref();
1797
1798     int exceptioncode = 0;
1799     int clientX, clientY;
1800     viewportToContents(_mouse->x(), _mouse->y(), clientX, clientY);
1801 #if APPLE_CHANGES
1802     QPoint screenLoc = viewportToGlobal(_mouse->pos());
1803     int screenX = screenLoc.x();
1804     int screenY = screenLoc.y();
1805 #else
1806     int screenX = _mouse->globalX();
1807     int screenY = _mouse->globalY();
1808 #endif
1809     int button = -1;
1810     switch (_mouse->button()) {
1811         case LeftButton:
1812             button = 0;
1813             break;
1814         case MidButton:
1815             button = 1;
1816             break;
1817         case RightButton:
1818             button = 2;
1819             break;
1820         default:
1821             break;
1822     }
1823     bool ctrlKey = (_mouse->state() & ControlButton);
1824     bool altKey = (_mouse->state() & AltButton);
1825     bool shiftKey = (_mouse->state() & ShiftButton);
1826     bool metaKey = (_mouse->state() & MetaButton);
1827
1828     // mouseout/mouseover
1829     if (setUnder && (d->prevMouseX != clientX || d->prevMouseY != clientY)) {
1830
1831         // ### this code sucks. we should save the oldUnder instead of calculating
1832         // it again. calculating is expensive! (Dirk)
1833         NodeImpl *oldUnder = 0;
1834         if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
1835             NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
1836             m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
1837             oldUnder = mev.innerNode.handle();
1838         }
1839         if (oldUnder != targetNode) {
1840             // send mouseout event to the old node
1841             if (oldUnder){
1842                 oldUnder->ref();
1843                 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
1844                                                         true,true,m_part->xmlDocImpl()->defaultView(),
1845                                                         0,screenX,screenY,clientX,clientY,
1846                                                         ctrlKey,altKey,shiftKey,metaKey,
1847                                                         button,targetNode);
1848                 oldUnder->dispatchEvent(me,exceptioncode,true);
1849             }
1850
1851             // send mouseover event to the new node
1852             if (targetNode) {
1853                 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
1854                                                         true,true,m_part->xmlDocImpl()->defaultView(),
1855                                                         0,screenX,screenY,clientX,clientY,
1856                                                         ctrlKey,altKey,shiftKey,metaKey,
1857                                                         button,oldUnder);
1858                 targetNode->dispatchEvent(me,exceptioncode,true);
1859             }
1860
1861             if (oldUnder)
1862                 oldUnder->deref();
1863         }
1864     }
1865
1866     bool swallowEvent = false;
1867
1868     if (targetNode) {
1869         // send the actual event
1870         MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
1871                                                 true,cancelable,m_part->xmlDocImpl()->defaultView(),
1872                                                 detail,screenX,screenY,clientX,clientY,
1873                                                 ctrlKey,altKey,shiftKey,metaKey,
1874                                                 button,0);
1875         me->ref();
1876         targetNode->dispatchEvent(me,exceptioncode,true);
1877         bool defaultHandled = me->defaultHandled();
1878         if (me->defaultHandled() || me->defaultPrevented())
1879             swallowEvent = true;
1880         me->deref();
1881
1882         // Special case: If it's a click event, we also send the KHTML_CLICK or KHTML_DBLCLICK event. This is not part
1883         // of the DOM specs, but is used for compatibility with the traditional onclick="" and ondblclick="" attributes,
1884         // as there is no way to tell the difference between single & double clicks using DOM (only the click count is
1885         // stored, which is not necessarily the same)
1886         if (eventId == EventImpl::CLICK_EVENT) {
1887             me = new MouseEventImpl(d->isDoubleClick ? EventImpl::KHTML_DBLCLICK_EVENT : EventImpl::KHTML_CLICK_EVENT,
1888                                     true,cancelable,m_part->xmlDocImpl()->defaultView(),
1889                                     detail,screenX,screenY,clientX,clientY,
1890                                     ctrlKey,altKey,shiftKey,metaKey,
1891                                     button,0);
1892
1893             me->ref();
1894             if (defaultHandled)
1895                 me->setDefaultHandled();
1896             targetNode->dispatchEvent(me,exceptioncode,true);
1897             if (me->defaultHandled() || me->defaultPrevented())
1898                 swallowEvent = true;
1899             me->deref();
1900         }
1901         else if (eventId == EventImpl::MOUSEDOWN_EVENT) {
1902             // Focus should be shifted on mouse down, not on a click.  -dwh
1903             // Blur current focus node when a link/button is clicked; this
1904             // is expected by some sites that rely on onChange handlers running
1905             // from form fields before the button click is processed.
1906             DOM::NodeImpl* nodeImpl = targetNode;
1907             for ( ; nodeImpl && !nodeImpl->isFocusable(); nodeImpl = nodeImpl->parentNode());
1908             // If focus shift is blocked, we eat the event.  Note we should never clear swallowEvent
1909             // if the page already set it (e.g., by canceling default behavior).
1910             if (nodeImpl && nodeImpl->isMouseFocusable())
1911                 swallowEvent |= !m_part->xmlDocImpl()->setFocusNode(nodeImpl);
1912             else if (!nodeImpl || !nodeImpl->focused())
1913                 swallowEvent |= !m_part->xmlDocImpl()->setFocusNode(0);
1914         }
1915     }
1916
1917     return swallowEvent;
1918 }
1919
1920 void KHTMLView::setIgnoreWheelEvents( bool e )
1921 {
1922     d->ignoreWheelEvents = e;
1923 }
1924
1925 #ifndef QT_NO_WHEELEVENT
1926
1927 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
1928 {
1929 #if !APPLE_CHANGES
1930     if ( d->ignoreWheelEvents && !verticalScrollBar()->isVisible() && m_part->parentPart() ) {
1931         if ( m_part->parentPart()->view() )
1932             m_part->parentPart()->view()->wheelEvent( e );
1933         e->ignore();
1934     }
1935     else if ( d->vmode == QScrollView::AlwaysOff ) {
1936         e->accept();
1937     }
1938     else {
1939         d->scrollBarMoved = true;
1940         QScrollView::viewportWheelEvent( e );
1941     }
1942 #endif
1943 }
1944 #endif
1945
1946 #if !APPLE_CHANGES
1947 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
1948 {
1949     // Handle drops onto frames (#16820)
1950     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
1951     // in e.g. kmail, so not handled here).
1952     if ( m_part->parentPart() )
1953     {
1954         // Duplicated from KonqView::eventFilter
1955         if ( QUriDrag::canDecode( ev ) )
1956         {
1957             KURL::List lstDragURLs;
1958             bool ok = KURLDrag::decode( ev, lstDragURLs );
1959             QObjectList *children = this->queryList( "QWidget" );
1960
1961             if ( ok &&
1962                  !lstDragURLs.first().url().contains( "javascript:", false ) && // ### this looks like a hack to me
1963                  ev->source() != this &&
1964                  children &&
1965                  children->findRef( ev->source() ) == -1 )
1966                 ev->acceptAction();
1967
1968             delete children;
1969         }
1970     }
1971     QScrollView::dragEnterEvent( ev );
1972 }
1973
1974 void KHTMLView::dropEvent( QDropEvent *ev )
1975 {
1976     // Handle drops onto frames (#16820)
1977     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
1978     // in e.g. kmail, so not handled here).
1979     if ( m_part->parentPart() )
1980     {
1981         KURL::List lstDragURLs;
1982         bool ok = KURLDrag::decode( ev, lstDragURLs );
1983
1984         KHTMLPart* part = m_part->parentPart();
1985         while ( part && part->parentPart() )
1986             part = part->parentPart();
1987         KParts::BrowserExtension *ext = part->browserExtension();
1988         if ( ok && ext && lstDragURLs.first().isValid() )
1989             emit ext->openURLRequest( lstDragURLs.first() );
1990     }
1991     QScrollView::dropEvent( ev );
1992 }
1993 #endif // !APPLE_CHANGES
1994
1995 void KHTMLView::focusInEvent( QFocusEvent *e )
1996 {
1997     m_part->setCaretVisible();
1998     QScrollView::focusInEvent( e );
1999 }
2000
2001 void KHTMLView::focusOutEvent( QFocusEvent *e )
2002 {
2003     m_part->stopAutoScroll();
2004     m_part->setCaretVisible(false);
2005     QScrollView::focusOutEvent( e );
2006 }
2007
2008 void KHTMLView::slotScrollBarMoved()
2009 {
2010     if (!d->scrollingSelf)
2011         d->scrollBarMoved = true;
2012 }
2013
2014 void KHTMLView::repaintRectangle(const QRect& r, bool immediate)
2015 {
2016     updateContents(r, immediate);
2017 }
2018
2019 void KHTMLView::timerEvent ( QTimerEvent *e )
2020 {
2021     if (e->timerId()==d->layoutTimerId) {
2022 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2023         if (m_part->xmlDocImpl() && !m_part->xmlDocImpl()->ownerElement())
2024             printf("Layout timer fired at %d\n", m_part->xmlDocImpl()->elapsedTime());
2025 #endif
2026         layout();
2027     }
2028 }
2029
2030 void KHTMLView::scheduleRelayout()
2031 {
2032     if (!d->layoutSchedulingEnabled)
2033         return;
2034
2035     if (!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->shouldScheduleLayout())
2036         return;
2037
2038     int delay = m_part->xmlDocImpl()->minimumLayoutDelay();
2039     if (d->layoutTimerId && d->delayedLayout && !delay)
2040         unscheduleRelayout();
2041     if (d->layoutTimerId)
2042         return;
2043
2044     d->delayedLayout = delay != 0;
2045
2046 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2047     if (!m_part->xmlDocImpl()->ownerElement())
2048         printf("Scheduling layout for %d\n", delay);
2049 #endif
2050
2051     d->layoutTimerId = startTimer(delay);
2052 }
2053
2054 bool KHTMLView::layoutPending()
2055 {
2056     return d->layoutTimerId;
2057 }
2058
2059 bool KHTMLView::haveDelayedLayoutScheduled()
2060 {
2061     return d->layoutTimerId && d->delayedLayout;
2062 }
2063
2064 void KHTMLView::unscheduleRelayout()
2065 {
2066     if (!d->layoutTimerId)
2067         return;
2068
2069 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2070     if (m_part->xmlDocImpl() && !m_part->xmlDocImpl()->ownerElement())
2071         printf("Layout timer unscheduled at %d\n", m_part->xmlDocImpl()->elapsedTime());
2072 #endif
2073     
2074     killTimer(d->layoutTimerId);
2075     d->layoutTimerId = 0;
2076     d->delayedLayout = false;
2077 }
2078
2079 bool KHTMLView::isTransparent() const
2080 {
2081     return d->isTransparent;
2082 }
2083
2084 void KHTMLView::setTransparent(bool isTransparent)
2085 {
2086     d->isTransparent = isTransparent;
2087 }
2088