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.
8 * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
27 #include "FrameView.h"
29 #include "AXObjectCache.h"
30 #include "CachedImage.h"
32 #include "EventNames.h"
33 #include "FloatRect.h"
35 #include "FrameTree.h"
36 #include "HTMLDocument.h"
37 #include "HTMLFrameSetElement.h"
38 #include "HTMLInputElement.h"
39 #include "HTMLNames.h"
41 #include "MouseEvent.h"
42 #include "MouseEventWithHitTestResults.h"
43 #include "OverflowEvent.h"
44 #include "PlatformKeyboardEvent.h"
45 #include "PlatformScrollBar.h"
46 #include "PlatformWheelEvent.h"
47 #include "RenderArena.h"
48 #include "RenderPart.h"
49 #include "RenderText.h"
50 #include "RenderView.h"
51 #include "SelectionController.h"
53 #include "cssstyleselector.h"
56 #include "XLinkNames.h"
58 #include "SVGCursorElement.h"
59 #include "SVGLength.h"
64 using namespace EventNames;
65 using namespace HTMLNames;
67 using namespace SVGNames;
70 struct ScheduledEvent {
71 RefPtr<Event> m_event;
72 RefPtr<EventTargetNode> m_eventTarget;
76 class FrameViewPrivate {
78 FrameViewPrivate(FrameView* view)
80 , layoutTimer(view, &FrameView::layoutTimerFired)
81 , hoverTimer(view, &FrameView::hoverTimerFired)
83 , m_mediaType("screen")
84 , m_scheduledEvents(0)
85 , m_overflowStatusDirty(true)
86 , m_viewportRenderer(0)
89 isTransparent = false;
90 baseBackgroundColor = Color::white;
91 vmode = hmode = ScrollbarAuto;
92 needToInitScrollbars = true;
98 delete m_scheduledEvents;
107 useSlowRepaints = false;
108 slowRepaintObjectCount = 0;
110 borderTouched = false;
111 scrollbarMoved = false;
112 ignoreWheelEvents = false;
117 scrollingSelf = false;
120 delayedLayout = false;
121 mousePressed = false;
122 doFullRepaint = true;
123 layoutSchedulingEnabled = true;
128 repaintRects->clear();
129 resizingFrameSet = 0;
131 m_currentMousePosition = IntPoint();
134 RefPtr<Node> underMouse;
135 RefPtr<Node> oldUnder;
136 RefPtr<Frame> oldSubframe;
137 RefPtr<PlatformScrollbar> oldScrollbar;
139 bool borderTouched : 1;
140 bool borderStart : 1;
141 bool scrollbarMoved : 1;
142 bool doFullRepaint : 1;
143 bool m_hasBorder : 1;
148 bool useSlowRepaints;
149 unsigned slowRepaintObjectCount;
150 bool ignoreWheelEvents;
152 int borderX, borderY;
154 RefPtr<Node> clickNode;
157 Timer<FrameView> layoutTimer;
159 RefPtr<Node> layoutRoot;
161 bool layoutSchedulingEnabled;
165 bool needToInitScrollbars;
168 Color baseBackgroundColor;
170 Timer<FrameView> hoverTimer;
172 RenderLayer* m_resizeLayer;
173 IntSize offsetFromResizeCorner;
175 // Used by objects during layout to communicate repaints that need to take place only
176 // after all layout has been completed.
177 DeprecatedPtrList<RenderObject::RepaintInfo>* repaintRects;
179 RefPtr<Node> dragTarget;
180 RefPtr<HTMLFrameSetElement> resizingFrameSet;
184 Vector<ScheduledEvent*>* m_scheduledEvents;
186 bool m_overflowStatusDirty;
187 bool horizontalOverflow;
188 bool m_verticalOverflow;
189 RenderObject* m_viewportRenderer;
191 IntPoint m_currentMousePosition;
194 FrameView::FrameView(Frame *frame)
197 , d(new FrameViewPrivate(this))
204 FrameView::~FrameView()
208 ASSERT(m_refCount == 0);
210 if (d->hoverTimer.isActive())
211 d->hoverTimer.stop();
213 // FIXME: Is this really the right place to call detach on the document?
214 if (Document* doc = m_frame->document())
216 if (RenderPart* renderer = m_frame->ownerRenderer())
217 renderer->setWidget(0);
224 bool FrameView::isFrameView() const
229 void FrameView::clearPart()
234 void FrameView::resetScrollbars()
236 // Reset the document's scrollbars back to our defaults before we yield the floor.
237 d->firstLayout = true;
238 suppressScrollbars(true);
239 ScrollView::setVScrollbarMode(d->vmode);
240 ScrollView::setHScrollbarMode(d->hmode);
241 suppressScrollbars(false);
244 void FrameView::init()
246 m_margins = IntSize(-1, -1); // undefined
250 void FrameView::clear()
252 setStaticBackground(false);
254 m_frame->selectionController()->clear();
258 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
259 if (d->layoutTimer.isActive() && m_frame->document() && !m_frame->document()->ownerElement())
260 printf("Killing the layout timer from a clear at %d\n", m_frame->document()->elapsedTime());
262 d->layoutTimer.stop();
266 suppressScrollbars(true);
269 bool FrameView::didFirstLayout() const
271 return !d->firstLayout;
274 void FrameView::initScrollbars()
276 if (!d->needToInitScrollbars)
278 d->needToInitScrollbars = false;
279 setScrollbarsMode(hScrollbarMode());
282 void FrameView::setMarginWidth(int w)
284 // make it update the rendering area when set
285 m_margins.setWidth(w);
288 void FrameView::setMarginHeight(int h)
290 // make it update the rendering area when set
291 m_margins.setHeight(h);
294 void FrameView::adjustViewSize()
296 if (m_frame->document()) {
297 Document *document = m_frame->document();
299 RenderView* root = static_cast<RenderView *>(document->renderer());
303 int docw = root->docWidth();
304 int doch = root->docHeight();
306 resizeContents(docw, doch);
310 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
312 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
313 // overflow:hidden and overflow:scroll on <body> as applying to the document's
314 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
315 // use the root element.
316 switch (o->style()->overflowX()) {
318 hMode = ScrollbarAlwaysOff;
321 hMode = ScrollbarAlwaysOn;
324 hMode = ScrollbarAuto;
327 // Don't set it at all.
331 switch (o->style()->overflowY()) {
333 vMode = ScrollbarAlwaysOff;
336 vMode = ScrollbarAlwaysOn;
339 vMode = ScrollbarAuto;
342 // Don't set it at all.
346 d->m_viewportRenderer = o;
349 int FrameView::layoutCount() const
351 return d->layoutCount;
354 bool FrameView::needsFullRepaint() const
356 return d->doFullRepaint;
359 void FrameView::addRepaintInfo(RenderObject* o, const IntRect& r)
361 if (!d->repaintRects) {
362 d->repaintRects = new DeprecatedPtrList<RenderObject::RepaintInfo>;
363 d->repaintRects->setAutoDelete(true);
366 d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
369 Node* FrameView::layoutRoot() const
371 return layoutPending() ? 0 : d->layoutRoot.get();
374 void FrameView::layout(bool allowSubtree)
376 d->layoutTimer.stop();
377 d->delayedLayout = false;
379 // Protect the view from being deleted during layout (in recalcStyle)
380 RefPtr<FrameView> protector(this);
383 // FIXME: Do we need to set m_size.width here?
384 // FIXME: Should we set m_size.height here too?
385 m_size.setWidth(visibleWidth());
389 if (!allowSubtree && d->layoutRoot) {
390 if (d->layoutRoot->renderer())
391 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
395 bool subtree = d->layoutRoot;
396 Document* document = m_frame->document();
398 // FIXME: Should we set m_size.height here too?
399 m_size.setWidth(visibleWidth());
403 Node* rootNode = subtree ? d->layoutRoot.get() : document;
404 d->layoutSchedulingEnabled = false;
406 // Always ensure our style info is up-to-date. This can happen in situations where
407 // the layout beats any sort of style recalc update that needs to occur.
408 if (document->hasChangedChild())
409 document->recalcStyle();
411 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
412 // so there's no point to continuiing to layout
413 if (protector->hasOneRef())
416 RenderObject* root = rootNode->renderer();
418 // FIXME: Do we need to set m_size here?
419 d->layoutSchedulingEnabled = true;
423 ScrollbarMode hMode = d->hmode;
424 ScrollbarMode vMode = d->vmode;
427 Document* document = static_cast<Document*>(rootNode);
428 RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
429 if (document->isHTMLDocument()) {
430 Node *body = static_cast<HTMLDocument*>(document)->body();
431 if (body && body->renderer()) {
432 if (body->hasTagName(framesetTag)) {
433 body->renderer()->setNeedsLayout(true);
434 vMode = ScrollbarAlwaysOff;
435 hMode = ScrollbarAlwaysOff;
436 } else if (body->hasTagName(bodyTag)) {
437 if (!d->firstLayout && m_size.height() != visibleHeight() && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight())
438 body->renderer()->setChildNeedsLayout(true);
439 // It's sufficient to just check one overflow direction, since it's illegal to have visible in only one direction.
440 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE ? body->renderer() : rootRenderer;
441 applyOverflowToViewport(o, hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
444 } else if (rootRenderer)
445 applyOverflowToViewport(rootRenderer, hMode, vMode); // XML/XHTML UAs use the root element.
446 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
447 if (d->firstLayout && !document->ownerElement())
448 printf("Elapsed time before first layout: %d\n", document->elapsedTime());
452 d->doFullRepaint = !subtree && (d->firstLayout || static_cast<RenderView*>(root)->printingMode());
454 d->repaintRects->clear();
456 bool didFirstLayout = false;
458 // Now set our scrollbar state for the layout.
459 ScrollbarMode currentHMode = hScrollbarMode();
460 ScrollbarMode currentVMode = vScrollbarMode();
462 if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
463 suppressScrollbars(true);
464 if (d->firstLayout) {
465 d->firstLayout = false;
466 didFirstLayout = true;
468 // Set the initial vMode to AlwaysOn if we're auto.
469 if (vMode == ScrollbarAuto)
470 ScrollView::setVScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
471 // Set the initial hMode to AlwaysOff if we're auto.
472 if (hMode == ScrollbarAuto)
473 ScrollView::setHScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
477 ScrollView::setScrollbarsMode(hMode);
479 ScrollView::setHScrollbarMode(hMode);
480 ScrollView::setVScrollbarMode(vMode);
483 suppressScrollbars(false, true);
486 IntSize oldSize = m_size;
488 m_size = IntSize(visibleWidth(), visibleHeight());
490 if (oldSize != m_size)
491 d->doFullRepaint = true;
494 RenderLayer* layer = root->enclosingLayer();
496 if (!d->doFullRepaint) {
497 layer->checkForRepaintOnResize();
498 root->repaintObjectsBeforeLayout();
502 if (root->recalcMinMax())
503 root->recalcMinMaxWidths();
508 m_frame->invalidateSelection();
510 d->layoutSchedulingEnabled=true;
512 if (!subtree && !static_cast<RenderView*>(root)->printingMode())
513 resizeContents(layer->width(), layer->height());
515 // Now update the positions of all layers.
516 layer->updateLayerPositions(d->doFullRepaint);
518 // We update our widget positions right after doing a layout.
520 static_cast<RenderView*>(root)->updateWidgetPositions();
522 if (d->repaintRects && !d->repaintRects->isEmpty()) {
523 // FIXME: Could optimize this and have objects removed from this list
524 // if they ever do full repaints.
525 RenderObject::RepaintInfo* r;
526 DeprecatedPtrListIterator<RenderObject::RepaintInfo> it(*d->repaintRects);
527 for (; (r = it.current()); ++it)
528 r->m_object->repaintRectangle(r->m_repaintRect);
529 d->repaintRects->clear();
535 if (AXObjectCache::accessibilityEnabled())
536 root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
537 updateDashboardRegions();
541 m_frame->didFirstLayout();
543 if (root->needsLayout()) {
547 setStaticBackground(useSlowRepaints());
549 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
550 updateOverflowStatus(visibleWidth() < contentsWidth(),
551 visibleHeight() < contentsHeight());
553 // Dispatch events scheduled during layout
554 dispatchScheduledEvents();
562 static Frame* subframeForTargetNode(Node* node)
567 RenderObject* renderer = node->renderer();
568 if (!renderer || !renderer->isWidget())
571 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
572 if (!widget || !widget->isFrameView())
575 return static_cast<FrameView*>(widget)->frame();
578 IntPoint FrameView::currentMousePosition() const
580 return d->m_currentMousePosition;
583 void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
585 if (!m_frame->document())
588 RefPtr<FrameView> protector(this);
590 d->mousePressed = true;
591 d->m_currentMousePosition = mouseEvent.pos();
593 MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
595 Frame* subframe = subframeForTargetNode(mev.targetNode());
596 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
601 d->clickCount = mouseEvent.clickCount();
602 d->clickNode = mev.targetNode();
604 RenderLayer* layer = d->clickNode->renderer()? d->clickNode->renderer()->enclosingLayer() : 0;
605 IntPoint p = windowToContents(mouseEvent.pos());
606 if (layer && layer->isPointInResizeControl(p)) {
607 layer->setInResizeMode(true);
608 d->m_resizeLayer = layer;
609 d->offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
614 bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
617 // Refetch the event target node if it currently is the shadow node inside an <input> element.
618 // If a mouse event handler changes the input element type to one that has a widget associated,
619 // we'd like to Frame::handleMousePressEvent to pass the event to the widget and thus the
620 // event target node can't still be the shadow node.
621 if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag))
622 mev = prepareMouseEvent(true, true, false, mouseEvent);
624 PlatformScrollbar* scrollbar = scrollbarUnderMouse(mouseEvent);
626 scrollbar = mev.scrollbar();
627 if (!scrollbar || !passMousePressEventToScrollbar(mev, scrollbar))
628 m_frame->handleMousePressEvent(mev);
630 // Many AK widgets run their own event loops and consume events while the mouse is down.
631 // When they finish, currentEvent is the mouseUp that they exited on. We need to update
632 // the khtml state with this mouseUp, which khtml never saw.
633 // If this event isn't a mouseUp, we assume that the mouseUp will be coming later. There
634 // is a hole here if the widget consumes the mouseUp and subsequent events.
635 if (m_frame->lastEventIsMouseUp())
636 d->mousePressed = false;
640 // This method only exists for platforms that don't know how to deliver
641 void FrameView::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
643 if (!m_frame->document())
646 RefPtr<FrameView> protector(this);
648 // We get this instead of a second mouse-up
649 d->mousePressed = false;
650 d->m_currentMousePosition = mouseEvent.pos();
652 MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
653 Frame* subframe = subframeForTargetNode(mev.targetNode());
654 if (subframe && passMousePressEventToSubframe(mev, subframe))
657 d->clickCount = mouseEvent.clickCount();
658 bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
660 if (mev.targetNode() == d->clickNode)
661 dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
664 m_frame->handleMouseReleaseEvent(mev);
669 static bool isSubmitImage(Node *node)
671 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE;
674 // Returns true if the node's editable block is not current focused for editing
675 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
677 return frame->selectionController()->rootEditableElement() != node->rootEditableElement();
680 static Cursor selectCursor(const MouseEventWithHitTestResults& event, Frame* frame, bool mousePressed, PlatformScrollbar* scrollbar)
682 // During selection, use an I-beam no matter what we're over.
683 if (mousePressed && frame->hasSelection())
684 return iBeamCursor();
686 Node* node = event.targetNode();
687 RenderObject* renderer = node ? node->renderer() : 0;
688 RenderStyle* style = renderer ? renderer->style() : 0;
690 if (style && style->cursors()) {
691 const CursorList* cursors = style->cursors();
692 for (unsigned i = 0; i < cursors->size(); ++i) {
693 CachedImage* cimage = (*cursors)[i].cursorImage;
694 IntPoint hotSpot = (*cursors)[i].hotSpot;
697 Element* e = node->document()->getElementById((*cursors)[i].cursorFragmentId);
698 if (e && e->hasTagName(cursorTag)) {
699 hotSpot.setX(int(static_cast<SVGCursorElement*>(e)->x()->value()));
700 hotSpot.setY(int(static_cast<SVGCursorElement*>(e)->y()->value()));
701 cimage = static_cast<SVGCursorElement*>(e)->cachedImage();
707 if (cimage->image()->isNull())
709 if (!cimage->isErrorImage()) {
710 return Cursor(cimage->image(), hotSpot);
715 switch (style ? style->cursor() : CURSOR_AUTO) {
717 bool editable = (node && node->isContentEditable());
718 bool editableLinkEnabled = false;
720 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
722 switch(frame->settings()->editableLinkBehavior()) {
724 case Settings::EditableLinkDefaultBehavior:
725 case Settings::EditableLinkAlwaysLive:
726 editableLinkEnabled = true;
729 case Settings::EditableLinkLiveWhenNotFocused:
730 editableLinkEnabled = nodeIsNotBeingEdited(node, frame) || event.event().shiftKey();
733 case Settings::EditableLinkOnlyLiveWithShiftKey:
734 editableLinkEnabled = event.event().shiftKey();
739 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
741 RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0;
742 bool inResizer = false;
743 if (frame->view() && layer && layer->isPointInResizeControl(frame->view()->windowToContents(event.event().pos())))
745 if ((editable || (renderer && renderer->isText() && renderer->canSelect())) && !inResizer && !scrollbar)
746 return iBeamCursor();
747 return pointerCursor();
750 return crossCursor();
755 case CURSOR_E_RESIZE:
756 return eastResizeCursor();
757 case CURSOR_W_RESIZE:
758 return westResizeCursor();
759 case CURSOR_N_RESIZE:
760 return northResizeCursor();
761 case CURSOR_S_RESIZE:
762 return southResizeCursor();
763 case CURSOR_NE_RESIZE:
764 return northEastResizeCursor();
765 case CURSOR_SW_RESIZE:
766 return southWestResizeCursor();
767 case CURSOR_NW_RESIZE:
768 return northWestResizeCursor();
769 case CURSOR_SE_RESIZE:
770 return southEastResizeCursor();
771 case CURSOR_NS_RESIZE:
772 return northSouthResizeCursor();
773 case CURSOR_EW_RESIZE:
774 return eastWestResizeCursor();
775 case CURSOR_NESW_RESIZE:
776 return northEastSouthWestResizeCursor();
777 case CURSOR_NWSE_RESIZE:
778 return northWestSouthEastResizeCursor();
779 case CURSOR_COL_RESIZE:
780 return columnResizeCursor();
781 case CURSOR_ROW_RESIZE:
782 return rowResizeCursor();
784 return iBeamCursor();
790 return pointerCursor();
792 return pointerCursor();
795 void FrameView::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent)
797 // in Radar 3703768 we saw frequent crashes apparently due to the
798 // part being null here, which seems impossible, so check for nil
799 // but also assert so that we can try to figure this out in debug
800 // builds, if it happens.
802 if (!m_frame || !m_frame->document())
805 RefPtr<FrameView> protector(this);
806 d->m_currentMousePosition = mouseEvent.pos();
808 if (d->hoverTimer.isActive())
809 d->hoverTimer.stop();
811 if (d->resizingFrameSet) {
812 dispatchMouseEvent(mousemoveEvent, d->resizingFrameSet.get(), false, 0, mouseEvent, false);
816 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
817 // if we are allowed to select.
818 // This means that :hover and :active freeze in the state they were in when the mouse
819 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
820 MouseEventWithHitTestResults mev = prepareMouseEvent(d->mousePressed && m_frame->mouseDownMayStartSelect(),
821 d->mousePressed, true, mouseEvent);
823 if (d->oldSubframe && d->oldSubframe->tree()->isDescendantOf(m_frame.get()))
824 passMouseMoveEventToSubframe(mev, d->oldSubframe.get());
826 bool swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
828 PlatformScrollbar* scrollbar = scrollbarUnderMouse(mouseEvent);
830 scrollbar = mev.scrollbar();
832 if (d->oldScrollbar != scrollbar) {
833 // Send mouse exited to the old scrollbar.
835 d->oldScrollbar->handleMouseOutEvent(mouseEvent);
836 d->oldScrollbar = scrollbar;
839 if (d->m_resizeLayer && d->m_resizeLayer->inResizeMode())
840 d->m_resizeLayer->resize(mouseEvent, d->offsetFromResizeCorner);
843 m_frame->handleMouseMoveEvent(mev);
845 RefPtr<Frame> newSubframe = subframeForTargetNode(mev.targetNode());
846 if (newSubframe && d->oldSubframe != newSubframe)
847 passMouseMoveEventToSubframe(mev, newSubframe.get());
849 if (scrollbar && !d->mousePressed)
850 scrollbar->handleMouseMoveEvent(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
851 if (!d->m_resizeLayer || !d->m_resizeLayer->inResizeMode())
852 setCursor(selectCursor(mev, m_frame.get(), d->mousePressed, scrollbar));
855 d->oldSubframe = newSubframe;
858 void FrameView::invalidateClick()
864 bool FrameView::mousePressed()
866 return d->mousePressed;
869 void FrameView::setMousePressed(bool pressed)
871 d->mousePressed = pressed;
874 void FrameView::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
876 if (!m_frame->document())
879 RefPtr<FrameView> protector(this);
881 d->mousePressed = false;
882 d->m_currentMousePosition = mouseEvent.pos();
884 if (d->resizingFrameSet) {
885 dispatchMouseEvent(mouseupEvent, d->resizingFrameSet.get(), true, d->clickCount, mouseEvent, false);
889 MouseEventWithHitTestResults mev = prepareMouseEvent(false, false, false, mouseEvent);
890 Frame* subframe = subframeForTargetNode(mev.targetNode());
891 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
894 bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
896 if (d->clickCount > 0 && mev.targetNode() == d->clickNode)
897 dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
899 if (d->m_resizeLayer) {
900 d->m_resizeLayer->setInResizeMode(false);
901 d->m_resizeLayer = 0;
905 m_frame->handleMouseReleaseEvent(mev);
910 bool FrameView::dispatchDragEvent(const AtomicString& eventType, Node *dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
912 IntPoint contentsPos = windowToContents(event.pos());
914 RefPtr<MouseEvent> me = new MouseEvent(eventType,
915 true, true, m_frame->document()->defaultView(),
916 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(),
917 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
920 ExceptionCode ec = 0;
921 EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec, true);
922 return me->defaultPrevented();
925 bool FrameView::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
929 MouseEventWithHitTestResults mev = prepareMouseEvent(true, false, false, event);
931 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
932 Node* newTarget = mev.targetNode();
933 if (newTarget && newTarget->isTextNode())
934 newTarget = newTarget->parentNode();
936 newTarget = newTarget->shadowAncestorNode();
938 if (d->dragTarget != newTarget) {
939 // note this ordering is explicitly chosen to match WinIE
941 accept = dispatchDragEvent(dragenterEvent, newTarget, event, clipboard);
943 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
946 accept = dispatchDragEvent(dragoverEvent, newTarget, event, clipboard);
948 d->dragTarget = newTarget;
953 void FrameView::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
956 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
960 bool FrameView::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
964 accept = dispatchDragEvent(dropEvent, d->dragTarget.get(), event, clipboard);
969 Node* FrameView::nodeUnderMouse() const
971 return d->underMouse.get();
974 bool FrameView::scrollTo(const IntRect& bounds)
976 d->scrollingSelf = true; // so scroll events get ignored
981 xe = bounds.right() - 1;
982 ye = bounds.bottom() - 1;
987 int curHeight = visibleHeight();
988 int curWidth = visibleWidth();
990 if (ye - y>curHeight-d->borderY)
991 ye = y + curHeight - d->borderY;
993 if (xe - x>curWidth-d->borderX)
994 xe = x + curWidth - d->borderX;
996 // is xpos of target left of the view's border?
997 if (x < contentsX() + d->borderX)
998 deltax = x - contentsX() - d->borderX;
999 // is xpos of target right of the view's right border?
1000 else if (xe + d->borderX > contentsX() + curWidth)
1001 deltax = xe + d->borderX - (contentsX() + curWidth);
1005 // is ypos of target above upper border?
1006 if (y < contentsY() + d->borderY)
1007 deltay = y - contentsY() - d->borderY;
1008 // is ypos of target below lower border?
1009 else if (ye + d->borderY > contentsY() + curHeight)
1010 deltay = ye + d->borderY - (contentsY() + curHeight);
1014 int maxx = curWidth - d->borderX;
1015 int maxy = curHeight - d->borderY;
1017 int scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax > -maxx ? deltax : -maxx);
1018 int scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay > -maxy ? deltay : -maxy);
1020 if (contentsX() + scrollX < 0)
1021 scrollX = -contentsX();
1022 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
1023 scrollX = contentsWidth() - visibleWidth() - contentsX();
1025 if (contentsY() + scrollY < 0)
1026 scrollY = -contentsY();
1027 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
1028 scrollY = contentsHeight() - visibleHeight() - contentsY();
1030 scrollBy(scrollX, scrollY);
1032 // generate abs(scroll.)
1038 d->scrollingSelf = false;
1040 return scrollX != maxx && scrollY != maxy;
1043 bool FrameView::advanceFocus(bool forward)
1045 Document* document = m_frame->document();
1049 Node* node = forward
1050 ? document->nextFocusNode(document->focusNode())
1051 : document->previousFocusNode(document->focusNode());
1054 // FIXME: Need to support tabbing out of the document to the UI.
1057 if (!node->isElementNode())
1058 // FIXME: May need a way to focus a document here.
1061 static_cast<Element*>(node)->focus();
1065 void FrameView::setMediaType(const String& mediaType)
1067 d->m_mediaType = mediaType;
1070 String FrameView::mediaType() const
1072 // See if we have an override type.
1073 String overrideType = m_frame->overrideMediaType();
1074 if (!overrideType.isNull())
1075 return overrideType;
1076 return d->m_mediaType;
1079 bool FrameView::useSlowRepaints() const
1081 return d->useSlowRepaints || d->slowRepaintObjectCount > 0;
1084 void FrameView::setUseSlowRepaints()
1086 d->useSlowRepaints = true;
1087 setStaticBackground(true);
1090 void FrameView::addSlowRepaintObject()
1092 if (d->slowRepaintObjectCount == 0)
1093 setStaticBackground(true);
1094 d->slowRepaintObjectCount++;
1097 void FrameView::removeSlowRepaintObject()
1099 d->slowRepaintObjectCount--;
1100 if (d->slowRepaintObjectCount == 0)
1101 setStaticBackground(d->useSlowRepaints);
1104 void FrameView::setScrollbarsMode(ScrollbarMode mode)
1109 ScrollView::setScrollbarsMode(mode);
1112 void FrameView::setVScrollbarMode(ScrollbarMode mode)
1115 ScrollView::setVScrollbarMode(mode);
1118 void FrameView::setHScrollbarMode(ScrollbarMode mode)
1121 ScrollView::setHScrollbarMode(mode);
1124 void FrameView::restoreScrollbar()
1126 suppressScrollbars(false);
1129 void FrameView::setResizingFrameSet(HTMLFrameSetElement* frameSet)
1131 d->resizingFrameSet = frameSet;
1134 void FrameView::scrollPointRecursively(int x, int y)
1136 if (frame()->prohibitsScrolling())
1139 ScrollView::scrollPointRecursively(x, y);
1142 void FrameView::setContentsPos(int x, int y)
1144 if (frame()->prohibitsScrolling())
1147 ScrollView::setContentsPos(x, y);
1150 MouseEventWithHitTestResults FrameView::prepareMouseEvent(bool readonly, bool active, bool mouseMove, const PlatformMouseEvent& mev)
1153 ASSERT(m_frame->document());
1155 IntPoint vPoint = windowToContents(mev.pos());
1156 return m_frame->document()->prepareMouseEvent(readonly, active, mouseMove, vPoint, mev);
1159 bool FrameView::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool cancelable,
1160 int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1162 // if the target node is a text node, dispatch on the parent node - rdar://4196646
1163 if (targetNode && targetNode->isTextNode())
1164 targetNode = targetNode->parentNode();
1166 targetNode = targetNode->shadowAncestorNode();
1167 d->underMouse = targetNode;
1169 // mouseout/mouseover
1171 if (d->oldUnder && d->oldUnder->document() != frame()->document()) {
1173 d->oldScrollbar = 0;
1176 if (d->oldUnder != targetNode) {
1177 // send mouseout event to the old node
1179 EventTargetNodeCast(d->oldUnder.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, targetNode);
1180 // send mouseover event to the new node
1182 EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, d->oldUnder.get());
1184 d->oldUnder = targetNode;
1187 bool swallowEvent = false;
1190 swallowEvent = EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1192 if (!swallowEvent && eventType == mousedownEvent) {
1193 // Blur current focus node when a link/button is clicked; this
1194 // is expected by some sites that rely on onChange handlers running
1195 // from form fields before the button click is processed.
1196 Node* node = targetNode;
1197 RenderObject* renderer = node ? node->renderer() : 0;
1199 // Walk up the render tree to search for a node to focus.
1200 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1202 node = renderer->element();
1203 if (node && node->isFocusable())
1205 renderer = renderer->parent();
1207 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
1208 // if the page already set it (e.g., by canceling default behavior).
1209 if (node && node->isMouseFocusable()) {
1210 if (!m_frame->document()->setFocusNode(node))
1211 swallowEvent = true;
1212 } else if (!node || !node->focused()) {
1213 if (!m_frame->document()->setFocusNode(0))
1214 swallowEvent = true;
1218 // It's ok to shift focus to this view now that we know that no focus change got blocked.
1219 if (!swallowEvent && !hasFocus())
1224 return swallowEvent;
1227 void FrameView::setIgnoreWheelEvents(bool e)
1229 d->ignoreWheelEvents = e;
1232 void FrameView::handleWheelEvent(PlatformWheelEvent& e)
1234 Document *doc = m_frame->document();
1236 RenderObject *docRenderer = doc->renderer();
1238 IntPoint vPoint = windowToContents(e.pos());
1240 RenderObject::NodeInfo hitTestResult(true, false);
1241 doc->renderer()->layer()->hitTest(hitTestResult, vPoint);
1242 Node *node = hitTestResult.innerNode();
1243 Frame* subframe = subframeForTargetNode(node);
1244 if (subframe && passWheelEventToSubframe(e, subframe)) {
1250 node = node->shadowAncestorNode();
1251 EventTargetNodeCast(node)->dispatchWheelEvent(e);
1255 if (node->renderer()) {
1256 // Just break up into two scrolls if we need to. Diagonal movement on
1257 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
1258 if (e.deltaX() && node->renderer()->scroll(e.deltaX() < 0 ? ScrollRight : ScrollLeft, ScrollByWheel,
1259 e.deltaX() < 0 ? -e.deltaX() : e.deltaX()))
1261 if (e.deltaY() && node->renderer()->scroll(e.deltaY() < 0 ? ScrollDown : ScrollUp, ScrollByWheel,
1262 e.deltaY() < 0 ? -e.deltaY() : e.deltaY()))
1265 if (!e.isAccepted())
1273 void FrameView::scrollbarMoved()
1275 // FIXME: Need to arrange for this to be called when the view is scrolled!
1276 if (!d->scrollingSelf)
1277 d->scrollbarMoved = true;
1280 void FrameView::repaintRectangle(const IntRect& r, bool immediate)
1282 updateContents(r, immediate);
1285 void FrameView::layoutTimerFired(Timer<FrameView>*)
1287 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1288 if (m_frame->document() && !m_frame->document()->ownerElement())
1289 printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
1294 void FrameView::hoverTimerFired(Timer<FrameView>*)
1296 d->hoverTimer.stop();
1297 prepareMouseEvent(false, false, true, PlatformMouseEvent(PlatformMouseEvent::currentEvent));
1300 void FrameView::scheduleRelayout()
1302 if (d->layoutRoot) {
1303 if (d->layoutRoot->renderer())
1304 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
1307 if (!d->layoutSchedulingEnabled)
1310 if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
1313 int delay = m_frame->document()->minimumLayoutDelay();
1314 if (d->layoutTimer.isActive() && d->delayedLayout && !delay)
1315 unscheduleRelayout();
1316 if (d->layoutTimer.isActive())
1319 d->delayedLayout = delay != 0;
1321 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1322 if (!m_frame->document()->ownerElement())
1323 printf("Scheduling layout for %d\n", delay);
1326 d->layoutTimer.startOneShot(delay * 0.001);
1329 void FrameView::scheduleRelayoutOfSubtree(Node* n)
1331 if (!d->layoutSchedulingEnabled || m_frame->document() && m_frame->document()->renderer() && m_frame->document()->renderer()->needsLayout()) {
1333 n->renderer()->markContainingBlocksForLayout(false);
1337 if (layoutPending()) {
1338 if (d->layoutRoot != n) {
1339 // Just do a full relayout
1340 if (d->layoutRoot && d->layoutRoot->renderer())
1341 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
1344 n->renderer()->markContainingBlocksForLayout(false);
1347 int delay = m_frame->document()->minimumLayoutDelay();
1349 d->delayedLayout = delay != 0;
1350 d->layoutTimer.startOneShot(delay * 0.001);
1354 bool FrameView::layoutPending() const
1356 return d->layoutTimer.isActive();
1359 bool FrameView::haveDelayedLayoutScheduled()
1361 return d->layoutTimer.isActive() && d->delayedLayout;
1364 void FrameView::unscheduleRelayout()
1366 if (!d->layoutTimer.isActive())
1369 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1370 if (m_frame->document() && !m_frame->document()->ownerElement())
1371 printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
1374 d->layoutTimer.stop();
1375 d->delayedLayout = false;
1378 bool FrameView::isTransparent() const
1380 return d->isTransparent;
1383 void FrameView::setTransparent(bool isTransparent)
1385 d->isTransparent = isTransparent;
1388 Color FrameView::baseBackgroundColor() const
1390 return d->baseBackgroundColor;
1393 void FrameView::setBaseBackgroundColor(Color bc)
1397 d->baseBackgroundColor = bc;
1400 void FrameView::scheduleHoverStateUpdate()
1402 if (!d->hoverTimer.isActive())
1403 d->hoverTimer.startOneShot(0);
1406 void FrameView::setHasBorder(bool b)
1412 bool FrameView::hasBorder() const
1414 return d->m_hasBorder;
1417 void FrameView::cleared()
1420 if (RenderPart* renderer = m_frame->ownerRenderer())
1421 renderer->viewCleared();
1425 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget, bool tempEvent)
1427 if (!d->m_scheduledEvents)
1428 d->m_scheduledEvents = new Vector<ScheduledEvent*>;
1430 ScheduledEvent *scheduledEvent = new ScheduledEvent;
1431 scheduledEvent->m_event = event;
1432 scheduledEvent->m_eventTarget = eventTarget;
1433 scheduledEvent->m_tempEvent = tempEvent;
1435 d->m_scheduledEvents->append(scheduledEvent);
1438 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
1440 if (!d->m_viewportRenderer)
1443 if (d->m_overflowStatusDirty) {
1444 d->horizontalOverflow = horizontalOverflow;
1445 d->m_verticalOverflow = verticalOverflow;
1446 d->m_overflowStatusDirty = false;
1451 bool horizontalOverflowChanged = (d->horizontalOverflow != horizontalOverflow);
1452 bool verticalOverflowChanged = (d->m_verticalOverflow != verticalOverflow);
1454 if (horizontalOverflowChanged || verticalOverflowChanged) {
1455 d->horizontalOverflow = horizontalOverflow;
1456 d->m_verticalOverflow = verticalOverflow;
1458 scheduleEvent(new OverflowEvent(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
1459 EventTargetNodeCast(d->m_viewportRenderer->element()), true);
1464 void FrameView::dispatchScheduledEvents()
1466 if (!d->m_scheduledEvents)
1469 Vector<ScheduledEvent*> scheduledEventsCopy = *d->m_scheduledEvents;
1470 d->m_scheduledEvents->clear();
1472 Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end();
1473 for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) {
1474 ScheduledEvent* scheduledEvent = *it;
1476 ExceptionCode ec = 0;
1478 // Only dispatch events to nodes that are in the document
1479 if (scheduledEvent->m_eventTarget->inDocument())
1480 scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event, ec, scheduledEvent->m_tempEvent);
1482 delete scheduledEvent;
1486 IntRect FrameView::windowClipRect() const
1488 // Get our parent's clip rect.
1489 IntRect clipRect(enclosingIntRect(visibleContentRect()));
1490 clipRect.setLocation(contentsToWindow(clipRect.location()));
1491 if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement())
1494 // Take our owner element and get the clip rect from the enclosing layer.
1495 Element* elt = m_frame->document()->ownerElement();
1496 RenderLayer* layer = elt->renderer()->enclosingLayer();
1498 // Apply the clip from the layer.
1499 FrameView* parentView = elt->document()->view();
1500 IntRect layerClipRect = layer->documentClipRect();
1501 layerClipRect.setLocation(parentView->contentsToWindow(layerClipRect.location()));
1502 clipRect.intersect(layerClipRect);
1504 // Now apply the clip from our ancestor.
1505 clipRect.intersect(parentView->windowClipRect());