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, 2005, 2006 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.
26 #include "FrameView.h"
28 #include "AccessibilityObjectCache.h"
29 #include "CachedImage.h"
31 #include "EventNames.h"
33 #include "HTMLDocument.h"
34 #include "HTMLFrameSetElement.h"
35 #include "HTMLInputElement.h"
36 #include "HTMLNames.h"
38 #include "MouseEvent.h"
39 #include "MouseEventWithHitTestResults.h"
40 #include "PlatformKeyboardEvent.h"
41 #include "PlatformWheelEvent.h"
42 #include "RenderArena.h"
43 #include "RenderPart.h"
44 #include "RenderText.h"
45 #include "RenderView.h"
46 #include "SelectionController.h"
47 #include "cssstyleselector.h"
51 using namespace EventNames;
52 using namespace HTMLNames;
54 class FrameViewPrivate {
56 FrameViewPrivate(FrameView* view)
58 , layoutTimer(view, &FrameView::layoutTimerFired)
59 , hoverTimer(view, &FrameView::hoverTimerFired)
61 , m_mediaType("screen")
64 isTransparent = false;
65 vmode = hmode = ScrollBarAuto;
66 needToInitScrollBars = true;
79 useSlowRepaints = false;
81 borderTouched = false;
82 scrollBarMoved = false;
83 ignoreWheelEvents = false;
88 scrollingSelf = false;
91 delayedLayout = false;
94 layoutSchedulingEnabled = true;
99 repaintRects->clear();
100 resizingFrameSet = 0;
104 RefPtr<Node> underMouse;
105 RefPtr<Node> oldUnder;
106 RefPtr<Frame> oldSubframe;
108 bool borderTouched : 1;
109 bool borderStart : 1;
110 bool scrollBarMoved : 1;
111 bool doFullRepaint : 1;
112 bool m_hasBorder : 1;
117 bool useSlowRepaints;
118 bool ignoreWheelEvents;
120 int borderX, borderY;
122 RefPtr<Node> clickNode;
125 Timer<FrameView> layoutTimer;
127 RefPtr<Node> layoutRoot;
129 bool layoutSchedulingEnabled;
133 bool needToInitScrollBars;
137 Timer<FrameView> hoverTimer;
139 RenderLayer* m_resizeLayer;
141 // Used by objects during layout to communicate repaints that need to take place only
142 // after all layout has been completed.
143 DeprecatedPtrList<RenderObject::RepaintInfo>* repaintRects;
145 RefPtr<Node> dragTarget;
146 RefPtr<HTMLFrameSetElement> resizingFrameSet;
151 FrameView::FrameView(Frame *frame)
154 , d(new FrameViewPrivate(this))
161 FrameView::~FrameView()
165 ASSERT(m_refCount == 0);
167 if (d->hoverTimer.isActive())
168 d->hoverTimer.stop();
170 // FIXME: Is this really the right place to call detach on the document?
171 if (Document* doc = m_frame->document())
173 if (RenderPart* renderer = m_frame->ownerRenderer())
174 renderer->setWidget(0);
181 void FrameView::clearPart()
186 void FrameView::resetScrollBars()
188 // Reset the document's scrollbars back to our defaults before we yield the floor.
189 d->firstLayout = true;
190 suppressScrollBars(true);
191 ScrollView::setVScrollBarMode(d->vmode);
192 ScrollView::setHScrollBarMode(d->hmode);
193 suppressScrollBars(false);
196 void FrameView::init()
198 m_margins = IntSize(-1, -1); // undefined
202 void FrameView::clear()
204 setStaticBackground(false);
206 // FIXME: 6498 Should just be able to call m_frame->selection().clear()
207 m_frame->setSelection(SelectionController());
211 #if INSTRUMENT_LAYOUT_SCHEDULING
212 if (d->layoutTimer.isActive() && m_frame->document() && !m_frame->document()->ownerElement())
213 printf("Killing the layout timer from a clear at %d\n", m_frame->document()->elapsedTime());
215 d->layoutTimer.stop();
219 suppressScrollBars(true);
222 void FrameView::initScrollBars()
224 if (!d->needToInitScrollBars)
226 d->needToInitScrollBars = false;
227 setScrollBarsMode(hScrollBarMode());
230 void FrameView::setMarginWidth(int w)
232 // make it update the rendering area when set
233 m_margins.setWidth(w);
236 void FrameView::setMarginHeight(int h)
238 // make it update the rendering area when set
239 m_margins.setHeight(h);
242 void FrameView::adjustViewSize()
244 if (m_frame->document()) {
245 Document *document = m_frame->document();
247 RenderView* root = static_cast<RenderView *>(document->renderer());
251 int docw = root->docWidth();
252 int doch = root->docHeight();
254 resizeContents(docw, doch);
258 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollBarMode& hMode, ScrollBarMode& vMode)
260 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
261 // overflow:hidden and overflow:scroll on <body> as applying to the document's
262 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
263 // use the root element.
264 switch (o->style()->overflowX()) {
266 hMode = ScrollBarAlwaysOff;
269 hMode = ScrollBarAlwaysOn;
272 hMode = ScrollBarAuto;
275 // Don't set it at all.
279 switch (o->style()->overflowY()) {
281 vMode = ScrollBarAlwaysOff;
284 vMode = ScrollBarAlwaysOn;
287 vMode = ScrollBarAuto;
290 // Don't set it at all.
295 int FrameView::layoutCount() const
297 return d->layoutCount;
300 bool FrameView::needsFullRepaint() const
302 return d->doFullRepaint;
305 void FrameView::addRepaintInfo(RenderObject* o, const IntRect& r)
307 if (!d->repaintRects) {
308 d->repaintRects = new DeprecatedPtrList<RenderObject::RepaintInfo>;
309 d->repaintRects->setAutoDelete(true);
312 d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
315 Node* FrameView::layoutRoot() const
317 return layoutPending() ? 0 : d->layoutRoot.get();
320 void FrameView::layout(bool allowSubtree)
322 d->layoutTimer.stop();
323 d->delayedLayout = false;
326 // FIXME: Do we need to set m_size.width here?
327 // FIXME: Should we set m_size.height here too?
328 m_size.setWidth(visibleWidth());
332 if (!allowSubtree && d->layoutRoot) {
333 if (d->layoutRoot->renderer())
334 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
338 bool subtree = d->layoutRoot;
339 Document* document = m_frame->document();
341 // FIXME: Should we set m_size.height here too?
342 m_size.setWidth(visibleWidth());
346 Node* rootNode = subtree ? d->layoutRoot.get() : document;
347 d->layoutSchedulingEnabled = false;
349 // Always ensure our style info is up-to-date. This can happen in situations where
350 // the layout beats any sort of style recalc update that needs to occur.
351 if (document->hasChangedChild())
352 document->recalcStyle();
354 RenderObject* root = rootNode->renderer();
356 // FIXME: Do we need to set m_size here?
357 d->layoutSchedulingEnabled = true;
361 ScrollBarMode hMode = d->hmode;
362 ScrollBarMode vMode = d->vmode;
365 Document* document = static_cast<Document*>(rootNode);
366 RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
367 if (document->isHTMLDocument()) {
368 Node *body = static_cast<HTMLDocument*>(document)->body();
369 if (body && body->renderer()) {
370 if (body->hasTagName(framesetTag)) {
371 body->renderer()->setNeedsLayout(true);
372 vMode = ScrollBarAlwaysOff;
373 hMode = ScrollBarAlwaysOff;
374 } else if (body->hasTagName(bodyTag)) {
375 if (!d->firstLayout && m_size.height() != visibleHeight() && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight())
376 body->renderer()->setChildNeedsLayout(true);
377 // It's sufficient to just check one overflow direction, since it's illegal to have visible in only one direction.
378 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE ? body->renderer() : rootRenderer;
379 applyOverflowToViewport(o, hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
382 } else if (rootRenderer)
383 applyOverflowToViewport(rootRenderer, hMode, vMode); // XML/XHTML UAs use the root element.
384 #if INSTRUMENT_LAYOUT_SCHEDULING
385 if (d->firstLayout && !document->ownerElement())
386 printf("Elapsed time before first layout: %d\n", document->elapsedTime());
390 d->doFullRepaint = !subtree && (d->firstLayout || static_cast<RenderView*>(root)->printingMode());
392 d->repaintRects->clear();
394 bool didFirstLayout = false;
396 // Now set our scrollbar state for the layout.
397 ScrollBarMode currentHMode = hScrollBarMode();
398 ScrollBarMode currentVMode = vScrollBarMode();
400 if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
401 suppressScrollBars(true);
402 if (d->firstLayout) {
403 d->firstLayout = false;
404 didFirstLayout = true;
406 // Set the initial vMode to AlwaysOn if we're auto.
407 if (vMode == ScrollBarAuto)
408 ScrollView::setVScrollBarMode(ScrollBarAlwaysOn); // This causes a vertical scrollbar to appear.
409 // Set the initial hMode to AlwaysOff if we're auto.
410 if (hMode == ScrollBarAuto)
411 ScrollView::setHScrollBarMode(ScrollBarAlwaysOff); // This causes a horizontal scrollbar to disappear.
415 ScrollView::setScrollBarsMode(hMode);
417 ScrollView::setHScrollBarMode(hMode);
418 ScrollView::setVScrollBarMode(vMode);
421 suppressScrollBars(false, true);
424 IntSize oldSize = m_size;
426 m_size = IntSize(visibleWidth(), visibleHeight());
428 if (oldSize != m_size)
429 d->doFullRepaint = true;
432 RenderLayer* layer = root->enclosingLayer();
434 if (!d->doFullRepaint) {
435 layer->checkForRepaintOnResize();
436 root->repaintObjectsBeforeLayout();
440 if (root->recalcMinMax())
441 root->recalcMinMaxWidths();
446 m_frame->invalidateSelection();
448 d->layoutSchedulingEnabled=true;
450 if (!subtree && !static_cast<RenderView*>(root)->printingMode())
451 resizeContents(layer->width(), layer->height());
453 // Now update the positions of all layers.
454 layer->updateLayerPositions(d->doFullRepaint);
456 // We update our widget positions right after doing a layout.
458 static_cast<RenderView*>(root)->updateWidgetPositions();
460 if (d->repaintRects && !d->repaintRects->isEmpty()) {
461 // FIXME: Could optimize this and have objects removed from this list
462 // if they ever do full repaints.
463 RenderObject::RepaintInfo* r;
464 DeprecatedPtrListIterator<RenderObject::RepaintInfo> it(*d->repaintRects);
465 for (; (r = it.current()); ++it)
466 r->m_object->repaintRectangle(r->m_repaintRect);
467 d->repaintRects->clear();
473 if (AccessibilityObjectCache::accessibilityEnabled())
474 root->document()->getAccObjectCache()->postNotification(root, "AXLayoutComplete");
475 updateDashboardRegions();
478 if (root->needsLayout()) {
482 setStaticBackground(d->useSlowRepaints);
485 m_frame->didFirstLayout();
493 static Frame* subframeForEvent(const MouseEventWithHitTestResults& mev)
495 if (!mev.targetNode())
498 RenderObject* renderer = mev.targetNode()->renderer();
499 if (!renderer || !renderer->isWidget())
502 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
503 if (!widget || !widget->isFrameView())
506 return static_cast<FrameView*>(widget)->frame();
509 void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
511 if (!m_frame->document())
514 RefPtr<FrameView> protector(this);
516 d->mousePressed = true;
518 MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
520 if (m_frame->passSubframeEventToSubframe(mev)) {
525 d->clickCount = mouseEvent.clickCount();
526 d->clickNode = mev.targetNode();
528 RenderLayer* layer = d->clickNode->renderer()? d->clickNode->renderer()->enclosingLayer() : 0;
529 IntPoint p = viewportToContents(mouseEvent.pos());
530 if (layer && layer->isPointInResizeControl(p)) {
531 layer->setInResizeMode(true);
532 d->m_resizeLayer = layer;
537 bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
540 m_frame->handleMousePressEvent(mev);
541 // Many AK widgets run their own event loops and consume events while the mouse is down.
542 // When they finish, currentEvent is the mouseUp that they exited on. We need to update
543 // the khtml state with this mouseUp, which khtml never saw.
544 // If this event isn't a mouseUp, we assume that the mouseUp will be coming later. There
545 // is a hole here if the widget consumes the mouseUp and subsequent events.
546 if (m_frame->lastEventIsMouseUp())
547 d->mousePressed = false;
551 void FrameView::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
553 if (!m_frame->document())
556 RefPtr<FrameView> protector(this);
558 // We get this instead of a second mouse-up
559 d->mousePressed = false;
561 MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
563 if (m_frame->passSubframeEventToSubframe(mev))
566 d->clickCount = mouseEvent.clickCount();
567 bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
569 if (mev.targetNode() == d->clickNode)
570 dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
572 // Qt delivers a release event AND a double click event.
574 m_frame->handleMouseReleaseEvent(mev);
575 m_frame->handleMouseReleaseDoubleClickEvent(mev);
581 static bool isSubmitImage(Node *node)
583 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE;
586 static Cursor selectCursor(const MouseEventWithHitTestResults& event, Frame* frame, bool mousePressed)
588 // During selection, use an I-beam no matter what we're over.
589 if (mousePressed && frame->hasSelection())
590 return iBeamCursor();
592 Node* node = event.targetNode();
593 RenderObject* renderer = node ? node->renderer() : 0;
594 RenderStyle* style = renderer ? renderer->style() : 0;
596 if (style && style->cursorImage() && !style->cursorImage()->image()->isNull())
597 if (!style->cursorImage()->isErrorImage())
598 return style->cursorImage()->image();
600 style = 0; // Fallback to CURSOR_AUTO
602 switch (style ? style->cursor() : CURSOR_AUTO) {
604 bool editable = (node && node->isContentEditable());
605 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || event.event().shiftKey()))
607 RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0;
608 bool inResizer = false;
609 if (frame->view() && layer && layer->isPointInResizeControl(frame->view()->viewportToContents(event.event().pos())))
611 if ((editable || (renderer && renderer->isText() && renderer->canSelect())) && !inResizer)
612 return iBeamCursor();
613 // FIXME: If the point is in a layer's overflow scrollbars, we should use the pointer cursor
614 return pointerCursor();
617 return crossCursor();
622 case CURSOR_E_RESIZE:
623 return eastResizeCursor();
624 case CURSOR_W_RESIZE:
625 return westResizeCursor();
626 case CURSOR_N_RESIZE:
627 return northResizeCursor();
628 case CURSOR_S_RESIZE:
629 return southResizeCursor();
630 case CURSOR_NE_RESIZE:
631 return northEastResizeCursor();
632 case CURSOR_SW_RESIZE:
633 return southWestResizeCursor();
634 case CURSOR_NW_RESIZE:
635 return northWestResizeCursor();
636 case CURSOR_SE_RESIZE:
637 return southEastResizeCursor();
638 case CURSOR_NS_RESIZE:
639 return northSouthResizeCursor();
640 case CURSOR_EW_RESIZE:
641 return eastWestResizeCursor();
642 case CURSOR_NESW_RESIZE:
643 return northEastSouthWestResizeCursor();
644 case CURSOR_NWSE_RESIZE:
645 return northWestSouthEastResizeCursor();
646 case CURSOR_COL_RESIZE:
647 return columnResizeCursor();
648 case CURSOR_ROW_RESIZE:
649 return rowResizeCursor();
651 return iBeamCursor();
657 return pointerCursor();
659 return pointerCursor();
662 void FrameView::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent)
664 // in Radar 3703768 we saw frequent crashes apparently due to the
665 // part being null here, which seems impossible, so check for nil
666 // but also assert so that we can try to figure this out in debug
667 // builds, if it happens.
669 if (!m_frame || !m_frame->document())
672 RefPtr<FrameView> protector(this);
674 if (d->hoverTimer.isActive())
675 d->hoverTimer.stop();
677 if (d->resizingFrameSet) {
678 dispatchMouseEvent(mousemoveEvent, d->resizingFrameSet.get(), false, 0, mouseEvent, false);
682 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
683 // if we are allowed to select.
684 // This means that :hover and :active freeze in the state they were in when the mouse
685 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
686 MouseEventWithHitTestResults mev = prepareMouseEvent(d->mousePressed && m_frame->mouseDownMayStartSelect(),
687 d->mousePressed, true, mouseEvent);
690 m_frame->passSubframeEventToSubframe(mev, d->oldSubframe.get());
692 bool swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
694 if (d->m_resizeLayer && d->m_resizeLayer->inResizeMode())
695 d->m_resizeLayer->resize(mouseEvent);
698 m_frame->handleMouseMoveEvent(mev);
700 RefPtr<Frame> newSubframe = subframeForEvent(mev);
702 if (newSubframe && d->oldSubframe != newSubframe)
703 m_frame->passSubframeEventToSubframe(mev, newSubframe.get());
705 setCursor(selectCursor(mev, m_frame.get(), d->mousePressed));
707 d->oldSubframe = newSubframe;
710 void FrameView::invalidateClick()
716 bool FrameView::mousePressed()
718 return d->mousePressed;
721 void FrameView::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
723 if (!m_frame->document())
726 RefPtr<FrameView> protector(this);
728 d->mousePressed = false;
730 if (d->resizingFrameSet) {
731 dispatchMouseEvent(mouseupEvent, d->resizingFrameSet.get(), true, d->clickCount, mouseEvent, false);
735 MouseEventWithHitTestResults mev = prepareMouseEvent(false, false, false, mouseEvent);
737 if (m_frame->passSubframeEventToSubframe(mev))
740 bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
742 if (d->clickCount > 0 && mev.targetNode() == d->clickNode)
743 dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
745 if (d->m_resizeLayer) {
746 d->m_resizeLayer->setInResizeMode(false);
747 d->m_resizeLayer = 0;
751 m_frame->handleMouseReleaseEvent(mev);
756 bool FrameView::dispatchDragEvent(const AtomicString& eventType, Node *dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
758 IntPoint clientPos = viewportToContents(event.pos());
760 RefPtr<MouseEvent> me = new MouseEvent(eventType,
761 true, true, m_frame->document()->defaultView(),
762 0, event.globalX(), event.globalY(), clientPos.x(), clientPos.y(),
763 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
766 ExceptionCode ec = 0;
767 EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec, true);
768 return me->defaultPrevented();
771 bool FrameView::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
775 MouseEventWithHitTestResults mev = prepareMouseEvent(true, false, false, event);
777 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
778 Node* newTarget = mev.targetNode();
779 if (newTarget && newTarget->isTextNode())
780 newTarget = newTarget->parentNode();
782 newTarget = newTarget->shadowAncestorNode();
784 if (d->dragTarget != newTarget) {
785 // note this ordering is explicitly chosen to match WinIE
787 accept = dispatchDragEvent(dragenterEvent, newTarget, event, clipboard);
789 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
792 accept = dispatchDragEvent(dragoverEvent, newTarget, event, clipboard);
794 d->dragTarget = newTarget;
799 void FrameView::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
802 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
806 bool FrameView::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
810 accept = dispatchDragEvent(dropEvent, d->dragTarget.get(), event, clipboard);
815 Node* FrameView::nodeUnderMouse() const
817 return d->underMouse.get();
820 bool FrameView::scrollTo(const IntRect& bounds)
822 d->scrollingSelf = true; // so scroll events get ignored
827 xe = bounds.right() - 1;
828 ye = bounds.bottom() - 1;
833 int curHeight = visibleHeight();
834 int curWidth = visibleWidth();
836 if (ye - y>curHeight-d->borderY)
837 ye = y + curHeight - d->borderY;
839 if (xe - x>curWidth-d->borderX)
840 xe = x + curWidth - d->borderX;
842 // is xpos of target left of the view's border?
843 if (x < contentsX() + d->borderX)
844 deltax = x - contentsX() - d->borderX;
845 // is xpos of target right of the view's right border?
846 else if (xe + d->borderX > contentsX() + curWidth)
847 deltax = xe + d->borderX - (contentsX() + curWidth);
851 // is ypos of target above upper border?
852 if (y < contentsY() + d->borderY)
853 deltay = y - contentsY() - d->borderY;
854 // is ypos of target below lower border?
855 else if (ye + d->borderY > contentsY() + curHeight)
856 deltay = ye + d->borderY - (contentsY() + curHeight);
860 int maxx = curWidth - d->borderX;
861 int maxy = curHeight - d->borderY;
863 int scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax > -maxx ? deltax : -maxx);
864 int scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay > -maxy ? deltay : -maxy);
866 if (contentsX() + scrollX < 0)
867 scrollX = -contentsX();
868 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
869 scrollX = contentsWidth() - visibleWidth() - contentsX();
871 if (contentsY() + scrollY < 0)
872 scrollY = -contentsY();
873 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
874 scrollY = contentsHeight() - visibleHeight() - contentsY();
876 scrollBy(scrollX, scrollY);
878 // generate abs(scroll.)
884 d->scrollingSelf = false;
886 return scrollX != maxx && scrollY != maxy;
889 void FrameView::focusNextPrevNode(bool next)
891 // Sets the focus node of the document to be the node after (or if next is false, before) the current focus node.
892 // Only nodes that are selectable (i.e. for which isSelectable() returns true) are taken into account, and the order
893 // used is that specified in the HTML spec (see Document::nextFocusNode() and Document::previousFocusNode()
896 Document *doc = m_frame->document();
897 Node *oldFocusNode = doc->focusNode();
900 // Find the next/previous node from the current one
902 newFocusNode = doc->nextFocusNode(oldFocusNode);
904 newFocusNode = doc->previousFocusNode(oldFocusNode);
906 // If there was previously no focus node and the user has scrolled the document, then instead of picking the first
907 // focusable node in the document, use the first one that lies within the visible area (if possible).
908 if (!oldFocusNode && newFocusNode && d->scrollBarMoved) {
909 bool visible = false;
910 Node *toFocus = newFocusNode;
911 while (!visible && toFocus) {
912 if (toFocus->getRect().intersects(IntRect(contentsX(), contentsY(), visibleWidth(), visibleHeight()))) {
913 // toFocus is visible in the contents area
916 // toFocus is _not_ visible in the contents area, pick the next node
918 toFocus = doc->nextFocusNode(toFocus);
920 toFocus = doc->previousFocusNode(toFocus);
925 newFocusNode = toFocus;
928 d->scrollBarMoved = false;
932 // No new focus node, scroll to bottom or top depending on next
934 scrollTo(IntRect(contentsX()+visibleWidth()/2,contentsHeight(),0,0));
936 scrollTo(IntRect(contentsX()+visibleWidth()/2,0,0,0));
939 // EDIT FIXME: if it's an editable element, activate the caret
940 // otherwise, hide it
941 if (newFocusNode->isContentEditable()) {
942 // make caret visible
948 // Scroll the view as necessary to ensure that the new focus node is visible
950 if (!scrollTo(newFocusNode->getRect()))
954 if (doc->renderer()) {
955 doc->renderer()->enclosingLayer()->scrollRectToVisible(IntRect(contentsX(), next ? 0: contentsHeight(), 0, 0));
959 // Set focus node on the document
960 m_frame->document()->setFocusNode(newFocusNode);
963 void FrameView::setMediaType(const String& mediaType)
965 d->m_mediaType = mediaType;
968 String FrameView::mediaType() const
970 // See if we have an override type.
971 String overrideType = m_frame->overrideMediaType();
972 if (!overrideType.isNull())
974 return d->m_mediaType;
977 void FrameView::useSlowRepaints()
979 d->useSlowRepaints = true;
980 setStaticBackground(true);
983 void FrameView::setScrollBarsMode(ScrollBarMode mode)
988 ScrollView::setScrollBarsMode(mode);
991 void FrameView::setVScrollBarMode(ScrollBarMode mode)
994 ScrollView::setVScrollBarMode(mode);
997 void FrameView::setHScrollBarMode(ScrollBarMode mode)
1000 ScrollView::setHScrollBarMode(mode);
1003 void FrameView::restoreScrollBar()
1005 suppressScrollBars(false);
1008 void FrameView::setResizingFrameSet(HTMLFrameSetElement* frameSet)
1010 d->resizingFrameSet = frameSet;
1013 MouseEventWithHitTestResults FrameView::prepareMouseEvent(bool readonly, bool active, bool mouseMove, const PlatformMouseEvent& mev)
1016 ASSERT(m_frame->document());
1018 IntPoint vPoint = viewportToContents(mev.pos());
1019 return m_frame->document()->prepareMouseEvent(readonly, active, mouseMove, vPoint, mev);
1022 bool FrameView::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool cancelable,
1023 int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1025 // if the target node is a text node, dispatch on the parent node - rdar://4196646
1026 if (targetNode && targetNode->isTextNode())
1027 targetNode = targetNode->parentNode();
1029 targetNode = targetNode->shadowAncestorNode();
1030 d->underMouse = targetNode;
1032 // mouseout/mouseover
1034 if (d->oldUnder && d->oldUnder->document() != frame()->document())
1037 if (d->oldUnder != targetNode) {
1038 // send mouseout event to the old node
1040 EventTargetNodeCast(d->oldUnder.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, targetNode);
1041 // send mouseover event to the new node
1043 EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, d->oldUnder.get());
1045 d->oldUnder = targetNode;
1048 bool swallowEvent = false;
1051 swallowEvent = EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1053 if (!swallowEvent && eventType == mousedownEvent) {
1054 // Blur current focus node when a link/button is clicked; this
1055 // is expected by some sites that rely on onChange handlers running
1056 // from form fields before the button click is processed.
1057 Node* node = targetNode;
1058 RenderObject* renderer = node ? node->renderer() : 0;
1060 // Walk up the render tree to search for a node to focus.
1061 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1063 node = renderer->element();
1064 if (node && node->isFocusable())
1066 renderer = renderer->parent();
1068 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
1069 // if the page already set it (e.g., by canceling default behavior).
1070 if (node && node->isMouseFocusable()) {
1071 if (!m_frame->document()->setFocusNode(node))
1072 swallowEvent = true;
1073 } else if (!node || !node->focused()) {
1074 if (!m_frame->document()->setFocusNode(0))
1075 swallowEvent = true;
1079 return swallowEvent;
1082 void FrameView::setIgnoreWheelEvents(bool e)
1084 d->ignoreWheelEvents = e;
1087 void FrameView::handleWheelEvent(PlatformWheelEvent& e)
1089 Document *doc = m_frame->document();
1091 RenderObject *docRenderer = doc->renderer();
1093 IntPoint vPoint = viewportToContents(e.pos());
1095 RenderObject::NodeInfo hitTestResult(true, false);
1096 doc->renderer()->layer()->hitTest(hitTestResult, vPoint);
1097 Node *node = hitTestResult.innerNode();
1099 if (m_frame->passWheelEventToChildWidget(node)) {
1104 node = node->shadowAncestorNode();
1105 EventTargetNodeCast(node)->dispatchWheelEvent(e);
1113 void FrameView::scrollBarMoved()
1115 // FIXME: Need to arrange for this to be called when the view is scrolled!
1116 if (!d->scrollingSelf)
1117 d->scrollBarMoved = true;
1120 void FrameView::repaintRectangle(const IntRect& r, bool immediate)
1122 updateContents(r, immediate);
1125 void FrameView::layoutTimerFired(Timer<FrameView>*)
1127 #if INSTRUMENT_LAYOUT_SCHEDULING
1128 if (m_frame->document() && !m_frame->document()->ownerElement())
1129 printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
1134 void FrameView::hoverTimerFired(Timer<FrameView>*)
1136 d->hoverTimer.stop();
1137 prepareMouseEvent(false, false, true, PlatformMouseEvent());
1140 void FrameView::scheduleRelayout()
1142 if (d->layoutRoot) {
1143 if (d->layoutRoot->renderer())
1144 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
1147 if (!d->layoutSchedulingEnabled)
1150 if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
1153 int delay = m_frame->document()->minimumLayoutDelay();
1154 if (d->layoutTimer.isActive() && d->delayedLayout && !delay)
1155 unscheduleRelayout();
1156 if (d->layoutTimer.isActive())
1159 d->delayedLayout = delay != 0;
1161 #if INSTRUMENT_LAYOUT_SCHEDULING
1162 if (!m_frame->document()->ownerElement())
1163 printf("Scheduling layout for %d\n", delay);
1166 d->layoutTimer.startOneShot(delay * 0.001);
1169 void FrameView::scheduleRelayoutOfSubtree(Node* n)
1171 if (!d->layoutSchedulingEnabled || m_frame->document() && m_frame->document()->renderer() && m_frame->document()->renderer()->needsLayout()) {
1173 n->renderer()->markContainingBlocksForLayout(false);
1177 if (layoutPending()) {
1178 if (d->layoutRoot != n) {
1179 // Just do a full relayout
1180 if (d->layoutRoot && d->layoutRoot->renderer())
1181 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
1184 n->renderer()->markContainingBlocksForLayout(false);
1187 int delay = m_frame->document()->minimumLayoutDelay();
1189 d->delayedLayout = delay != 0;
1190 d->layoutTimer.startOneShot(delay * 0.001);
1194 bool FrameView::layoutPending() const
1196 return d->layoutTimer.isActive();
1199 bool FrameView::haveDelayedLayoutScheduled()
1201 return d->layoutTimer.isActive() && d->delayedLayout;
1204 void FrameView::unscheduleRelayout()
1206 if (!d->layoutTimer.isActive())
1209 #if INSTRUMENT_LAYOUT_SCHEDULING
1210 if (m_frame->document() && !m_frame->document()->ownerElement())
1211 printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
1214 d->layoutTimer.stop();
1215 d->delayedLayout = false;
1218 bool FrameView::isTransparent() const
1220 return d->isTransparent;
1223 void FrameView::setTransparent(bool isTransparent)
1225 d->isTransparent = isTransparent;
1228 void FrameView::scheduleHoverStateUpdate()
1230 if (!d->hoverTimer.isActive())
1231 d->hoverTimer.startOneShot(0);
1234 void FrameView::setHasBorder(bool b)
1240 bool FrameView::hasBorder() const
1242 return d->m_hasBorder;
1245 void FrameView::cleared()
1248 if (RenderPart* renderer = m_frame->ownerRenderer())
1249 renderer->viewCleared();