1 /* This file is part of the KDE project
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.
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.
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.
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.
25 #include "FrameView.h"
28 #include "SelectionController.h"
29 #include "khtml_events.h"
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"
45 #include "khtml_settings.h"
51 #include <qpaintdevicemetrics.h>
57 #include "KWQAccObjectCache.h"
59 #include "CachedImage.h"
61 // #define INSTRUMENT_LAYOUT_SCHEDULING 1
64 using namespace EventNames;
65 using namespace HTMLNames;
66 using namespace khtml;
68 class KHTMLViewPrivate {
77 delayedLayout = false;
80 isTransparent = false;
81 vmode = hmode = QScrollView::Auto;
83 needToInitScrollBars = true;
99 useSlowRepaints = false;
101 borderTouched = false;
102 scrollBarMoved = false;
103 ignoreWheelEvents = false;
112 scrollingSelf = false;
114 delayedLayout = false;
115 mousePressed = false;
116 doFullRepaint = true;
117 layoutSchedulingEnabled = true;
118 layoutSuppressed = false;
122 repaintRects->clear();
125 NodeImpl *underMouse;
127 bool borderTouched:1;
129 bool scrollBarMoved:1;
130 bool doFullRepaint:1;
132 QScrollView::ScrollBarMode vmode;
133 QScrollView::ScrollBarMode hmode;
135 bool useSlowRepaints;
136 bool ignoreWheelEvents;
138 int borderX, borderY;
142 int prevMouseX, prevMouseY;
147 bool layoutSchedulingEnabled;
148 bool layoutSuppressed;
152 bool needToInitScrollBars;
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;
160 RefPtr<NodeImpl> dragTarget;
163 KHTMLView::KHTMLView( Frame *frame, QWidget *parent, const char *name)
164 : QScrollView( parent, name, WResizeNoErase | WRepaintNoErase | WPaintUnclipped ),
171 d = new KHTMLViewPrivate;
173 connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotScrollBarMoved()));
180 KHTMLView::~KHTMLView()
184 assert(_refCount == 0);
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();
200 void KHTMLView::clearPart()
208 void KHTMLView::resetScrollBars()
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);
218 void KHTMLView::init()
221 setFocusPolicy(QWidget::StrongFocus);
222 viewport()->setFocusPolicy( QWidget::WheelFocus );
223 viewport()->setFocusProxy(this);
225 _marginWidth = -1; // undefined
231 void KHTMLView::clear()
233 // viewport()->erase();
235 setStaticBackground(false);
237 // FIXME: 6498 Should just be able to call m_frame->selection().clear()
238 m_frame->setSelection(SelectionController());
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());
250 suppressScrollBars(true);
253 void KHTMLView::resizeEvent(QResizeEvent* e)
255 if (m_frame && m_frame->xmlDocImpl())
256 m_frame->xmlDocImpl()->dispatchWindowEvent(EventNames::resizeEvent, false, false);
259 void KHTMLView::initScrollBars()
261 if (!d->needToInitScrollBars)
263 d->needToInitScrollBars = false;
264 setScrollBarsMode(hScrollBarMode());
267 void KHTMLView::setMarginWidth(int w)
269 // make it update the rendering area when set
273 void KHTMLView::setMarginHeight(int h)
275 // make it update the rendering area when set
279 void KHTMLView::adjustViewSize()
281 if( m_frame->xmlDocImpl() ) {
282 DocumentImpl *document = m_frame->xmlDocImpl();
284 RenderCanvas* root = static_cast<RenderCanvas *>(document->renderer());
288 int docw = root->docWidth();
289 int doch = root->docHeight();
291 resizeContents(docw, doch);
295 void KHTMLView::applyOverflowToViewport(RenderObject* o, ScrollBarMode& hMode, ScrollBarMode& vMode)
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()) {
303 hMode = vMode = AlwaysOff;
306 hMode = vMode = AlwaysOn;
309 hMode = vMode = Auto;
312 // Don't set it at all.
317 bool KHTMLView::inLayout() const
319 return d->layoutSuppressed;
322 int KHTMLView::layoutCount() const
324 return d->layoutCount;
327 bool KHTMLView::needsFullRepaint() const
329 return d->doFullRepaint;
332 void KHTMLView::addRepaintInfo(RenderObject* o, const IntRect& r)
334 if (!d->repaintRects) {
335 d->repaintRects = new QPtrList<RenderObject::RepaintInfo>;
336 d->repaintRects->setAutoDelete(true);
339 d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
342 void KHTMLView::layout()
344 if (d->layoutSuppressed)
347 killTimer(d->layoutTimerId);
348 d->layoutTimerId = 0;
349 d->delayedLayout = false;
352 // FIXME: Do we need to set _width here?
353 // FIXME: Should we set _height here too?
354 _width = visibleWidth();
358 DocumentImpl* document = m_frame->xmlDocImpl();
360 // FIXME: Should we set _height here too?
361 _width = visibleWidth();
365 d->layoutSchedulingEnabled = false;
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();
372 RenderCanvas* root = static_cast<RenderCanvas*>(document->renderer());
374 // FIXME: Do we need to set _width or _height here?
375 d->layoutSchedulingEnabled = true;
379 ScrollBarMode hMode = d->hmode;
380 ScrollBarMode vMode = d->vmode;
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);
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
397 else if (rootRenderer)
398 applyOverflowToViewport(rootRenderer, hMode, vMode); // XML/XHTML UAs use the root element.
400 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
401 if (d->firstLayout && !document->ownerElement())
402 printf("Elapsed time before first layout: %d\n", document->elapsedTime());
405 d->doFullRepaint = d->firstLayout || root->printingMode();
407 d->repaintRects->clear();
409 // Now set our scrollbar state for the layout.
410 ScrollBarMode currentHMode = hScrollBarMode();
411 ScrollBarMode currentVMode = vScrollBarMode();
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;
420 // Set the initial vMode to AlwaysOn if we're auto.
422 QScrollView::setVScrollBarMode(AlwaysOn); // This causes a vertical scrollbar to appear.
423 // Set the initial hMode to AlwaysOff if we're auto.
425 QScrollView::setHScrollBarMode(AlwaysOff); // This causes a horizontal scrollbar to disappear.
429 QScrollView::setScrollBarsMode(hMode);
431 QScrollView::setHScrollBarMode(hMode);
432 QScrollView::setVScrollBarMode(vMode);
435 suppressScrollBars(false, true);
438 int oldHeight = _height;
439 int oldWidth = _width;
441 _height = visibleHeight();
442 _width = visibleWidth();
444 if (oldHeight != _height || oldWidth != _width)
445 d->doFullRepaint = true;
447 RenderLayer* layer = root->layer();
449 if (!d->doFullRepaint) {
450 layer->computeRepaintRects();
451 root->repaintObjectsBeforeLayout();
456 m_frame->invalidateSelection();
458 d->layoutSchedulingEnabled=true;
459 d->layoutSuppressed = false;
461 if (!root->printingMode())
462 resizeContents(layer->width(), layer->height());
464 // Now update the positions of all layers.
465 layer->updateLayerPositions(d->doFullRepaint);
467 // We update our widget positions right after doing a layout.
468 root->updateWidgetPositions();
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();
482 if (KWQAccObjectCache::accessibilityEnabled())
483 root->document()->getAccObjectCache()->postNotification(root, "AXLayoutComplete");
485 updateDashboardRegions();
488 if (root->needsLayout()) {
489 //qDebug("needs layout, delaying repaint");
493 setStaticBackground(d->useSlowRepaints);
495 if (didFirstLayout) {
496 m_frame->didFirstLayout();
501 void KHTMLView::updateDashboardRegions()
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 Mac(m_frame)->dashboardRegionsChanged();
518 void KHTMLView::viewportMousePressEvent( QMouseEvent *_mouse )
520 if(!m_frame->xmlDocImpl()) return;
522 RefPtr<KHTMLView> protector(this);
525 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
527 d->mousePressed = true;
529 NodeImpl::MouseEvent mev( _mouse->stateAfter(), NodeImpl::MousePress );
530 m_frame->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
532 if (m_frame->passSubframeEventToSubframe(mev)) {
537 d->clickCount = _mouse->clickCount();
539 d->clickNode->deref();
540 d->clickNode = mev.innerNode.get();
544 bool swallowEvent = dispatchMouseEvent(mousedownEvent,mev.innerNode.get(),true,
545 d->clickCount,_mouse,true,NodeImpl::MousePress);
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;
561 void KHTMLView::viewportMouseDoubleClickEvent( QMouseEvent *_mouse )
563 if(!m_frame->xmlDocImpl()) return;
565 RefPtr<KHTMLView> protector(this);
568 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
570 // We get this instead of a second mouse-up
571 d->mousePressed = false;
573 NodeImpl::MouseEvent mev( _mouse->stateAfter(), NodeImpl::MouseDblClick );
574 m_frame->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
576 if (m_frame->passSubframeEventToSubframe(mev))
579 d->clickCount = _mouse->clickCount();
580 bool swallowEvent = dispatchMouseEvent(mouseupEvent,mev.innerNode.get(),true,
581 d->clickCount,_mouse,false,NodeImpl::MouseRelease);
583 if (mev.innerNode == d->clickNode)
584 dispatchMouseEvent(clickEvent,mev.innerNode.get(),true,
585 d->clickCount,_mouse,true,NodeImpl::MouseRelease);
587 // Qt delivers a release event AND a double click event.
589 MouseReleaseEvent event1( _mouse, xm, ym, mev.url, mev.target, mev.innerNode.get() );
590 QApplication::sendEvent( m_frame, &event1 );
592 MouseDoubleClickEvent event2( _mouse, xm, ym, mev.url, mev.target, mev.innerNode.get() );
593 QApplication::sendEvent( m_frame, &event2 );
599 static bool isSubmitImage(NodeImpl *node)
601 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElementImpl*>(node)->inputType() == HTMLInputElementImpl::IMAGE;
604 static QCursor selectCursor(const NodeImpl::MouseEvent &event, Frame *frame, bool mousePressed)
606 // During selection, use an I-beam no matter what we're over
607 if (mousePressed && frame->hasSelection())
608 return KCursor::ibeamCursor();
610 NodeImpl *node = event.innerNode.get();
611 RenderObject *renderer = node ? node->renderer() : 0;
612 RenderStyle *style = renderer ? renderer->style() : 0;
614 if (style && style->cursorImage() && !style->cursorImage()->pixmap().isNull())
615 return QCursor(style->cursorImage()->pixmap());
617 switch (style ? style->cursor() : 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();
625 return KCursor::crossCursor();
627 return frame->urlCursor();
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();
647 return KCursor::ibeamCursor();
649 return KCursor::waitCursor();
651 return KCursor::whatsThisCursor();
658 void KHTMLView::viewportMouseMoveEvent( QMouseEvent * _mouse )
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.
665 if(!m_frame || !m_frame->xmlDocImpl()) return;
668 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
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 );
677 if (!m_frame->passSubframeEventToSubframe(mev))
678 viewport()->setCursor(selectCursor(mev, m_frame, d->mousePressed));
680 bool swallowEvent = dispatchMouseEvent(mousemoveEvent,mev.innerNode.get(),false,
681 0,_mouse,true,NodeImpl::MouseMove);
683 // execute the scheduled script. This is to make sure the mouseover events come after the mouseout events
684 m_frame->executeScheduledScript();
690 MouseMoveEvent event(_mouse, xm, ym, mev.url, mev.target, mev.innerNode.get());
691 QApplication::sendEvent(m_frame, &event);
695 void KHTMLView::invalidateClick()
699 d->clickNode->deref();
704 void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse )
706 if ( !m_frame->xmlDocImpl() ) return;
708 RefPtr<KHTMLView> protector(this);
711 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
713 d->mousePressed = false;
715 NodeImpl::MouseEvent mev( _mouse->stateAfter(), NodeImpl::MouseRelease );
716 m_frame->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
718 if (m_frame->passSubframeEventToSubframe(mev))
721 bool swallowEvent = dispatchMouseEvent(mouseupEvent,mev.innerNode.get(),true,
722 d->clickCount,_mouse,false,NodeImpl::MouseRelease);
724 if (d->clickCount > 0 && mev.innerNode == d->clickNode
726 dispatchMouseEvent(clickEvent,mev.innerNode.get(),true,
727 d->clickCount,_mouse,true,NodeImpl::MouseRelease);
730 MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode.get() );
731 QApplication::sendEvent( m_frame, &event );
737 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
739 if (m_frame->xmlDocImpl() && m_frame->xmlDocImpl()->focusNode()) {
740 if (m_frame->xmlDocImpl()->focusNode()->dispatchKeyEvent(_ke))
749 bool KHTMLView::dispatchDragEvent(const AtomicString &eventType, NodeImpl *dragTarget, const IntPoint &loc, ClipboardImpl *clipboard)
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
761 MouseEventImpl *me = new MouseEventImpl(eventType,
762 true, true, m_frame->xmlDocImpl()->defaultView(),
763 0, screenX, screenY, clientX, clientY,
764 ctrlKey, altKey, shiftKey, metaKey,
767 int exceptioncode = 0;
768 dragTarget->dispatchEvent(me, exceptioncode, true);
769 bool accept = me->defaultPrevented();
774 bool KHTMLView::updateDragAndDrop(const IntPoint &loc, ClipboardImpl *clipboard)
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();
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();
788 if (d->dragTarget != newTarget) {
789 // note this ordering is explicitly chosen to match WinIE
791 accept = dispatchDragEvent(dragenterEvent, newTarget, loc, clipboard);
794 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), loc, clipboard);
796 } else if (newTarget) {
797 accept = dispatchDragEvent(dragoverEvent, newTarget, loc, clipboard);
799 d->dragTarget = newTarget;
804 void KHTMLView::cancelDragAndDrop(const IntPoint &loc, ClipboardImpl *clipboard)
807 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), loc, clipboard);
812 bool KHTMLView::performDragAndDrop(const IntPoint &loc, ClipboardImpl *clipboard)
816 accept = dispatchDragEvent(dropEvent, d->dragTarget.get(), loc, clipboard);
823 NodeImpl *KHTMLView::nodeUnderMouse() const
825 return d->underMouse;
828 bool KHTMLView::scrollTo(const IntRect &bounds)
830 d->scrollingSelf = true; // so scroll events get ignored
836 ye = bounds.bottom();
841 int curHeight = visibleHeight();
842 int curWidth = visibleWidth();
844 if (ye-y>curHeight-d->borderY)
845 ye = y + curHeight - d->borderY;
847 if (xe-x>curWidth-d->borderX)
848 xe = x + curWidth - d->borderX;
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 );
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 );
868 int maxx = curWidth-d->borderX;
869 int maxy = curHeight-d->borderY;
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);
876 if (contentsX() + scrollX < 0)
877 scrollX = -contentsX();
878 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
879 scrollX = contentsWidth() - visibleWidth() - contentsX();
881 if (contentsY() + scrollY < 0)
882 scrollY = -contentsY();
883 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
884 scrollY = contentsHeight() - visibleHeight() - contentsY();
886 scrollBy(scrollX, scrollY);
888 // generate abs(scroll.)
894 d->scrollingSelf = false;
896 if ( (scrollX!=maxx) && (scrollY!=maxy) )
902 void KHTMLView::focusNextPrevNode(bool next)
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()
909 DocumentImpl *doc = m_frame->xmlDocImpl();
910 NodeImpl *oldFocusNode = doc->focusNode();
911 NodeImpl *newFocusNode;
913 // Find the next/previous node from the current one
915 newFocusNode = doc->nextFocusNode(oldFocusNode);
917 newFocusNode = doc->previousFocusNode(oldFocusNode);
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
932 // toFocus is _not_ visible in the contents area, pick the next node
934 toFocus = doc->nextFocusNode(toFocus);
936 toFocus = doc->previousFocusNode(toFocus);
941 newFocusNode = toFocus;
944 d->scrollBarMoved = false;
948 // No new focus node, scroll to bottom or top depending on next
950 scrollTo(IntRect(contentsX()+visibleWidth()/2,contentsHeight(),0,0));
952 scrollTo(IntRect(contentsX()+visibleWidth()/2,0,0,0));
955 // EDIT FIXME: if it's an editable element, activate the caret
956 // otherwise, hide it
957 if (newFocusNode->isContentEditable()) {
958 // make caret visible
964 // Scroll the view as necessary to ensure that the new focus node is visible
966 if (!scrollTo(newFocusNode->getRect()))
970 if (doc->renderer()) {
971 doc->renderer()->enclosingLayer()->scrollRectToVisible(IntRect(contentsX(), next ? 0: contentsHeight(), 0, 0));
975 // Set focus node on the document
976 m_frame->xmlDocImpl()->setFocusNode(newFocusNode);
979 void KHTMLView::setMediaType( const QString &medium )
984 QString KHTMLView::mediaType() const
986 // See if we have an override type.
987 QString overrideType = m_frame->overrideMediaType();
988 if (!overrideType.isNull())
994 void KHTMLView::useSlowRepaints()
996 kdDebug(0) << "slow repaints requested" << endl;
997 d->useSlowRepaints = true;
998 setStaticBackground(true);
1001 void KHTMLView::setScrollBarsMode ( ScrollBarMode mode )
1003 #ifndef KHTML_NO_SCROLLBARS
1007 QScrollView::setScrollBarsMode(mode);
1013 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
1015 #ifndef KHTML_NO_SCROLLBARS
1017 QScrollView::setVScrollBarMode(mode);
1023 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
1025 #ifndef KHTML_NO_SCROLLBARS
1027 QScrollView::setHScrollBarMode(mode);
1033 void KHTMLView::restoreScrollBar ( )
1035 suppressScrollBars(false);
1039 bool KHTMLView::dispatchMouseEvent(const AtomicString &eventType, NodeImpl *targetNode, bool cancelable,
1040 int detail,QMouseEvent *_mouse, bool setUnder,
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();
1047 d->underMouse->deref();
1048 d->underMouse = targetNode;
1050 d->underMouse->ref();
1052 // mouseout/mouseover
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();
1069 if (oldUnder != targetNode) {
1070 // send mouseout event to the old node
1072 oldUnder->dispatchMouseEvent(_mouse, mouseoutEvent);
1073 // send mouseover event to the new node
1075 targetNode->dispatchMouseEvent(_mouse, mouseoverEvent);
1080 bool swallowEvent = false;
1083 swallowEvent = targetNode->dispatchMouseEvent(_mouse, eventType, detail);
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;
1103 return swallowEvent;
1106 void KHTMLView::setIgnoreWheelEvents( bool e )
1108 d->ignoreWheelEvents = e;
1111 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
1113 DocumentImpl *doc = m_frame->xmlDocImpl();
1115 RenderObject *docRenderer = doc->renderer();
1118 viewportToContents(e->x(), e->y(), x, y);
1120 RenderObject::NodeInfo hitTestResult(true, false);
1121 doc->renderer()->layer()->hitTest(hitTestResult, x, y);
1122 NodeImpl *node = hitTestResult.innerNode();
1124 if (m_frame->passWheelEventToChildWidget(node)) {
1129 node->dispatchWheelEvent(e);
1130 if (e->isAccepted())
1137 void KHTMLView::focusInEvent( QFocusEvent *e )
1139 m_frame->setCaretVisible();
1142 void KHTMLView::focusOutEvent( QFocusEvent *e )
1144 m_frame->setCaretVisible(false);
1147 void KHTMLView::slotScrollBarMoved()
1149 if (!d->scrollingSelf)
1150 d->scrollBarMoved = true;
1153 void KHTMLView::repaintRectangle(const IntRect& r, bool immediate)
1155 updateContents(r, immediate);
1158 void KHTMLView::timerEvent ( QTimerEvent *e )
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());
1169 void KHTMLView::scheduleRelayout()
1171 if (!d->layoutSchedulingEnabled)
1174 if (!m_frame->xmlDocImpl() || !m_frame->xmlDocImpl()->shouldScheduleLayout())
1177 int delay = m_frame->xmlDocImpl()->minimumLayoutDelay();
1178 if (d->layoutTimerId && d->delayedLayout && !delay)
1179 unscheduleRelayout();
1180 if (d->layoutTimerId)
1183 d->delayedLayout = delay != 0;
1185 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1186 if (!m_frame->xmlDocImpl()->ownerElement())
1187 printf("Scheduling layout for %d\n", delay);
1190 d->layoutTimerId = startTimer(delay);
1193 bool KHTMLView::layoutPending()
1195 return d->layoutTimerId;
1198 bool KHTMLView::haveDelayedLayoutScheduled()
1200 return d->layoutTimerId && d->delayedLayout;
1203 void KHTMLView::unscheduleRelayout()
1205 if (!d->layoutTimerId)
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());
1213 killTimer(d->layoutTimerId);
1214 d->layoutTimerId = 0;
1215 d->delayedLayout = false;
1218 bool KHTMLView::isTransparent() const
1220 return d->isTransparent;
1223 void KHTMLView::setTransparent(bool isTransparent)
1225 d->isTransparent = isTransparent;