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"
34 #include "FrameTree.h"
35 #include "HTMLDocument.h"
36 #include "HTMLFrameSetElement.h"
37 #include "HTMLInputElement.h"
38 #include "HTMLNames.h"
40 #include "MouseEvent.h"
41 #include "MouseEventWithHitTestResults.h"
42 #include "OverflowEvent.h"
43 #include "PlatformKeyboardEvent.h"
44 #include "PlatformScrollBar.h"
45 #include "PlatformWheelEvent.h"
46 #include "RenderArena.h"
47 #include "RenderPart.h"
48 #include "RenderText.h"
49 #include "RenderView.h"
50 #include "SelectionController.h"
52 #include "cssstyleselector.h"
55 #include "XLinkNames.h"
57 #include "SVGCursorElement.h"
58 #include "SVGLength.h"
63 using namespace EventNames;
64 using namespace HTMLNames;
66 using namespace SVGNames;
69 struct ScheduledEvent {
70 RefPtr<Event> m_event;
71 RefPtr<EventTargetNode> m_eventTarget;
75 class FrameViewPrivate {
77 FrameViewPrivate(FrameView* view)
79 , layoutTimer(view, &FrameView::layoutTimerFired)
80 , hoverTimer(view, &FrameView::hoverTimerFired)
82 , m_mediaType("screen")
83 , m_scheduledEvents(0)
84 , m_overflowStatusDirty(true)
85 , m_viewportRenderer(0)
88 isTransparent = false;
89 baseBackgroundColor = Color::white;
90 vmode = hmode = ScrollBarAuto;
91 needToInitScrollBars = true;
97 delete m_scheduledEvents;
106 useSlowRepaints = false;
107 slowRepaintObjectCount = 0;
109 borderTouched = false;
110 scrollBarMoved = false;
111 ignoreWheelEvents = false;
116 scrollingSelf = false;
119 delayedLayout = false;
120 mousePressed = false;
121 doFullRepaint = true;
122 layoutSchedulingEnabled = true;
127 repaintRects->clear();
128 resizingFrameSet = 0;
130 m_currentMousePosition = IntPoint();
133 RefPtr<Node> underMouse;
134 RefPtr<Node> oldUnder;
135 RefPtr<Frame> oldSubframe;
136 RefPtr<PlatformScrollBar> oldScrollBar;
138 bool borderTouched : 1;
139 bool borderStart : 1;
140 bool scrollBarMoved : 1;
141 bool doFullRepaint : 1;
142 bool m_hasBorder : 1;
147 bool useSlowRepaints;
148 unsigned slowRepaintObjectCount;
149 bool ignoreWheelEvents;
151 int borderX, borderY;
153 RefPtr<Node> clickNode;
156 Timer<FrameView> layoutTimer;
158 RefPtr<Node> layoutRoot;
160 bool layoutSchedulingEnabled;
164 bool needToInitScrollBars;
167 Color baseBackgroundColor;
169 Timer<FrameView> hoverTimer;
171 RenderLayer* m_resizeLayer;
172 IntSize offsetFromResizeCorner;
174 // Used by objects during layout to communicate repaints that need to take place only
175 // after all layout has been completed.
176 DeprecatedPtrList<RenderObject::RepaintInfo>* repaintRects;
178 RefPtr<Node> dragTarget;
179 RefPtr<HTMLFrameSetElement> resizingFrameSet;
183 Vector<ScheduledEvent*>* m_scheduledEvents;
185 bool m_overflowStatusDirty;
186 bool horizontalOverflow;
187 bool m_verticalOverflow;
188 RenderObject* m_viewportRenderer;
190 IntPoint m_currentMousePosition;
193 FrameView::FrameView(Frame *frame)
196 , d(new FrameViewPrivate(this))
203 FrameView::~FrameView()
207 ASSERT(m_refCount == 0);
209 if (d->hoverTimer.isActive())
210 d->hoverTimer.stop();
212 // FIXME: Is this really the right place to call detach on the document?
213 if (Document* doc = m_frame->document())
215 if (RenderPart* renderer = m_frame->ownerRenderer())
216 renderer->setWidget(0);
223 bool FrameView::isFrameView() const
228 void FrameView::clearPart()
233 void FrameView::resetScrollBars()
235 // Reset the document's scrollbars back to our defaults before we yield the floor.
236 d->firstLayout = true;
237 suppressScrollBars(true);
238 ScrollView::setVScrollBarMode(d->vmode);
239 ScrollView::setHScrollBarMode(d->hmode);
240 suppressScrollBars(false);
243 void FrameView::init()
245 m_margins = IntSize(-1, -1); // undefined
249 void FrameView::clear()
251 setStaticBackground(false);
253 m_frame->selectionController()->clear();
257 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
258 if (d->layoutTimer.isActive() && m_frame->document() && !m_frame->document()->ownerElement())
259 printf("Killing the layout timer from a clear at %d\n", m_frame->document()->elapsedTime());
261 d->layoutTimer.stop();
265 suppressScrollBars(true);
268 bool FrameView::didFirstLayout() const
270 return !d->firstLayout;
273 void FrameView::initScrollBars()
275 if (!d->needToInitScrollBars)
277 d->needToInitScrollBars = false;
278 setScrollBarsMode(hScrollBarMode());
281 void FrameView::setMarginWidth(int w)
283 // make it update the rendering area when set
284 m_margins.setWidth(w);
287 void FrameView::setMarginHeight(int h)
289 // make it update the rendering area when set
290 m_margins.setHeight(h);
293 void FrameView::adjustViewSize()
295 if (m_frame->document()) {
296 Document *document = m_frame->document();
298 RenderView* root = static_cast<RenderView *>(document->renderer());
302 int docw = root->docWidth();
303 int doch = root->docHeight();
305 resizeContents(docw, doch);
309 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollBarMode& hMode, ScrollBarMode& vMode)
311 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
312 // overflow:hidden and overflow:scroll on <body> as applying to the document's
313 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
314 // use the root element.
315 switch (o->style()->overflowX()) {
317 hMode = ScrollBarAlwaysOff;
320 hMode = ScrollBarAlwaysOn;
323 hMode = ScrollBarAuto;
326 // Don't set it at all.
330 switch (o->style()->overflowY()) {
332 vMode = ScrollBarAlwaysOff;
335 vMode = ScrollBarAlwaysOn;
338 vMode = ScrollBarAuto;
341 // Don't set it at all.
345 d->m_viewportRenderer = o;
348 int FrameView::layoutCount() const
350 return d->layoutCount;
353 bool FrameView::needsFullRepaint() const
355 return d->doFullRepaint;
358 void FrameView::addRepaintInfo(RenderObject* o, const IntRect& r)
360 if (!d->repaintRects) {
361 d->repaintRects = new DeprecatedPtrList<RenderObject::RepaintInfo>;
362 d->repaintRects->setAutoDelete(true);
365 d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
368 Node* FrameView::layoutRoot() const
370 return layoutPending() ? 0 : d->layoutRoot.get();
373 void FrameView::layout(bool allowSubtree)
375 d->layoutTimer.stop();
376 d->delayedLayout = false;
378 // Protect the view from being deleted during layout (in recalcStyle)
379 RefPtr<FrameView> protector(this);
382 // FIXME: Do we need to set m_size.width here?
383 // FIXME: Should we set m_size.height here too?
384 m_size.setWidth(visibleWidth());
388 if (!allowSubtree && d->layoutRoot) {
389 if (d->layoutRoot->renderer())
390 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
394 bool subtree = d->layoutRoot;
395 Document* document = m_frame->document();
397 // FIXME: Should we set m_size.height here too?
398 m_size.setWidth(visibleWidth());
402 Node* rootNode = subtree ? d->layoutRoot.get() : document;
403 d->layoutSchedulingEnabled = false;
405 // Always ensure our style info is up-to-date. This can happen in situations where
406 // the layout beats any sort of style recalc update that needs to occur.
407 if (document->hasChangedChild())
408 document->recalcStyle();
410 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
411 // so there's no point to continuiing to layout
412 if (protector->hasOneRef())
415 RenderObject* root = rootNode->renderer();
417 // FIXME: Do we need to set m_size here?
418 d->layoutSchedulingEnabled = true;
422 ScrollBarMode hMode = d->hmode;
423 ScrollBarMode vMode = d->vmode;
426 Document* document = static_cast<Document*>(rootNode);
427 RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
428 if (document->isHTMLDocument()) {
429 Node *body = static_cast<HTMLDocument*>(document)->body();
430 if (body && body->renderer()) {
431 if (body->hasTagName(framesetTag)) {
432 body->renderer()->setNeedsLayout(true);
433 vMode = ScrollBarAlwaysOff;
434 hMode = ScrollBarAlwaysOff;
435 } else if (body->hasTagName(bodyTag)) {
436 if (!d->firstLayout && m_size.height() != visibleHeight() && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight())
437 body->renderer()->setChildNeedsLayout(true);
438 // It's sufficient to just check one overflow direction, since it's illegal to have visible in only one direction.
439 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE ? body->renderer() : rootRenderer;
440 applyOverflowToViewport(o, hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
443 } else if (rootRenderer)
444 applyOverflowToViewport(rootRenderer, hMode, vMode); // XML/XHTML UAs use the root element.
445 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
446 if (d->firstLayout && !document->ownerElement())
447 printf("Elapsed time before first layout: %d\n", document->elapsedTime());
451 d->doFullRepaint = !subtree && (d->firstLayout || static_cast<RenderView*>(root)->printingMode());
453 d->repaintRects->clear();
455 bool didFirstLayout = false;
457 // Now set our scrollbar state for the layout.
458 ScrollBarMode currentHMode = hScrollBarMode();
459 ScrollBarMode currentVMode = vScrollBarMode();
461 if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
462 suppressScrollBars(true);
463 if (d->firstLayout) {
464 d->firstLayout = false;
465 didFirstLayout = true;
467 // Set the initial vMode to AlwaysOn if we're auto.
468 if (vMode == ScrollBarAuto)
469 ScrollView::setVScrollBarMode(ScrollBarAlwaysOn); // This causes a vertical scrollbar to appear.
470 // Set the initial hMode to AlwaysOff if we're auto.
471 if (hMode == ScrollBarAuto)
472 ScrollView::setHScrollBarMode(ScrollBarAlwaysOff); // This causes a horizontal scrollbar to disappear.
476 ScrollView::setScrollBarsMode(hMode);
478 ScrollView::setHScrollBarMode(hMode);
479 ScrollView::setVScrollBarMode(vMode);
482 suppressScrollBars(false, true);
485 IntSize oldSize = m_size;
487 m_size = IntSize(visibleWidth(), visibleHeight());
489 if (oldSize != m_size)
490 d->doFullRepaint = true;
493 RenderLayer* layer = root->enclosingLayer();
495 if (!d->doFullRepaint) {
496 layer->checkForRepaintOnResize();
497 root->repaintObjectsBeforeLayout();
501 if (root->recalcMinMax())
502 root->recalcMinMaxWidths();
507 m_frame->invalidateSelection();
509 d->layoutSchedulingEnabled=true;
511 if (!subtree && !static_cast<RenderView*>(root)->printingMode())
512 resizeContents(layer->width(), layer->height());
514 // Now update the positions of all layers.
515 layer->updateLayerPositions(d->doFullRepaint);
517 // We update our widget positions right after doing a layout.
519 static_cast<RenderView*>(root)->updateWidgetPositions();
521 if (d->repaintRects && !d->repaintRects->isEmpty()) {
522 // FIXME: Could optimize this and have objects removed from this list
523 // if they ever do full repaints.
524 RenderObject::RepaintInfo* r;
525 DeprecatedPtrListIterator<RenderObject::RepaintInfo> it(*d->repaintRects);
526 for (; (r = it.current()); ++it)
527 r->m_object->repaintRectangle(r->m_repaintRect);
528 d->repaintRects->clear();
534 if (AXObjectCache::accessibilityEnabled())
535 root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
536 updateDashboardRegions();
540 m_frame->didFirstLayout();
542 if (root->needsLayout()) {
546 setStaticBackground(useSlowRepaints());
548 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
549 updateOverflowStatus(visibleWidth() < contentsWidth(),
550 visibleHeight() < contentsHeight());
552 // Dispatch events scheduled during layout
553 dispatchScheduledEvents();
561 static Frame* subframeForTargetNode(Node* node)
566 RenderObject* renderer = node->renderer();
567 if (!renderer || !renderer->isWidget())
570 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
571 if (!widget || !widget->isFrameView())
574 return static_cast<FrameView*>(widget)->frame();
577 IntPoint FrameView::currentMousePosition() const
579 return d->m_currentMousePosition;
582 void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
584 if (!m_frame->document())
587 RefPtr<FrameView> protector(this);
589 d->mousePressed = true;
590 d->m_currentMousePosition = windowToContents(mouseEvent.pos());
592 MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
594 Frame* subframe = subframeForTargetNode(mev.targetNode());
595 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
600 d->clickCount = mouseEvent.clickCount();
601 d->clickNode = mev.targetNode();
603 RenderLayer* layer = d->clickNode->renderer()? d->clickNode->renderer()->enclosingLayer() : 0;
604 IntPoint p = windowToContents(mouseEvent.pos());
605 if (layer && layer->isPointInResizeControl(p)) {
606 layer->setInResizeMode(true);
607 d->m_resizeLayer = layer;
608 d->offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
613 bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
616 // Refetch the event target node if it currently is the shadow node inside an <input> element.
617 // If a mouse event handler changes the input element type to one that has a widget associated,
618 // we'd like to Frame::handleMousePressEvent to pass the event to the widget and thus the
619 // event target node can't still be the shadow node.
620 if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag))
621 mev = prepareMouseEvent(true, true, false, mouseEvent);
623 PlatformScrollBar* scrollbar = scrollbarUnderMouse(mouseEvent);
625 scrollbar = mev.scrollbar();
626 if (!scrollbar || !passMousePressEventToScrollbar(mev, scrollbar))
627 m_frame->handleMousePressEvent(mev);
629 // Many AK widgets run their own event loops and consume events while the mouse is down.
630 // When they finish, currentEvent is the mouseUp that they exited on. We need to update
631 // the khtml state with this mouseUp, which khtml never saw.
632 // If this event isn't a mouseUp, we assume that the mouseUp will be coming later. There
633 // is a hole here if the widget consumes the mouseUp and subsequent events.
634 if (m_frame->lastEventIsMouseUp())
635 d->mousePressed = false;
639 // This method only exists for platforms that don't know how to deliver
640 void FrameView::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
642 if (!m_frame->document())
645 RefPtr<FrameView> protector(this);
647 // We get this instead of a second mouse-up
648 d->mousePressed = false;
649 d->m_currentMousePosition = windowToContents(mouseEvent.pos());
651 MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
652 Frame* subframe = subframeForTargetNode(mev.targetNode());
653 if (subframe && passMousePressEventToSubframe(mev, subframe))
656 d->clickCount = mouseEvent.clickCount();
657 bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
659 if (mev.targetNode() == d->clickNode)
660 dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
663 m_frame->handleMouseReleaseEvent(mev);
668 static bool isSubmitImage(Node *node)
670 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE;
673 // Returns true if the node's editable block is not current focused for editing
674 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
676 return frame->selectionController()->rootEditableElement() != node->rootEditableElement();
679 static Cursor selectCursor(const MouseEventWithHitTestResults& event, Frame* frame, bool mousePressed, PlatformScrollBar* scrollbar)
681 // During selection, use an I-beam no matter what we're over.
682 if (mousePressed && frame->hasSelection())
683 return iBeamCursor();
685 Node* node = event.targetNode();
686 RenderObject* renderer = node ? node->renderer() : 0;
687 RenderStyle* style = renderer ? renderer->style() : 0;
689 if (style && style->cursors()) {
690 const CursorList* cursors = style->cursors();
691 for (unsigned i = 0; i < cursors->size(); ++i) {
692 CachedImage* cimage = (*cursors)[i].cursorImage;
693 IntPoint hotSpot = (*cursors)[i].hotSpot;
696 Element* e = node->document()->getElementById((*cursors)[i].cursorFragmentId);
697 if (e && e->hasTagName(cursorTag)) {
698 hotSpot.setX(int(static_cast<SVGCursorElement*>(e)->x()->value()));
699 hotSpot.setY(int(static_cast<SVGCursorElement*>(e)->y()->value()));
700 cimage = static_cast<SVGCursorElement*>(e)->cachedImage();
706 if (cimage->image()->isNull())
708 if (!cimage->isErrorImage()) {
709 return Cursor(cimage->image(), hotSpot);
714 switch (style ? style->cursor() : CURSOR_AUTO) {
716 bool editable = (node && node->isContentEditable());
717 bool editableLinkEnabled = false;
719 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
721 switch(frame->settings()->editableLinkBehavior()) {
723 case Settings::EditableLinkDefaultBehavior:
724 case Settings::EditableLinkAlwaysLive:
725 editableLinkEnabled = true;
728 case Settings::EditableLinkLiveWhenNotFocused:
729 editableLinkEnabled = nodeIsNotBeingEdited(node, frame) || event.event().shiftKey();
732 case Settings::EditableLinkOnlyLiveWithShiftKey:
733 editableLinkEnabled = event.event().shiftKey();
738 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
740 RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0;
741 bool inResizer = false;
742 if (frame->view() && layer && layer->isPointInResizeControl(frame->view()->windowToContents(event.event().pos())))
744 if ((editable || (renderer && renderer->isText() && renderer->canSelect())) && !inResizer && !scrollbar)
745 return iBeamCursor();
746 // FIXME: If the point is in a layer's overflow scrollbars, we should use the pointer cursor
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 = windowToContents(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 setCursor(selectCursor(mev, m_frame.get(), d->mousePressed, scrollbar));
854 d->oldSubframe = newSubframe;
857 void FrameView::invalidateClick()
863 bool FrameView::mousePressed()
865 return d->mousePressed;
868 void FrameView::setMousePressed(bool pressed)
870 d->mousePressed = pressed;
873 void FrameView::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
875 if (!m_frame->document())
878 RefPtr<FrameView> protector(this);
880 d->mousePressed = false;
881 d->m_currentMousePosition = windowToContents(mouseEvent.pos());
883 if (d->resizingFrameSet) {
884 dispatchMouseEvent(mouseupEvent, d->resizingFrameSet.get(), true, d->clickCount, mouseEvent, false);
888 MouseEventWithHitTestResults mev = prepareMouseEvent(false, false, false, mouseEvent);
889 Frame* subframe = subframeForTargetNode(mev.targetNode());
890 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
893 bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
895 if (d->clickCount > 0 && mev.targetNode() == d->clickNode)
896 dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
898 if (d->m_resizeLayer) {
899 d->m_resizeLayer->setInResizeMode(false);
900 d->m_resizeLayer = 0;
904 m_frame->handleMouseReleaseEvent(mev);
909 bool FrameView::dispatchDragEvent(const AtomicString& eventType, Node *dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
911 IntPoint contentsPos = windowToContents(event.pos());
913 RefPtr<MouseEvent> me = new MouseEvent(eventType,
914 true, true, m_frame->document()->defaultView(),
915 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(),
916 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
919 ExceptionCode ec = 0;
920 EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec, true);
921 return me->defaultPrevented();
924 bool FrameView::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
928 MouseEventWithHitTestResults mev = prepareMouseEvent(true, false, false, event);
930 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
931 Node* newTarget = mev.targetNode();
932 if (newTarget && newTarget->isTextNode())
933 newTarget = newTarget->parentNode();
935 newTarget = newTarget->shadowAncestorNode();
937 if (d->dragTarget != newTarget) {
938 // note this ordering is explicitly chosen to match WinIE
940 accept = dispatchDragEvent(dragenterEvent, newTarget, event, clipboard);
942 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
945 accept = dispatchDragEvent(dragoverEvent, newTarget, event, clipboard);
947 d->dragTarget = newTarget;
952 void FrameView::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
955 dispatchDragEvent(dragleaveEvent, d->dragTarget.get(), event, clipboard);
959 bool FrameView::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
963 accept = dispatchDragEvent(dropEvent, d->dragTarget.get(), event, clipboard);
968 Node* FrameView::nodeUnderMouse() const
970 return d->underMouse.get();
973 bool FrameView::scrollTo(const IntRect& bounds)
975 d->scrollingSelf = true; // so scroll events get ignored
980 xe = bounds.right() - 1;
981 ye = bounds.bottom() - 1;
986 int curHeight = visibleHeight();
987 int curWidth = visibleWidth();
989 if (ye - y>curHeight-d->borderY)
990 ye = y + curHeight - d->borderY;
992 if (xe - x>curWidth-d->borderX)
993 xe = x + curWidth - d->borderX;
995 // is xpos of target left of the view's border?
996 if (x < contentsX() + d->borderX)
997 deltax = x - contentsX() - d->borderX;
998 // is xpos of target right of the view's right border?
999 else if (xe + d->borderX > contentsX() + curWidth)
1000 deltax = xe + d->borderX - (contentsX() + curWidth);
1004 // is ypos of target above upper border?
1005 if (y < contentsY() + d->borderY)
1006 deltay = y - contentsY() - d->borderY;
1007 // is ypos of target below lower border?
1008 else if (ye + d->borderY > contentsY() + curHeight)
1009 deltay = ye + d->borderY - (contentsY() + curHeight);
1013 int maxx = curWidth - d->borderX;
1014 int maxy = curHeight - d->borderY;
1016 int scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax > -maxx ? deltax : -maxx);
1017 int scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay > -maxy ? deltay : -maxy);
1019 if (contentsX() + scrollX < 0)
1020 scrollX = -contentsX();
1021 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
1022 scrollX = contentsWidth() - visibleWidth() - contentsX();
1024 if (contentsY() + scrollY < 0)
1025 scrollY = -contentsY();
1026 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
1027 scrollY = contentsHeight() - visibleHeight() - contentsY();
1029 scrollBy(scrollX, scrollY);
1031 // generate abs(scroll.)
1037 d->scrollingSelf = false;
1039 return scrollX != maxx && scrollY != maxy;
1042 bool FrameView::advanceFocus(bool forward)
1044 Document* document = m_frame->document();
1048 Node* node = forward
1049 ? document->nextFocusNode(document->focusNode())
1050 : document->previousFocusNode(document->focusNode());
1053 // FIXME: Need to support tabbing out of the document to the UI.
1056 if (!node->isElementNode())
1057 // FIXME: May need a way to focus a document here.
1060 static_cast<Element*>(node)->focus();
1064 void FrameView::setMediaType(const String& mediaType)
1066 d->m_mediaType = mediaType;
1069 String FrameView::mediaType() const
1071 // See if we have an override type.
1072 String overrideType = m_frame->overrideMediaType();
1073 if (!overrideType.isNull())
1074 return overrideType;
1075 return d->m_mediaType;
1078 bool FrameView::useSlowRepaints() const
1080 return d->useSlowRepaints || d->slowRepaintObjectCount > 0;
1083 void FrameView::setUseSlowRepaints()
1085 d->useSlowRepaints = true;
1086 setStaticBackground(true);
1089 void FrameView::addSlowRepaintObject()
1091 if (d->slowRepaintObjectCount == 0)
1092 setStaticBackground(true);
1093 d->slowRepaintObjectCount++;
1096 void FrameView::removeSlowRepaintObject()
1098 d->slowRepaintObjectCount--;
1099 if (d->slowRepaintObjectCount == 0)
1100 setStaticBackground(d->useSlowRepaints);
1103 void FrameView::setScrollBarsMode(ScrollBarMode mode)
1108 ScrollView::setScrollBarsMode(mode);
1111 void FrameView::setVScrollBarMode(ScrollBarMode mode)
1114 ScrollView::setVScrollBarMode(mode);
1117 void FrameView::setHScrollBarMode(ScrollBarMode mode)
1120 ScrollView::setHScrollBarMode(mode);
1123 void FrameView::restoreScrollBar()
1125 suppressScrollBars(false);
1128 void FrameView::setResizingFrameSet(HTMLFrameSetElement* frameSet)
1130 d->resizingFrameSet = frameSet;
1133 void FrameView::scrollPointRecursively(int x, int y)
1135 if (frame()->prohibitsScrolling())
1138 ScrollView::scrollPointRecursively(x, y);
1141 void FrameView::setContentsPos(int x, int y)
1143 if (frame()->prohibitsScrolling())
1146 ScrollView::setContentsPos(x, y);
1149 MouseEventWithHitTestResults FrameView::prepareMouseEvent(bool readonly, bool active, bool mouseMove, const PlatformMouseEvent& mev)
1152 ASSERT(m_frame->document());
1154 IntPoint vPoint = windowToContents(mev.pos());
1155 return m_frame->document()->prepareMouseEvent(readonly, active, mouseMove, vPoint, mev);
1158 bool FrameView::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool cancelable,
1159 int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1161 // if the target node is a text node, dispatch on the parent node - rdar://4196646
1162 if (targetNode && targetNode->isTextNode())
1163 targetNode = targetNode->parentNode();
1165 targetNode = targetNode->shadowAncestorNode();
1166 d->underMouse = targetNode;
1168 // mouseout/mouseover
1170 if (d->oldUnder && d->oldUnder->document() != frame()->document()) {
1172 d->oldScrollBar = 0;
1175 if (d->oldUnder != targetNode) {
1176 // send mouseout event to the old node
1178 EventTargetNodeCast(d->oldUnder.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, targetNode);
1179 // send mouseover event to the new node
1181 EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, d->oldUnder.get());
1183 d->oldUnder = targetNode;
1186 bool swallowEvent = false;
1189 swallowEvent = EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1191 if (!swallowEvent && eventType == mousedownEvent) {
1192 // Blur current focus node when a link/button is clicked; this
1193 // is expected by some sites that rely on onChange handlers running
1194 // from form fields before the button click is processed.
1195 Node* node = targetNode;
1196 RenderObject* renderer = node ? node->renderer() : 0;
1198 // Walk up the render tree to search for a node to focus.
1199 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1201 node = renderer->element();
1202 if (node && node->isFocusable())
1204 renderer = renderer->parent();
1206 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
1207 // if the page already set it (e.g., by canceling default behavior).
1208 if (node && node->isMouseFocusable()) {
1209 if (!m_frame->document()->setFocusNode(node))
1210 swallowEvent = true;
1211 } else if (!node || !node->focused()) {
1212 if (!m_frame->document()->setFocusNode(0))
1213 swallowEvent = true;
1217 // It's ok to shift focus to this view now that we know that no focus change got blocked.
1218 if (!swallowEvent && !hasFocus())
1223 return swallowEvent;
1226 void FrameView::setIgnoreWheelEvents(bool e)
1228 d->ignoreWheelEvents = e;
1231 void FrameView::handleWheelEvent(PlatformWheelEvent& e)
1233 Document *doc = m_frame->document();
1235 RenderObject *docRenderer = doc->renderer();
1237 IntPoint vPoint = windowToContents(e.pos());
1239 RenderObject::NodeInfo hitTestResult(true, false);
1240 doc->renderer()->layer()->hitTest(hitTestResult, vPoint);
1241 Node *node = hitTestResult.innerNode();
1242 Frame* subframe = subframeForTargetNode(node);
1243 if (subframe && passWheelEventToSubframe(e, subframe)) {
1249 node = node->shadowAncestorNode();
1250 EventTargetNodeCast(node)->dispatchWheelEvent(e);
1254 if (node->renderer()) {
1255 // Just break up into two scrolls if we need to. Diagonal movement on
1256 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
1257 if (e.deltaX() && node->renderer()->scroll(e.deltaX() < 0 ? ScrollRight : ScrollLeft, ScrollByWheel,
1258 e.deltaX() < 0 ? -e.deltaX() : e.deltaX()))
1260 if (e.deltaY() && node->renderer()->scroll(e.deltaY() < 0 ? ScrollDown : ScrollUp, ScrollByWheel,
1261 e.deltaY() < 0 ? -e.deltaY() : e.deltaY()))
1264 if (!e.isAccepted())
1272 void FrameView::scrollBarMoved()
1274 // FIXME: Need to arrange for this to be called when the view is scrolled!
1275 if (!d->scrollingSelf)
1276 d->scrollBarMoved = true;
1279 void FrameView::repaintRectangle(const IntRect& r, bool immediate)
1281 updateContents(r, immediate);
1284 void FrameView::layoutTimerFired(Timer<FrameView>*)
1286 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1287 if (m_frame->document() && !m_frame->document()->ownerElement())
1288 printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
1293 void FrameView::hoverTimerFired(Timer<FrameView>*)
1295 d->hoverTimer.stop();
1296 prepareMouseEvent(false, false, true, PlatformMouseEvent(PlatformMouseEvent::currentEvent));
1299 void FrameView::scheduleRelayout()
1301 if (d->layoutRoot) {
1302 if (d->layoutRoot->renderer())
1303 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
1306 if (!d->layoutSchedulingEnabled)
1309 if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
1312 int delay = m_frame->document()->minimumLayoutDelay();
1313 if (d->layoutTimer.isActive() && d->delayedLayout && !delay)
1314 unscheduleRelayout();
1315 if (d->layoutTimer.isActive())
1318 d->delayedLayout = delay != 0;
1320 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1321 if (!m_frame->document()->ownerElement())
1322 printf("Scheduling layout for %d\n", delay);
1325 d->layoutTimer.startOneShot(delay * 0.001);
1328 void FrameView::scheduleRelayoutOfSubtree(Node* n)
1330 if (!d->layoutSchedulingEnabled || m_frame->document() && m_frame->document()->renderer() && m_frame->document()->renderer()->needsLayout()) {
1332 n->renderer()->markContainingBlocksForLayout(false);
1336 if (layoutPending()) {
1337 if (d->layoutRoot != n) {
1338 // Just do a full relayout
1339 if (d->layoutRoot && d->layoutRoot->renderer())
1340 d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
1343 n->renderer()->markContainingBlocksForLayout(false);
1346 int delay = m_frame->document()->minimumLayoutDelay();
1348 d->delayedLayout = delay != 0;
1349 d->layoutTimer.startOneShot(delay * 0.001);
1353 bool FrameView::layoutPending() const
1355 return d->layoutTimer.isActive();
1358 bool FrameView::haveDelayedLayoutScheduled()
1360 return d->layoutTimer.isActive() && d->delayedLayout;
1363 void FrameView::unscheduleRelayout()
1365 if (!d->layoutTimer.isActive())
1368 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1369 if (m_frame->document() && !m_frame->document()->ownerElement())
1370 printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
1373 d->layoutTimer.stop();
1374 d->delayedLayout = false;
1377 bool FrameView::isTransparent() const
1379 return d->isTransparent;
1382 void FrameView::setTransparent(bool isTransparent)
1384 d->isTransparent = isTransparent;
1387 Color FrameView::baseBackgroundColor() const
1389 return d->baseBackgroundColor;
1392 void FrameView::setBaseBackgroundColor(Color bc)
1396 d->baseBackgroundColor = bc;
1399 void FrameView::scheduleHoverStateUpdate()
1401 if (!d->hoverTimer.isActive())
1402 d->hoverTimer.startOneShot(0);
1405 void FrameView::setHasBorder(bool b)
1411 bool FrameView::hasBorder() const
1413 return d->m_hasBorder;
1416 void FrameView::cleared()
1419 if (RenderPart* renderer = m_frame->ownerRenderer())
1420 renderer->viewCleared();
1424 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget, bool tempEvent)
1426 if (!d->m_scheduledEvents)
1427 d->m_scheduledEvents = new Vector<ScheduledEvent*>;
1429 ScheduledEvent *scheduledEvent = new ScheduledEvent;
1430 scheduledEvent->m_event = event;
1431 scheduledEvent->m_eventTarget = eventTarget;
1432 scheduledEvent->m_tempEvent = tempEvent;
1434 d->m_scheduledEvents->append(scheduledEvent);
1437 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
1439 if (!d->m_viewportRenderer)
1442 if (d->m_overflowStatusDirty) {
1443 d->horizontalOverflow = horizontalOverflow;
1444 d->m_verticalOverflow = verticalOverflow;
1445 d->m_overflowStatusDirty = false;
1450 bool horizontalOverflowChanged = (d->horizontalOverflow != horizontalOverflow);
1451 bool verticalOverflowChanged = (d->m_verticalOverflow != verticalOverflow);
1453 if (horizontalOverflowChanged || verticalOverflowChanged) {
1454 d->horizontalOverflow = horizontalOverflow;
1455 d->m_verticalOverflow = verticalOverflow;
1457 scheduleEvent(new OverflowEvent(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
1458 EventTargetNodeCast(d->m_viewportRenderer->element()), true);
1463 void FrameView::dispatchScheduledEvents()
1465 if (!d->m_scheduledEvents)
1468 Vector<ScheduledEvent*> scheduledEventsCopy = *d->m_scheduledEvents;
1469 d->m_scheduledEvents->clear();
1471 Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end();
1472 for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) {
1473 ScheduledEvent* scheduledEvent = *it;
1475 ExceptionCode ec = 0;
1477 // Only dispatch events to nodes that are in the document
1478 if (scheduledEvent->m_eventTarget->inDocument())
1479 scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event, ec, scheduledEvent->m_tempEvent);
1481 delete scheduledEvent;