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)
9 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
28 #include "FrameView.h"
30 #include "AXObjectCache.h"
31 #include "CachedImage.h"
33 #include "EventNames.h"
34 #include "FloatRect.h"
36 #include "FrameLoader.h"
37 #include "FrameTree.h"
38 #include "HTMLDocument.h"
39 #include "HTMLFrameElementBase.h"
40 #include "HTMLFrameSetElement.h"
41 #include "HTMLInputElement.h"
42 #include "HTMLNames.h"
43 #include "HitTestRequest.h"
44 #include "HitTestResult.h"
46 #include "KeyboardEvent.h"
47 #include "MouseEvent.h"
48 #include "MouseEventWithHitTestResults.h"
49 #include "OverflowEvent.h"
50 #include "PlatformKeyboardEvent.h"
51 #include "PlatformScrollBar.h"
52 #include "PlatformWheelEvent.h"
53 #include "RenderArena.h"
54 #include "RenderPart.h"
55 #include "RenderText.h"
56 #include "RenderView.h"
57 #include "SelectionController.h"
59 #include "cssstyleselector.h"
62 #include "XLinkNames.h"
64 #include "SVGCursorElement.h"
65 #include "SVGLength.h"
70 using namespace EventNames;
71 using namespace HTMLNames;
73 using namespace SVGNames;
76 struct ScheduledEvent {
77 RefPtr<Event> m_event;
78 RefPtr<EventTargetNode> m_eventTarget;
82 class FrameViewPrivate {
84 FrameViewPrivate(FrameView* view)
86 , layoutTimer(view, &FrameView::layoutTimerFired)
87 , hoverTimer(view, &FrameView::hoverTimerFired)
89 , m_mediaType("screen")
90 , m_scheduledEvents(0)
91 , m_overflowStatusDirty(true)
92 , m_viewportRenderer(0)
95 isTransparent = false;
96 baseBackgroundColor = Color::white;
97 vmode = hmode = ScrollbarAuto;
98 needToInitScrollbars = true;
104 delete m_scheduledEvents;
113 useSlowRepaints = false;
114 slowRepaintObjectCount = 0;
116 borderTouched = false;
117 ignoreWheelEvents = false;
124 delayedLayout = false;
125 mousePressed = false;
126 doFullRepaint = true;
127 layoutSchedulingEnabled = true;
132 repaintRects->clear();
133 resizingFrameSet = 0;
135 m_currentMousePosition = IntPoint();
138 RefPtr<Node> underMouse;
139 RefPtr<Node> oldUnder;
140 RefPtr<Frame> oldSubframe;
141 RefPtr<PlatformScrollbar> oldScrollbar;
143 bool borderTouched : 1;
144 bool borderStart : 1;
145 bool doFullRepaint : 1;
146 bool m_hasBorder : 1;
151 bool useSlowRepaints;
152 unsigned slowRepaintObjectCount;
153 bool ignoreWheelEvents;
155 int borderX, borderY;
157 RefPtr<Node> clickNode;
159 Timer<FrameView> layoutTimer;
161 RefPtr<Node> layoutRoot;
163 bool layoutSchedulingEnabled;
167 bool needToInitScrollbars;
170 Color baseBackgroundColor;
172 Timer<FrameView> hoverTimer;
174 RenderLayer* m_resizeLayer;
175 IntSize offsetFromResizeCorner;
177 // Used by objects during layout to communicate repaints that need to take place only
178 // after all layout has been completed.
179 DeprecatedPtrList<RenderObject::RepaintInfo>* repaintRects;
181 RefPtr<Node> dragTarget;
182 RefPtr<HTMLFrameSetElement> resizingFrameSet;
186 Vector<ScheduledEvent*>* m_scheduledEvents;
188 bool m_overflowStatusDirty;
189 bool horizontalOverflow;
190 bool m_verticalOverflow;
191 RenderObject* m_viewportRenderer;
193 IntPoint m_currentMousePosition;
196 FrameView::FrameView(Frame *frame)
199 , d(new FrameViewPrivate(this))
206 FrameView::~FrameView()
210 ASSERT(m_refCount == 0);
212 if (d->hoverTimer.isActive())
213 d->hoverTimer.stop();
215 // FIXME: Is this really the right place to call detach on the document?
216 if (Document* doc = m_frame->document())
218 if (RenderPart* renderer = m_frame->ownerRenderer())
219 renderer->setWidget(0);
226 bool FrameView::isFrameView() const
231 void FrameView::clearPart()
236 void FrameView::resetScrollbars()
238 // Reset the document's scrollbars back to our defaults before we yield the floor.
239 d->firstLayout = true;
240 suppressScrollbars(true);
241 ScrollView::setVScrollbarMode(d->vmode);
242 ScrollView::setHScrollbarMode(d->hmode);
243 suppressScrollbars(false);
246 void FrameView::init()
248 m_margins = IntSize(-1, -1); // undefined
252 void FrameView::clear()
254 setStaticBackground(false);
256 m_frame->selectionController()->clear();
260 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
261 if (d->layoutTimer.isActive() && m_frame->document() && !m_frame->document()->ownerElement())
262 printf("Killing the layout timer from a clear at %d\n", m_frame->document()->elapsedTime());
264 d->layoutTimer.stop();
267 if (RenderPart* renderer = m_frame->ownerRenderer())
268 renderer->viewCleared();
270 suppressScrollbars(true);
273 bool FrameView::didFirstLayout() const
275 return !d->firstLayout;
278 void FrameView::initScrollbars()
280 if (!d->needToInitScrollbars)
282 d->needToInitScrollbars = false;
283 setScrollbarsMode(hScrollbarMode());
286 void FrameView::setMarginWidth(int w)
288 // make it update the rendering area when set
289 m_margins.setWidth(w);
292 void FrameView::setMarginHeight(int h)
294 // make it update the rendering area when set
295 m_margins.setHeight(h);
298 void FrameView::adjustViewSize()
300 if (m_frame->document()) {
301 Document *document = m_frame->document();
303 RenderView* root = static_cast<RenderView *>(document->renderer());
307 int docw = root->docWidth();
308 int doch = root->docHeight();
310 resizeContents(docw, doch);
314 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
316 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
317 // overflow:hidden and overflow:scroll on <body> as applying to the document's
318 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
319 // use the root element.
320 switch (o->style()->overflowX()) {
322 hMode = ScrollbarAlwaysOff;
325 hMode = ScrollbarAlwaysOn;
328 hMode = ScrollbarAuto;
331 // Don't set it at all.
335 switch (o->style()->overflowY()) {
337 vMode = ScrollbarAlwaysOff;
340 vMode = ScrollbarAlwaysOn;
343 vMode = ScrollbarAuto;
346 // Don't set it at all.
350 d->m_viewportRenderer = o;
353 int FrameView::layoutCount() const
355 return d->layoutCount;
358 bool FrameView::needsFullRepaint() const
360 return d->doFullRepaint;
363 void FrameView::addRepaintInfo(RenderObject* o, const IntRect& r)
365 if (!d->repaintRects) {
366 d->repaintRects = new DeprecatedPtrList<RenderObject::RepaintInfo>;
367 d->repaintRects->setAutoDelete(true);
370 d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
373 Node* FrameView::layoutRoot() const
375 return layoutPending() ? 0 : d->layoutRoot.get();
378 void FrameView::layout(bool allowSubtree)
380 d->layoutTimer.stop();
381 d->delayedLayout = false;
383 // Protect the view from being deleted during layout (in recalcStyle)
384 RefPtr<FrameView> protector(this);
387 // FIXME: Do we need to set m_size.width here?
388 // FIXME: Should we set m_size.height here too?
389 m_size.setWidth(visibleWidth());
393 if (!allowSubtree && d->layoutRoot) {
394 if (d->layoutRoot->renderer())
395 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
399 bool subtree = d->layoutRoot;
400 Document* document = m_frame->document();
402 // FIXME: Should we set m_size.height here too?
403 m_size.setWidth(visibleWidth());
407 Node* rootNode = subtree ? d->layoutRoot.get() : document;
408 d->layoutSchedulingEnabled = false;
410 // Always ensure our style info is up-to-date. This can happen in situations where
411 // the layout beats any sort of style recalc update that needs to occur.
412 if (document->hasChangedChild())
413 document->recalcStyle();
415 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
416 // so there's no point to continuiing to layout
417 if (protector->hasOneRef())
420 RenderObject* root = rootNode->renderer();
422 // FIXME: Do we need to set m_size here?
423 d->layoutSchedulingEnabled = true;
427 ScrollbarMode hMode = d->hmode;
428 ScrollbarMode vMode = d->vmode;
431 Document* document = static_cast<Document*>(rootNode);
432 RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
433 if (document->isHTMLDocument()) {
434 Node *body = static_cast<HTMLDocument*>(document)->body();
435 if (body && body->renderer()) {
436 if (body->hasTagName(framesetTag)) {
437 body->renderer()->setNeedsLayout(true);
438 vMode = ScrollbarAlwaysOff;
439 hMode = ScrollbarAlwaysOff;
440 } else if (body->hasTagName(bodyTag)) {
441 if (!d->firstLayout && m_size.height() != visibleHeight() && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight())
442 body->renderer()->setChildNeedsLayout(true);
443 // It's sufficient to just check one overflow direction, since it's illegal to have visible in only one direction.
444 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE ? body->renderer() : rootRenderer;
445 applyOverflowToViewport(o, hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
448 } else if (rootRenderer)
449 applyOverflowToViewport(rootRenderer, hMode, vMode); // XML/XHTML UAs use the root element.
450 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
451 if (d->firstLayout && !document->ownerElement())
452 printf("Elapsed time before first layout: %d\n", document->elapsedTime());
456 d->doFullRepaint = !subtree && (d->firstLayout || static_cast<RenderView*>(root)->printingMode());
458 d->repaintRects->clear();
460 bool didFirstLayout = false;
462 // Now set our scrollbar state for the layout.
463 ScrollbarMode currentHMode = hScrollbarMode();
464 ScrollbarMode currentVMode = vScrollbarMode();
466 if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
467 suppressScrollbars(true);
468 if (d->firstLayout) {
469 d->firstLayout = false;
470 didFirstLayout = true;
472 // Set the initial vMode to AlwaysOn if we're auto.
473 if (vMode == ScrollbarAuto)
474 ScrollView::setVScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
475 // Set the initial hMode to AlwaysOff if we're auto.
476 if (hMode == ScrollbarAuto)
477 ScrollView::setHScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
481 ScrollView::setScrollbarsMode(hMode);
483 ScrollView::setHScrollbarMode(hMode);
484 ScrollView::setVScrollbarMode(vMode);
487 suppressScrollbars(false, true);
490 IntSize oldSize = m_size;
492 m_size = IntSize(visibleWidth(), visibleHeight());
494 if (oldSize != m_size)
495 d->doFullRepaint = true;
498 RenderLayer* layer = root->enclosingLayer();
500 if (!d->doFullRepaint) {
501 layer->checkForRepaintOnResize();
502 root->repaintObjectsBeforeLayout();
506 if (root->recalcMinMax())
507 root->recalcMinMaxWidths();
512 m_frame->invalidateSelection();
514 d->layoutSchedulingEnabled=true;
516 if (!subtree && !static_cast<RenderView*>(root)->printingMode())
517 resizeContents(layer->width(), layer->height());
519 // Now update the positions of all layers.
520 layer->updateLayerPositions(d->doFullRepaint);
522 // We update our widget positions right after doing a layout.
524 static_cast<RenderView*>(root)->updateWidgetPositions();
526 if (d->repaintRects && !d->repaintRects->isEmpty()) {
527 // FIXME: Could optimize this and have objects removed from this list
528 // if they ever do full repaints.
529 RenderObject::RepaintInfo* r;
530 DeprecatedPtrListIterator<RenderObject::RepaintInfo> it(*d->repaintRects);
531 for (; (r = it.current()); ++it)
532 r->m_object->repaintRectangle(r->m_repaintRect);
533 d->repaintRects->clear();
539 if (AXObjectCache::accessibilityEnabled())
540 root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
541 updateDashboardRegions();
545 m_frame->loader()->didFirstLayout();
547 if (root->needsLayout()) {
551 setStaticBackground(useSlowRepaints());
553 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
554 updateOverflowStatus(visibleWidth() < contentsWidth(),
555 visibleHeight() < contentsHeight());
557 // Dispatch events scheduled during layout
558 dispatchScheduledEvents();
566 static Frame* subframeForTargetNode(Node* node)
571 RenderObject* renderer = node->renderer();
572 if (!renderer || !renderer->isWidget())
575 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
576 if (!widget || !widget->isFrameView())
579 return static_cast<FrameView*>(widget)->frame();
582 IntPoint FrameView::currentMousePosition() const
584 return d->m_currentMousePosition;
587 void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
589 if (!m_frame->document())
592 RefPtr<FrameView> protector(this);
594 d->mousePressed = true;
595 d->m_currentMousePosition = mouseEvent.pos();
597 MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
599 if (!mev.targetNode()) {
604 Frame* subframe = subframeForTargetNode(mev.targetNode());
605 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
610 d->clickCount = mouseEvent.clickCount();
611 d->clickNode = mev.targetNode();
613 RenderLayer* layer = d->clickNode->renderer()? d->clickNode->renderer()->enclosingLayer() : 0;
614 IntPoint p = windowToContents(mouseEvent.pos());
615 if (layer && layer->isPointInResizeControl(p)) {
616 layer->setInResizeMode(true);
617 d->m_resizeLayer = layer;
618 d->offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
623 bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
626 // Refetch the event target node if it currently is the shadow node inside an <input> element.
627 // If a mouse event handler changes the input element type to one that has a widget associated,
628 // we'd like to Frame::handleMousePressEvent to pass the event to the widget and thus the
629 // event target node can't still be the shadow node.
630 if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag))
631 mev = prepareMouseEvent(true, true, false, mouseEvent);
633 PlatformScrollbar* scrollbar = scrollbarUnderMouse(mouseEvent);
635 scrollbar = mev.scrollbar();
636 if (!scrollbar || !passMousePressEventToScrollbar(mev, scrollbar))
637 m_frame->handleMousePressEvent(mev);
639 // Many AK widgets run their own event loops and consume events while the mouse is down.
640 // When they finish, currentEvent is the mouseUp that they exited on. We need to update
641 // the khtml state with this mouseUp, which khtml never saw.
642 // If this event isn't a mouseUp, we assume that the mouseUp will be coming later. There
643 // is a hole here if the widget consumes the mouseUp and subsequent events.
644 if (m_frame->lastEventIsMouseUp())
645 d->mousePressed = false;
649 // This method only exists for platforms that don't know how to deliver
650 void FrameView::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
652 if (!m_frame->document())
655 RefPtr<FrameView> protector(this);
657 // We get this instead of a second mouse-up
658 d->mousePressed = false;
659 d->m_currentMousePosition = mouseEvent.pos();
661 MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
662 Frame* subframe = subframeForTargetNode(mev.targetNode());
663 if (subframe && passMousePressEventToSubframe(mev, subframe))
666 d->clickCount = mouseEvent.clickCount();
667 bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
669 if (mev.targetNode() == d->clickNode)
670 dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
673 m_frame->handleMouseReleaseEvent(mev);
678 static bool isSubmitImage(Node *node)
680 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE;
683 // Returns true if the node's editable block is not current focused for editing
684 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
686 return frame->selectionController()->rootEditableElement() != node->rootEditableElement();
689 static Cursor selectCursor(const MouseEventWithHitTestResults& event, Frame* frame, bool mousePressed, PlatformScrollbar* scrollbar)
691 // During selection, use an I-beam no matter what we're over.
692 if (mousePressed && frame->selectionController()->isCaretOrRange())
693 return iBeamCursor();
695 Node* node = event.targetNode();
696 RenderObject* renderer = node ? node->renderer() : 0;
697 RenderStyle* style = renderer ? renderer->style() : 0;
699 if (style && style->cursors()) {
700 const CursorList* cursors = style->cursors();
701 for (unsigned i = 0; i < cursors->size(); ++i) {
702 CachedImage* cimage = (*cursors)[i].cursorImage;
703 IntPoint hotSpot = (*cursors)[i].hotSpot;
706 Element* e = node->document()->getElementById((*cursors)[i].cursorFragmentId);
707 if (e && e->hasTagName(cursorTag)) {
708 hotSpot.setX(int(static_cast<SVGCursorElement*>(e)->x()->value()));
709 hotSpot.setY(int(static_cast<SVGCursorElement*>(e)->y()->value()));
710 cimage = static_cast<SVGCursorElement*>(e)->cachedImage();
716 if (cimage->image()->isNull())
718 if (!cimage->isErrorImage()) {
719 return Cursor(cimage->image(), hotSpot);
724 switch (style ? style->cursor() : CURSOR_AUTO) {
726 bool editable = (node && node->isContentEditable());
727 bool editableLinkEnabled = false;
729 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
731 switch(frame->settings()->editableLinkBehavior()) {
733 case Settings::EditableLinkDefaultBehavior:
734 case Settings::EditableLinkAlwaysLive:
735 editableLinkEnabled = true;
738 case Settings::EditableLinkLiveWhenNotFocused:
739 editableLinkEnabled = nodeIsNotBeingEdited(node, frame) || event.event().shiftKey();
742 case Settings::EditableLinkOnlyLiveWithShiftKey:
743 editableLinkEnabled = event.event().shiftKey();
748 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
750 RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0;
751 bool inResizer = false;
752 if (frame->view() && layer && layer->isPointInResizeControl(frame->view()->windowToContents(event.event().pos())))
754 if ((editable || (renderer && renderer->isText() && renderer->canSelect())) && !inResizer && !scrollbar)
755 return iBeamCursor();
756 return pointerCursor();
759 return crossCursor();
764 case CURSOR_ALL_SCROLL:
766 case CURSOR_E_RESIZE:
767 return eastResizeCursor();
768 case CURSOR_W_RESIZE:
769 return westResizeCursor();
770 case CURSOR_N_RESIZE:
771 return northResizeCursor();
772 case CURSOR_S_RESIZE:
773 return southResizeCursor();
774 case CURSOR_NE_RESIZE:
775 return northEastResizeCursor();
776 case CURSOR_SW_RESIZE:
777 return southWestResizeCursor();
778 case CURSOR_NW_RESIZE:
779 return northWestResizeCursor();
780 case CURSOR_SE_RESIZE:
781 return southEastResizeCursor();
782 case CURSOR_NS_RESIZE:
783 return northSouthResizeCursor();
784 case CURSOR_EW_RESIZE:
785 return eastWestResizeCursor();
786 case CURSOR_NESW_RESIZE:
787 return northEastSouthWestResizeCursor();
788 case CURSOR_NWSE_RESIZE:
789 return northWestSouthEastResizeCursor();
790 case CURSOR_COL_RESIZE:
791 return columnResizeCursor();
792 case CURSOR_ROW_RESIZE:
793 return rowResizeCursor();
795 return iBeamCursor();
801 return pointerCursor();
803 return pointerCursor();
806 void FrameView::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent)
808 // in Radar 3703768 we saw frequent crashes apparently due to the
809 // part being null here, which seems impossible, so check for nil
810 // but also assert so that we can try to figure this out in debug
811 // builds, if it happens.
813 if (!m_frame || !m_frame->document())
816 RefPtr<FrameView> protector(this);
817 d->m_currentMousePosition = mouseEvent.pos();
819 if (d->hoverTimer.isActive())
820 d->hoverTimer.stop();
822 if (d->resizingFrameSet) {
823 dispatchMouseEvent(mousemoveEvent, d->resizingFrameSet.get(), false, 0, mouseEvent, false);
827 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
828 // if we are allowed to select.
829 // This means that :hover and :active freeze in the state they were in when the mouse
830 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
831 MouseEventWithHitTestResults mev = prepareMouseEvent(d->mousePressed && m_frame->mouseDownMayStartSelect(),
832 d->mousePressed, true, mouseEvent);
834 if (d->oldSubframe && d->oldSubframe->tree()->isDescendantOf(m_frame.get()))
835 passMouseMoveEventToSubframe(mev, d->oldSubframe.get());
837 bool swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
839 PlatformScrollbar* scrollbar = scrollbarUnderMouse(mouseEvent);
841 scrollbar = mev.scrollbar();
843 if (d->oldScrollbar != scrollbar) {
844 // Send mouse exited to the old scrollbar.
846 d->oldScrollbar->handleMouseOutEvent(mouseEvent);
847 d->oldScrollbar = scrollbar;
850 if (d->m_resizeLayer && d->m_resizeLayer->inResizeMode())
851 d->m_resizeLayer->resize(mouseEvent, d->offsetFromResizeCorner);
854 m_frame->handleMouseMoveEvent(mev);
856 RefPtr<Frame> newSubframe = subframeForTargetNode(mev.targetNode());
858 if (d->oldSubframe != newSubframe)
859 passMouseMoveEventToSubframe(mev, newSubframe.get());
861 if (scrollbar && !d->mousePressed)
862 scrollbar->handleMouseMoveEvent(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
863 if (!d->m_resizeLayer || !d->m_resizeLayer->inResizeMode())
864 setCursor(selectCursor(mev, m_frame.get(), d->mousePressed, scrollbar));
867 d->oldSubframe = newSubframe;
870 void FrameView::invalidateClick()
876 bool FrameView::mousePressed()
878 return d->mousePressed;
881 void FrameView::setMousePressed(bool pressed)
883 d->mousePressed = pressed;
886 void FrameView::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
888 if (!m_frame->document())
891 RefPtr<FrameView> protector(this);
893 d->mousePressed = false;
894 d->m_currentMousePosition = mouseEvent.pos();
896 if (d->resizingFrameSet) {
897 dispatchMouseEvent(mouseupEvent, d->resizingFrameSet.get(), true, d->clickCount, mouseEvent, false);
901 MouseEventWithHitTestResults mev = prepareMouseEvent(false, false, false, mouseEvent);
902 Frame* subframe = subframeForTargetNode(mev.targetNode());
903 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
906 bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
908 if (d->clickCount > 0 && mev.targetNode() == d->clickNode)
909 dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
911 if (d->m_resizeLayer) {
912 d->m_resizeLayer->setInResizeMode(false);
913 d->m_resizeLayer = 0;
917 m_frame->handleMouseReleaseEvent(mev);
922 bool FrameView::dispatchDragEvent(const AtomicString& eventType, Node *dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
924 IntPoint contentsPos = windowToContents(event.pos());
926 RefPtr<MouseEvent> me = new MouseEvent(eventType,
927 true, true, m_frame->document()->defaultView(),
928 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(),
929 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
932 ExceptionCode ec = 0;
933 EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec, true);
934 return me->defaultPrevented();
937 bool FrameView::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
941 MouseEventWithHitTestResults mev = prepareMouseEvent(true, false, false, event);
943 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
944 Node* newTarget = mev.targetNode();
945 if (newTarget && newTarget->isTextNode())
946 newTarget = newTarget->parentNode();
948 newTarget = newTarget->shadowAncestorNode();
950 if (d->dragTarget != newTarget) {
951 // FIXME: this ordering was explicitly chosen to match WinIE. However,
952 // it is sometimes incorrect when dragging within subframes, as seen with
953 // LayoutTests/fast/events/drag-in-frames.html.
955 if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
956 accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->view()->updateDragAndDrop(event, clipboard);
958 accept = dispatchDragEvent(dragenterEvent, newTarget, event, clipboard);
961 if (d->dragTarget->hasTagName(frameTag) || d->dragTarget->hasTagName(iframeTag))
962 accept = static_cast<HTMLFrameElementBase*>(d->dragTarget.get())->contentFrame()->view()->updateDragAndDrop(event, clipboard);
964 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
967 if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
968 accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->view()->updateDragAndDrop(event, clipboard);
970 accept = dispatchDragEvent(dragoverEvent, newTarget, event, clipboard);
972 d->dragTarget = newTarget;
977 void FrameView::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
980 if (d->dragTarget->hasTagName(frameTag) || d->dragTarget->hasTagName(iframeTag))
981 static_cast<HTMLFrameElementBase*>(d->dragTarget.get())->contentFrame()->view()->cancelDragAndDrop(event, clipboard);
983 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
987 bool FrameView::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
991 if (d->dragTarget->hasTagName(frameTag) || d->dragTarget->hasTagName(iframeTag))
992 accept = static_cast<HTMLFrameElementBase*>(d->dragTarget.get())->contentFrame()->view()->performDragAndDrop(event, clipboard);
994 accept = dispatchDragEvent(dropEvent, d->dragTarget.get(), event, clipboard);
999 Node* FrameView::nodeUnderMouse() const
1001 return d->underMouse.get();
1004 bool FrameView::scrollTo(const IntRect& bounds)
1009 xe = bounds.right() - 1;
1010 ye = bounds.bottom() - 1;
1015 int curHeight = visibleHeight();
1016 int curWidth = visibleWidth();
1018 if (ye - y>curHeight-d->borderY)
1019 ye = y + curHeight - d->borderY;
1021 if (xe - x>curWidth-d->borderX)
1022 xe = x + curWidth - d->borderX;
1024 // is xpos of target left of the view's border?
1025 if (x < contentsX() + d->borderX)
1026 deltax = x - contentsX() - d->borderX;
1027 // is xpos of target right of the view's right border?
1028 else if (xe + d->borderX > contentsX() + curWidth)
1029 deltax = xe + d->borderX - (contentsX() + curWidth);
1033 // is ypos of target above upper border?
1034 if (y < contentsY() + d->borderY)
1035 deltay = y - contentsY() - d->borderY;
1036 // is ypos of target below lower border?
1037 else if (ye + d->borderY > contentsY() + curHeight)
1038 deltay = ye + d->borderY - (contentsY() + curHeight);
1042 int maxx = curWidth - d->borderX;
1043 int maxy = curHeight - d->borderY;
1045 int scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax > -maxx ? deltax : -maxx);
1046 int scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay > -maxy ? deltay : -maxy);
1048 if (contentsX() + scrollX < 0)
1049 scrollX = -contentsX();
1050 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
1051 scrollX = contentsWidth() - visibleWidth() - contentsX();
1053 if (contentsY() + scrollY < 0)
1054 scrollY = -contentsY();
1055 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
1056 scrollY = contentsHeight() - visibleHeight() - contentsY();
1058 scrollBy(scrollX, scrollY);
1060 // generate abs(scroll.)
1066 return scrollX != maxx && scrollY != maxy;
1069 bool FrameView::advanceFocus(KeyboardEvent* event)
1071 Document* document = m_frame->document();
1075 Node* node = event->shiftKey()
1076 ? document->previousFocusNode(document->focusNode(), event)
1077 : document->nextFocusNode(document->focusNode(), event);
1080 // FIXME: Need to support tabbing out of the document to the UI.
1083 if (!node->isElementNode())
1084 // FIXME: May need a way to focus a document here.
1087 static_cast<Element*>(node)->focus();
1091 void FrameView::setMediaType(const String& mediaType)
1093 d->m_mediaType = mediaType;
1096 String FrameView::mediaType() const
1098 // See if we have an override type.
1099 String overrideType = m_frame->loader()->overrideMediaType();
1100 if (!overrideType.isNull())
1101 return overrideType;
1102 return d->m_mediaType;
1105 bool FrameView::useSlowRepaints() const
1107 return d->useSlowRepaints || d->slowRepaintObjectCount > 0;
1110 void FrameView::setUseSlowRepaints()
1112 d->useSlowRepaints = true;
1113 setStaticBackground(true);
1116 void FrameView::addSlowRepaintObject()
1118 if (d->slowRepaintObjectCount == 0)
1119 setStaticBackground(true);
1120 d->slowRepaintObjectCount++;
1123 void FrameView::removeSlowRepaintObject()
1125 d->slowRepaintObjectCount--;
1126 if (d->slowRepaintObjectCount == 0)
1127 setStaticBackground(d->useSlowRepaints);
1130 void FrameView::setScrollbarsMode(ScrollbarMode mode)
1135 ScrollView::setScrollbarsMode(mode);
1138 void FrameView::setVScrollbarMode(ScrollbarMode mode)
1141 ScrollView::setVScrollbarMode(mode);
1144 void FrameView::setHScrollbarMode(ScrollbarMode mode)
1147 ScrollView::setHScrollbarMode(mode);
1150 void FrameView::restoreScrollbar()
1152 suppressScrollbars(false);
1155 void FrameView::setResizingFrameSet(HTMLFrameSetElement* frameSet)
1157 d->resizingFrameSet = frameSet;
1160 void FrameView::scrollPointRecursively(int x, int y)
1162 if (frame()->prohibitsScrolling())
1165 ScrollView::scrollPointRecursively(x, y);
1168 void FrameView::setContentsPos(int x, int y)
1170 if (frame()->prohibitsScrolling())
1173 ScrollView::setContentsPos(x, y);
1176 MouseEventWithHitTestResults FrameView::prepareMouseEvent(bool readonly, bool active, bool mouseMove, const PlatformMouseEvent& mev)
1179 ASSERT(m_frame->document());
1181 IntPoint vPoint = windowToContents(mev.pos());
1182 return m_frame->document()->prepareMouseEvent(readonly, active, mouseMove, vPoint, mev);
1185 bool FrameView::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool cancelable,
1186 int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1188 // if the target node is a text node, dispatch on the parent node - rdar://4196646
1189 if (targetNode && targetNode->isTextNode())
1190 targetNode = targetNode->parentNode();
1192 targetNode = targetNode->shadowAncestorNode();
1193 d->underMouse = targetNode;
1195 // mouseout/mouseover
1197 if (d->oldUnder && d->oldUnder->document() != frame()->document()) {
1199 d->oldScrollbar = 0;
1202 if (d->oldUnder != targetNode) {
1203 // send mouseout event to the old node
1205 EventTargetNodeCast(d->oldUnder.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, targetNode);
1206 // send mouseover event to the new node
1208 EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, d->oldUnder.get());
1210 d->oldUnder = targetNode;
1213 bool swallowEvent = false;
1216 swallowEvent = EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1218 if (!swallowEvent && eventType == mousedownEvent) {
1219 // Blur current focus node when a link/button is clicked; this
1220 // is expected by some sites that rely on onChange handlers running
1221 // from form fields before the button click is processed.
1222 Node* node = targetNode;
1223 RenderObject* renderer = node ? node->renderer() : 0;
1225 // Walk up the render tree to search for a node to focus.
1226 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1228 node = renderer->element();
1229 if (node && node->isFocusable())
1231 renderer = renderer->parent();
1233 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
1234 // if the page already set it (e.g., by canceling default behavior).
1235 if (node && node->isMouseFocusable()) {
1236 if (!m_frame->document()->setFocusNode(node))
1237 swallowEvent = true;
1238 } else if (!node || !node->focused()) {
1239 if (!m_frame->document()->setFocusNode(0))
1240 swallowEvent = true;
1244 // It's ok to shift focus to this view now that we know that no focus change got blocked.
1245 if (!swallowEvent && !hasFocus())
1250 return swallowEvent;
1253 void FrameView::setIgnoreWheelEvents(bool e)
1255 d->ignoreWheelEvents = e;
1258 void FrameView::handleWheelEvent(PlatformWheelEvent& e)
1260 Document *doc = m_frame->document();
1262 RenderObject *docRenderer = doc->renderer();
1264 IntPoint vPoint = windowToContents(e.pos());
1266 HitTestRequest hitTestRequest(true, false);
1267 HitTestResult hitTestResult(vPoint);
1268 doc->renderer()->layer()->hitTest(hitTestRequest, hitTestResult);
1269 Node *node = hitTestResult.innerNode();
1270 Frame* subframe = subframeForTargetNode(node);
1271 if (subframe && passWheelEventToSubframe(e, subframe)) {
1277 node = node->shadowAncestorNode();
1278 EventTargetNodeCast(node)->dispatchWheelEvent(e);
1282 if (node->renderer()) {
1283 // Just break up into two scrolls if we need to. Diagonal movement on
1284 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
1285 if (e.deltaX() && node->renderer()->scroll(e.deltaX() < 0 ? ScrollRight : ScrollLeft, ScrollByWheel,
1286 e.deltaX() < 0 ? -e.deltaX() : e.deltaX()))
1288 if (e.deltaY() && node->renderer()->scroll(e.deltaY() < 0 ? ScrollDown : ScrollUp, ScrollByWheel,
1289 e.deltaY() < 0 ? -e.deltaY() : e.deltaY()))
1292 if (!e.isAccepted())
1300 void FrameView::repaintRectangle(const IntRect& r, bool immediate)
1302 updateContents(r, immediate);
1305 void FrameView::layoutTimerFired(Timer<FrameView>*)
1307 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1308 if (m_frame->document() && !m_frame->document()->ownerElement())
1309 printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
1314 void FrameView::hoverTimerFired(Timer<FrameView>*)
1316 d->hoverTimer.stop();
1317 prepareMouseEvent(false, false, true, PlatformMouseEvent(PlatformMouseEvent::currentEvent));
1320 void FrameView::scheduleRelayout()
1322 if (d->layoutRoot) {
1323 if (d->layoutRoot->renderer())
1324 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
1327 if (!d->layoutSchedulingEnabled)
1330 if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
1333 int delay = m_frame->document()->minimumLayoutDelay();
1334 if (d->layoutTimer.isActive() && d->delayedLayout && !delay)
1335 unscheduleRelayout();
1336 if (d->layoutTimer.isActive())
1339 d->delayedLayout = delay != 0;
1341 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1342 if (!m_frame->document()->ownerElement())
1343 printf("Scheduling layout for %d\n", delay);
1346 d->layoutTimer.startOneShot(delay * 0.001);
1349 void FrameView::scheduleRelayoutOfSubtree(Node* n)
1351 if (!d->layoutSchedulingEnabled || m_frame->document() && m_frame->document()->renderer() && m_frame->document()->renderer()->needsLayout()) {
1353 n->renderer()->markContainingBlocksForLayout(false);
1357 if (layoutPending()) {
1358 if (d->layoutRoot != n) {
1359 // Just do a full relayout
1360 if (d->layoutRoot && d->layoutRoot->renderer())
1361 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
1364 n->renderer()->markContainingBlocksForLayout(false);
1367 int delay = m_frame->document()->minimumLayoutDelay();
1369 d->delayedLayout = delay != 0;
1370 d->layoutTimer.startOneShot(delay * 0.001);
1374 bool FrameView::layoutPending() const
1376 return d->layoutTimer.isActive();
1379 bool FrameView::haveDelayedLayoutScheduled()
1381 return d->layoutTimer.isActive() && d->delayedLayout;
1384 void FrameView::unscheduleRelayout()
1386 if (!d->layoutTimer.isActive())
1389 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1390 if (m_frame->document() && !m_frame->document()->ownerElement())
1391 printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
1394 d->layoutTimer.stop();
1395 d->delayedLayout = false;
1398 bool FrameView::isTransparent() const
1400 return d->isTransparent;
1403 void FrameView::setTransparent(bool isTransparent)
1405 d->isTransparent = isTransparent;
1408 Color FrameView::baseBackgroundColor() const
1410 return d->baseBackgroundColor;
1413 void FrameView::setBaseBackgroundColor(Color bc)
1417 d->baseBackgroundColor = bc;
1420 void FrameView::scheduleHoverStateUpdate()
1422 if (!d->hoverTimer.isActive())
1423 d->hoverTimer.startOneShot(0);
1426 void FrameView::setHasBorder(bool b)
1432 bool FrameView::hasBorder() const
1434 return d->m_hasBorder;
1437 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget, bool tempEvent)
1439 if (!d->m_scheduledEvents)
1440 d->m_scheduledEvents = new Vector<ScheduledEvent*>;
1442 ScheduledEvent *scheduledEvent = new ScheduledEvent;
1443 scheduledEvent->m_event = event;
1444 scheduledEvent->m_eventTarget = eventTarget;
1445 scheduledEvent->m_tempEvent = tempEvent;
1447 d->m_scheduledEvents->append(scheduledEvent);
1450 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
1452 if (!d->m_viewportRenderer)
1455 if (d->m_overflowStatusDirty) {
1456 d->horizontalOverflow = horizontalOverflow;
1457 d->m_verticalOverflow = verticalOverflow;
1458 d->m_overflowStatusDirty = false;
1463 bool horizontalOverflowChanged = (d->horizontalOverflow != horizontalOverflow);
1464 bool verticalOverflowChanged = (d->m_verticalOverflow != verticalOverflow);
1466 if (horizontalOverflowChanged || verticalOverflowChanged) {
1467 d->horizontalOverflow = horizontalOverflow;
1468 d->m_verticalOverflow = verticalOverflow;
1470 scheduleEvent(new OverflowEvent(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
1471 EventTargetNodeCast(d->m_viewportRenderer->element()), true);
1476 void FrameView::dispatchScheduledEvents()
1478 if (!d->m_scheduledEvents)
1481 Vector<ScheduledEvent*> scheduledEventsCopy = *d->m_scheduledEvents;
1482 d->m_scheduledEvents->clear();
1484 Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end();
1485 for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) {
1486 ScheduledEvent* scheduledEvent = *it;
1488 ExceptionCode ec = 0;
1490 // Only dispatch events to nodes that are in the document
1491 if (scheduledEvent->m_eventTarget->inDocument())
1492 scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event, ec, scheduledEvent->m_tempEvent);
1494 delete scheduledEvent;
1498 IntRect FrameView::windowClipRect() const
1500 return windowClipRect(true);
1503 IntRect FrameView::windowClipRect(bool clipToContents) const
1505 // Set our clip rect to be our contents.
1508 clipRect = enclosingIntRect(visibleContentRect());
1510 clipRect = IntRect(contentsX(), contentsY(), width(), height());
1511 clipRect.setLocation(contentsToWindow(clipRect.location()));
1512 if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement())
1515 // Take our owner element and get the clip rect from the enclosing layer.
1516 Element* elt = m_frame->document()->ownerElement();
1517 RenderLayer* layer = elt->renderer()->enclosingLayer();
1518 // FIXME: layer should never be null, but sometimes seems to be anyway.
1521 FrameView* parentView = elt->document()->view();
1522 clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
1526 IntRect FrameView::windowClipRectForLayer(const RenderLayer* layer, bool clipToLayerContents) const
1528 // Apply the clip from the layer.
1530 if (clipToLayerContents)
1531 clipRect = layer->childrenClipRect();
1533 clipRect = layer->selfClipRect();
1535 clipRect.setLocation(contentsToWindow(clipRect.location()));
1537 // Now apply the clip from our view.
1538 clipRect.intersect(windowClipRect());
1540 // Return the result.