2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 * 1999 Lars Knoll <knoll@kde.org>
4 * 1999 Antti Koivisto <koivisto@kde.org>
5 * 2000 Dirk Mueller <mueller@kde.org>
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7 * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8 * (C) 2006 Alexey Proskuryakov (ap@nypop.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., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
27 #include "FrameView.h"
29 #include "AXObjectCache.h"
30 #include "CSSStyleSelector.h"
31 #include "ChromeClient.h"
32 #include "EventHandler.h"
33 #include "FloatRect.h"
34 #include "FocusController.h"
36 #include "FrameLoader.h"
37 #include "FrameLoaderClient.h"
38 #include "GraphicsContext.h"
39 #include "HTMLDocument.h"
40 #include "HTMLFrameElement.h"
41 #include "HTMLFrameSetElement.h"
42 #include "HTMLNames.h"
43 #include "OverflowEvent.h"
45 #include "RenderPart.h"
46 #include "RenderPartObject.h"
47 #include "RenderTheme.h"
48 #include "RenderView.h"
50 #include "SystemTime.h"
54 using namespace HTMLNames
;
56 double FrameView::sCurrentPaintTimeStamp
= 0.0;
58 struct ScheduledEvent
{
59 RefPtr
<Event
> m_event
;
60 RefPtr
<EventTargetNode
> m_eventTarget
;
63 class FrameViewPrivate
{
65 FrameViewPrivate(FrameView
* view
)
66 : m_slowRepaintObjectCount(0)
67 , m_layoutTimer(view
, &FrameView::layoutTimerFired
)
69 , m_postLayoutTasksTimer(view
, &FrameView::postLayoutTimerFired
)
70 , m_mediaType("screen")
72 , m_overflowStatusDirty(true)
73 , m_viewportRenderer(0)
74 , m_wasScrolledByUser(false)
75 , m_inProgrammaticScroll(false)
76 , m_shouldUpdateWhileOffscreen(true)
78 m_isTransparent
= false;
79 m_baseBackgroundColor
= Color::white
;
80 m_vmode
= m_hmode
= ScrollbarAuto
;
81 m_needToInitScrollbars
= true;
86 m_useSlowRepaints
= false;
91 m_delayedLayout
= false;
92 m_doFullRepaint
= true;
93 m_layoutSchedulingEnabled
= true;
96 m_nestedLayoutCount
= 0;
97 m_postLayoutTasksTimer
.stop();
99 m_firstLayoutCallbackPending
= false;
100 m_wasScrolledByUser
= false;
101 m_lastLayoutSize
= IntSize();
102 m_lastZoomFactor
= 1.0f
;
103 m_deferringRepaints
= 0;
105 m_repaintRect
= IntRect();
106 m_repaintRects
.clear();
107 m_paintRestriction
= PaintRestrictionNone
;
108 m_isPainting
= false;
111 bool m_doFullRepaint
;
113 ScrollbarMode m_vmode
;
114 ScrollbarMode m_hmode
;
115 bool m_useSlowRepaints
;
116 unsigned m_slowRepaintObjectCount
;
118 int m_borderX
, m_borderY
;
120 Timer
<FrameView
> m_layoutTimer
;
121 bool m_delayedLayout
;
122 RenderObject
* m_layoutRoot
;
124 bool m_layoutSchedulingEnabled
;
127 unsigned m_nestedLayoutCount
;
128 Timer
<FrameView
> m_postLayoutTasksTimer
;
129 bool m_firstLayoutCallbackPending
;
132 bool m_needToInitScrollbars
;
133 bool m_isTransparent
;
134 Color m_baseBackgroundColor
;
135 IntSize m_lastLayoutSize
;
136 float m_lastZoomFactor
;
140 unsigned m_enqueueEvents
;
141 Vector
<ScheduledEvent
*> m_scheduledEvents
;
143 bool m_overflowStatusDirty
;
144 bool m_horizontalOverflow
;
145 bool m_verticalOverflow
;
146 RenderObject
* m_viewportRenderer
;
148 bool m_wasScrolledByUser
;
149 bool m_inProgrammaticScroll
;
151 unsigned m_deferringRepaints
;
152 unsigned m_repaintCount
;
153 IntRect m_repaintRect
;
154 Vector
<IntRect
> m_repaintRects
;
156 bool m_shouldUpdateWhileOffscreen
;
158 RefPtr
<Node
> m_nodeToDraw
;
159 PaintRestriction m_paintRestriction
;
163 FrameView::FrameView(Frame
* frame
)
166 , d(new FrameViewPrivate(this))
172 FrameView::FrameView(Frame
* frame
, const IntSize
& initialSize
)
175 , d(new FrameViewPrivate(this))
178 Widget::setFrameRect(IntRect(x(), y(), initialSize
.width(), initialSize
.height()));
182 FrameView::~FrameView()
184 if (d
->m_postLayoutTasksTimer
.isActive()) {
185 d
->m_postLayoutTasksTimer
.stop();
186 d
->m_scheduledEvents
.clear();
187 d
->m_enqueueEvents
= 0;
191 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
192 setHasVerticalScrollbar(false);
194 ASSERT(m_refCount
== 0);
195 ASSERT(d
->m_scheduledEvents
.isEmpty());
196 ASSERT(!d
->m_enqueueEvents
);
199 ASSERT(m_frame
->view() != this || !m_frame
->document() || !m_frame
->contentRenderer());
200 RenderPart
* renderer
= m_frame
->ownerRenderer();
201 if (renderer
&& renderer
->widget() == this)
202 renderer
->setWidget(0);
209 bool FrameView::isFrameView() const
214 void FrameView::clearFrame()
219 void FrameView::resetScrollbars()
221 // Reset the document's scrollbars back to our defaults before we yield the floor.
222 d
->m_firstLayout
= true;
223 setScrollbarsSuppressed(true);
224 setScrollbarModes(d
->m_hmode
, d
->m_vmode
);
225 setScrollbarsSuppressed(false);
228 void FrameView::init()
230 m_margins
= IntSize(-1, -1); // undefined
233 // Propagate the marginwidth/height and scrolling modes to the view.
234 Element
* ownerElement
= m_frame
&& m_frame
->document() ? m_frame
->document()->ownerElement() : 0;
235 if (ownerElement
&& (ownerElement
->hasTagName(frameTag
) || ownerElement
->hasTagName(iframeTag
))) {
236 HTMLFrameElement
* frameElt
= static_cast<HTMLFrameElement
*>(ownerElement
);
237 if (frameElt
->scrollingMode() == ScrollbarAlwaysOff
)
238 setCanHaveScrollbars(false);
239 int marginWidth
= frameElt
->getMarginWidth();
240 int marginHeight
= frameElt
->getMarginHeight();
241 if (marginWidth
!= -1)
242 setMarginWidth(marginWidth
);
243 if (marginHeight
!= -1)
244 setMarginHeight(marginHeight
);
248 void FrameView::clear()
250 setCanBlitOnScroll(true);
255 if (RenderPart
* renderer
= m_frame
->ownerRenderer())
256 renderer
->viewCleared();
258 setScrollbarsSuppressed(true);
261 bool FrameView::didFirstLayout() const
263 return !d
->m_firstLayout
;
266 void FrameView::initScrollbars()
268 if (!d
->m_needToInitScrollbars
)
270 d
->m_needToInitScrollbars
= false;
271 d
->m_hmode
= horizontalScrollbarMode();
272 d
->m_vmode
= verticalScrollbarMode();
273 setScrollbarModes(d
->m_hmode
, d
->m_vmode
);
276 void FrameView::invalidateRect(const IntRect
& rect
)
280 hostWindow()->repaint(rect
, true);
287 RenderPart
* renderer
= m_frame
->ownerRenderer();
291 IntRect repaintRect
= rect
;
292 repaintRect
.move(renderer
->borderLeft() + renderer
->paddingLeft(),
293 renderer
->borderTop() + renderer
->paddingTop());
294 renderer
->repaintRectangle(repaintRect
);
297 void FrameView::setMarginWidth(int w
)
299 // make it update the rendering area when set
300 m_margins
.setWidth(w
);
303 void FrameView::setMarginHeight(int h
)
305 // make it update the rendering area when set
306 m_margins
.setHeight(h
);
309 void FrameView::setCanHaveScrollbars(bool canScroll
)
311 ScrollView::setCanHaveScrollbars(canScroll
);
312 scrollbarModes(d
->m_hmode
, d
->m_vmode
);
315 void FrameView::adjustViewSize()
317 ASSERT(m_frame
->view() == this);
318 RenderView
* root
= m_frame
->contentRenderer();
321 setContentsSize(IntSize(root
->overflowWidth(), root
->overflowHeight()));
324 void FrameView::applyOverflowToViewport(RenderObject
* o
, ScrollbarMode
& hMode
, ScrollbarMode
& vMode
)
326 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
327 // overflow:hidden and overflow:scroll on <body> as applying to the document's
328 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
329 // use the root element.
330 switch (o
->style()->overflowX()) {
332 hMode
= ScrollbarAlwaysOff
;
335 hMode
= ScrollbarAlwaysOn
;
338 hMode
= ScrollbarAuto
;
341 // Don't set it at all.
345 switch (o
->style()->overflowY()) {
347 vMode
= ScrollbarAlwaysOff
;
350 vMode
= ScrollbarAlwaysOn
;
353 vMode
= ScrollbarAuto
;
356 // Don't set it at all.
360 d
->m_viewportRenderer
= o
;
363 int FrameView::layoutCount() const
365 return d
->m_layoutCount
;
368 bool FrameView::needsFullRepaint() const
370 return d
->m_doFullRepaint
;
373 RenderObject
* FrameView::layoutRoot(bool onlyDuringLayout
) const
375 return onlyDuringLayout
&& layoutPending() ? 0 : d
->m_layoutRoot
;
378 void FrameView::layout(bool allowSubtree
)
383 d
->m_layoutTimer
.stop();
384 d
->m_delayedLayout
= false;
386 // Protect the view from being deleted during layout (in recalcStyle)
387 RefPtr
<FrameView
> protector(this);
390 // FIXME: Do we need to set m_size.width here?
391 // FIXME: Should we set m_size.height here too?
392 m_size
.setWidth(visibleWidth());
396 // we shouldn't enter layout() while painting
397 ASSERT(!isPainting());
401 if (!allowSubtree
&& d
->m_layoutRoot
) {
402 d
->m_layoutRoot
->markContainingBlocksForLayout(false);
406 ASSERT(m_frame
->view() == this);
407 // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a
408 // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful
410 if (m_frame
->view() != this)
413 Document
* document
= m_frame
->document();
415 // FIXME: Should we set m_size.height here too?
416 m_size
.setWidth(visibleWidth());
420 d
->m_layoutSchedulingEnabled
= false;
422 if (!d
->m_nestedLayoutCount
&& d
->m_postLayoutTasksTimer
.isActive()) {
423 // This is a new top-level layout. If there are any remaining tasks from the previous
424 // layout, finish them now.
425 d
->m_postLayoutTasksTimer
.stop();
426 performPostLayoutTasks();
429 // Viewport-dependent media queries may cause us to need completely different style information.
431 if (document
->styleSelector()->affectedByViewportChange())
432 document
->updateStyleSelector();
434 // Always ensure our style info is up-to-date. This can happen in situations where
435 // the layout beats any sort of style recalc update that needs to occur.
436 if (m_frame
->needsReapplyStyles())
437 m_frame
->reapplyStyles();
438 else if (document
->hasChangedChild())
439 document
->recalcStyle();
441 bool subtree
= d
->m_layoutRoot
;
443 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
444 // so there's no point to continuing to layout
445 if (protector
->hasOneRef())
448 RenderObject
* root
= subtree
? d
->m_layoutRoot
: document
->renderer();
450 // FIXME: Do we need to set m_size here?
451 d
->m_layoutSchedulingEnabled
= true;
455 d
->m_nestedLayoutCount
++;
457 ScrollbarMode hMode
= d
->m_hmode
;
458 ScrollbarMode vMode
= d
->m_vmode
;
461 RenderObject
* rootRenderer
= document
->documentElement() ? document
->documentElement()->renderer() : 0;
462 Node
* body
= document
->body();
463 if (body
&& body
->renderer()) {
464 if (body
->hasTagName(framesetTag
)) {
465 body
->renderer()->setChildNeedsLayout(true);
466 vMode
= ScrollbarAlwaysOff
;
467 hMode
= ScrollbarAlwaysOff
;
468 } else if (body
->hasTagName(bodyTag
)) {
469 if (!d
->m_firstLayout
&& m_size
.height() != visibleHeight()
470 && static_cast<RenderBox
*>(body
->renderer())->stretchesToViewHeight())
471 body
->renderer()->setChildNeedsLayout(true);
472 // It's sufficient to just check the X overflow,
473 // since it's illegal to have visible in only one direction.
474 RenderObject
* o
= rootRenderer
->style()->overflowX() == OVISIBLE
&& document
->documentElement()->hasTagName(htmlTag
) ? body
->renderer() : rootRenderer
;
475 applyOverflowToViewport(o
, hMode
, vMode
);
477 } else if (rootRenderer
)
478 applyOverflowToViewport(rootRenderer
, hMode
, vMode
);
479 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
480 if (d
->m_firstLayout
&& !document
->ownerElement())
481 printf("Elapsed time before first layout: %d\n", document
->elapsedTime());
485 d
->m_doFullRepaint
= !subtree
&& (d
->m_firstLayout
|| static_cast<RenderView
*>(root
)->printing());
488 // Now set our scrollbar state for the layout.
489 ScrollbarMode currentHMode
= horizontalScrollbarMode();
490 ScrollbarMode currentVMode
= verticalScrollbarMode();
492 if (d
->m_firstLayout
|| (hMode
!= currentHMode
|| vMode
!= currentVMode
)) {
493 setScrollbarsSuppressed(true);
494 if (d
->m_firstLayout
) {
495 d
->m_firstLayout
= false;
496 d
->m_firstLayoutCallbackPending
= true;
497 d
->m_lastLayoutSize
= IntSize(width(), height());
498 d
->m_lastZoomFactor
= root
->style()->zoom();
500 // Set the initial vMode to AlwaysOn if we're auto.
501 if (vMode
== ScrollbarAuto
)
502 setVerticalScrollbarMode(ScrollbarAlwaysOn
); // This causes a vertical scrollbar to appear.
503 // Set the initial hMode to AlwaysOff if we're auto.
504 if (hMode
== ScrollbarAuto
)
505 setHorizontalScrollbarMode(ScrollbarAlwaysOff
); // This causes a horizontal scrollbar to disappear.
507 setScrollbarModes(hMode
, vMode
);
508 setScrollbarsSuppressed(false, true);
511 IntSize oldSize
= m_size
;
513 m_size
= IntSize(visibleWidth(), visibleHeight());
515 if (oldSize
!= m_size
)
516 d
->m_doFullRepaint
= true;
519 RenderLayer
* layer
= root
->enclosingLayer();
521 pauseScheduledEvents();
524 root
->view()->pushLayoutState(root
);
526 d
->m_midLayout
= true;
527 beginDeferredRepaints();
529 endDeferredRepaints();
530 d
->m_midLayout
= false;
533 root
->view()->popLayoutState();
536 m_frame
->invalidateSelection();
538 d
->m_layoutSchedulingEnabled
= true;
540 if (!subtree
&& !static_cast<RenderView
*>(root
)->printing())
543 // Now update the positions of all layers.
544 beginDeferredRepaints();
545 layer
->updateLayerPositions(d
->m_doFullRepaint
);
546 endDeferredRepaints();
551 if (AXObjectCache::accessibilityEnabled())
552 root
->document()->axObjectCache()->postNotificationToElement(root
, "AXLayoutComplete");
554 #if ENABLE(DASHBOARD_SUPPORT)
555 updateDashboardRegions();
558 ASSERT(!root
->needsLayout());
560 setCanBlitOnScroll(!useSlowRepaints());
562 if (document
->hasListenerType(Document::OVERFLOWCHANGED_LISTENER
))
563 updateOverflowStatus(visibleWidth() < contentsWidth(),
564 visibleHeight() < contentsHeight());
566 if (!d
->m_postLayoutTasksTimer
.isActive()) {
567 // Calls resumeScheduledEvents()
568 performPostLayoutTasks();
571 // Post-layout widget updates or an event handler made us need layout again.
572 // Lay out again, but this time defer widget updates and event dispatch until after
574 d
->m_postLayoutTasksTimer
.startOneShot(0);
575 pauseScheduledEvents();
579 resumeScheduledEvents();
580 ASSERT(d
->m_enqueueEvents
);
583 d
->m_nestedLayoutCount
--;
586 void FrameView::addWidgetToUpdate(RenderPartObject
* object
)
588 if (!m_widgetUpdateSet
)
589 m_widgetUpdateSet
.set(new HashSet
<RenderPartObject
*>);
591 m_widgetUpdateSet
->add(object
);
594 void FrameView::removeWidgetToUpdate(RenderPartObject
* object
)
596 if (!m_widgetUpdateSet
)
599 m_widgetUpdateSet
->remove(object
);
602 void FrameView::setMediaType(const String
& mediaType
)
604 d
->m_mediaType
= mediaType
;
607 String
FrameView::mediaType() const
609 // See if we have an override type.
610 String overrideType
= m_frame
->loader()->client()->overrideMediaType();
611 if (!overrideType
.isNull())
613 return d
->m_mediaType
;
616 bool FrameView::useSlowRepaints() const
618 return d
->m_useSlowRepaints
|| d
->m_slowRepaintObjectCount
> 0;
621 void FrameView::setUseSlowRepaints()
623 d
->m_useSlowRepaints
= true;
624 setCanBlitOnScroll(false);
627 void FrameView::addSlowRepaintObject()
629 if (!d
->m_slowRepaintObjectCount
)
630 setCanBlitOnScroll(false);
631 d
->m_slowRepaintObjectCount
++;
634 void FrameView::removeSlowRepaintObject()
636 ASSERT(d
->m_slowRepaintObjectCount
> 0);
637 d
->m_slowRepaintObjectCount
--;
638 if (!d
->m_slowRepaintObjectCount
)
639 setCanBlitOnScroll(!d
->m_useSlowRepaints
);
642 void FrameView::restoreScrollbar()
644 setScrollbarsSuppressed(false);
647 void FrameView::scrollRectIntoViewRecursively(const IntRect
& r
)
649 bool wasInProgrammaticScroll
= d
->m_inProgrammaticScroll
;
650 d
->m_inProgrammaticScroll
= true;
651 ScrollView::scrollRectIntoViewRecursively(r
);
652 d
->m_inProgrammaticScroll
= wasInProgrammaticScroll
;
655 void FrameView::setScrollPosition(const IntPoint
& scrollPoint
)
657 bool wasInProgrammaticScroll
= d
->m_inProgrammaticScroll
;
658 d
->m_inProgrammaticScroll
= true;
659 ScrollView::setScrollPosition(scrollPoint
);
660 d
->m_inProgrammaticScroll
= wasInProgrammaticScroll
;
663 HostWindow
* FrameView::hostWindow() const
665 Page
* page
= frame() ? frame()->page() : 0;
668 return page
->chrome();
671 const unsigned cRepaintRectUnionThreshold
= 25;
673 void FrameView::repaintContentRectangle(const IntRect
& r
, bool immediate
)
675 ASSERT(!m_frame
->document()->ownerElement());
677 if (d
->m_deferringRepaints
&& !immediate
) {
678 IntRect visibleContent
= visibleContentRect();
679 visibleContent
.intersect(r
);
680 if (!visibleContent
.isEmpty()) {
682 d
->m_repaintRect
.unite(r
);
683 if (d
->m_repaintCount
== cRepaintRectUnionThreshold
)
684 d
->m_repaintRects
.clear();
685 else if (d
->m_repaintCount
< cRepaintRectUnionThreshold
)
686 d
->m_repaintRects
.append(r
);
691 if (!immediate
&& isOffscreen() && !shouldUpdateWhileOffscreen())
694 ScrollView::repaintContentRectangle(r
, immediate
);
697 void FrameView::beginDeferredRepaints()
699 Page
* page
= m_frame
->page();
700 if (page
->mainFrame() != m_frame
)
701 return page
->mainFrame()->view()->beginDeferredRepaints();
703 d
->m_deferringRepaints
++;
704 d
->m_repaintCount
= 0;
705 d
->m_repaintRect
= IntRect();
706 d
->m_repaintRects
.clear();
710 void FrameView::endDeferredRepaints()
712 Page
* page
= m_frame
->page();
713 if (page
->mainFrame() != m_frame
)
714 return page
->mainFrame()->view()->endDeferredRepaints();
716 ASSERT(d
->m_deferringRepaints
> 0);
717 if (--d
->m_deferringRepaints
== 0) {
718 if (d
->m_repaintCount
>= cRepaintRectUnionThreshold
)
719 repaintContentRectangle(d
->m_repaintRect
, false);
721 unsigned size
= d
->m_repaintRects
.size();
722 for (unsigned i
= 0; i
< size
; i
++)
723 repaintContentRectangle(d
->m_repaintRects
[i
], false);
724 d
->m_repaintRects
.clear();
729 void FrameView::layoutTimerFired(Timer
<FrameView
>*)
731 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
732 if (m_frame
->document() && !m_frame
->document()->ownerElement())
733 printf("Layout timer fired at %d\n", m_frame
->document()->elapsedTime());
738 void FrameView::scheduleRelayout()
740 ASSERT(!m_frame
->document() || !m_frame
->document()->inPageCache());
741 ASSERT(m_frame
->view() == this);
743 if (d
->m_layoutRoot
) {
744 d
->m_layoutRoot
->markContainingBlocksForLayout(false);
747 if (!d
->m_layoutSchedulingEnabled
)
750 if (!m_frame
->document() || !m_frame
->document()->shouldScheduleLayout())
753 int delay
= m_frame
->document()->minimumLayoutDelay();
754 if (d
->m_layoutTimer
.isActive() && d
->m_delayedLayout
&& !delay
)
755 unscheduleRelayout();
756 if (d
->m_layoutTimer
.isActive())
759 d
->m_delayedLayout
= delay
!= 0;
761 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
762 if (!m_frame
->document()->ownerElement())
763 printf("Scheduling layout for %d\n", delay
);
766 d
->m_layoutTimer
.startOneShot(delay
* 0.001);
769 static bool isObjectAncestorContainerOf(RenderObject
* ancestor
, RenderObject
* descendant
)
771 for (RenderObject
* r
= descendant
; r
; r
= r
->container()) {
778 void FrameView::scheduleRelayoutOfSubtree(RenderObject
* relayoutRoot
)
780 ASSERT(m_frame
->view() == this);
782 if (!d
->m_layoutSchedulingEnabled
|| (m_frame
->contentRenderer()
783 && m_frame
->contentRenderer()->needsLayout())) {
785 relayoutRoot
->markContainingBlocksForLayout(false);
789 if (layoutPending()) {
790 if (d
->m_layoutRoot
!= relayoutRoot
) {
791 if (isObjectAncestorContainerOf(d
->m_layoutRoot
, relayoutRoot
)) {
792 // Keep the current root
793 relayoutRoot
->markContainingBlocksForLayout(false, d
->m_layoutRoot
);
794 } else if (d
->m_layoutRoot
&& isObjectAncestorContainerOf(relayoutRoot
, d
->m_layoutRoot
)) {
795 // Re-root at relayoutRoot
796 d
->m_layoutRoot
->markContainingBlocksForLayout(false, relayoutRoot
);
797 d
->m_layoutRoot
= relayoutRoot
;
799 // Just do a full relayout
801 d
->m_layoutRoot
->markContainingBlocksForLayout(false);
803 relayoutRoot
->markContainingBlocksForLayout(false);
807 int delay
= m_frame
->document()->minimumLayoutDelay();
808 d
->m_layoutRoot
= relayoutRoot
;
809 d
->m_delayedLayout
= delay
!= 0;
810 d
->m_layoutTimer
.startOneShot(delay
* 0.001);
814 bool FrameView::layoutPending() const
816 return d
->m_layoutTimer
.isActive();
819 bool FrameView::needsLayout() const
821 // It is possible that our document will not have a body yet. If this is the case,
822 // then we are not allowed to schedule layouts yet, so we won't be pending layout.
825 RenderView
* root
= m_frame
->contentRenderer();
826 Document
* doc
= m_frame
->document();
827 // doc->hasChangedChild() condition can occur when using WebKit ObjC interface
828 return layoutPending() || (root
&& root
->needsLayout()) || d
->m_layoutRoot
|| (doc
&& doc
->hasChangedChild()) || m_frame
->needsReapplyStyles();
831 void FrameView::setNeedsLayout()
833 RenderView
* root
= m_frame
->contentRenderer();
835 root
->setNeedsLayout(true);
838 void FrameView::unscheduleRelayout()
840 if (!d
->m_layoutTimer
.isActive())
843 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
844 if (m_frame
->document() && !m_frame
->document()->ownerElement())
845 printf("Layout timer unscheduled at %d\n", m_frame
->document()->elapsedTime());
848 d
->m_layoutTimer
.stop();
849 d
->m_delayedLayout
= false;
852 bool FrameView::isTransparent() const
854 return d
->m_isTransparent
;
857 void FrameView::setTransparent(bool isTransparent
)
859 d
->m_isTransparent
= isTransparent
;
862 Color
FrameView::baseBackgroundColor() const
864 return d
->m_baseBackgroundColor
;
867 void FrameView::setBaseBackgroundColor(Color bc
)
871 d
->m_baseBackgroundColor
= bc
;
874 bool FrameView::shouldUpdateWhileOffscreen() const
876 return d
->m_shouldUpdateWhileOffscreen
;
879 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen
)
881 d
->m_shouldUpdateWhileOffscreen
= shouldUpdateWhileOffscreen
;
884 void FrameView::scheduleEvent(PassRefPtr
<Event
> event
, PassRefPtr
<EventTargetNode
> eventTarget
)
886 if (!d
->m_enqueueEvents
) {
887 ExceptionCode ec
= 0;
888 eventTarget
->dispatchEvent(event
, ec
);
892 ScheduledEvent
* scheduledEvent
= new ScheduledEvent
;
893 scheduledEvent
->m_event
= event
;
894 scheduledEvent
->m_eventTarget
= eventTarget
;
895 d
->m_scheduledEvents
.append(scheduledEvent
);
898 void FrameView::pauseScheduledEvents()
900 ASSERT(d
->m_scheduledEvents
.isEmpty() || d
->m_enqueueEvents
);
901 d
->m_enqueueEvents
++;
904 void FrameView::resumeScheduledEvents()
906 d
->m_enqueueEvents
--;
907 if (!d
->m_enqueueEvents
)
908 dispatchScheduledEvents();
909 ASSERT(d
->m_scheduledEvents
.isEmpty() || d
->m_enqueueEvents
);
912 void FrameView::performPostLayoutTasks()
914 if (d
->m_firstLayoutCallbackPending
) {
915 d
->m_firstLayoutCallbackPending
= false;
916 m_frame
->loader()->didFirstLayout();
919 RenderView
* root
= m_frame
->contentRenderer();
921 root
->updateWidgetPositions();
922 if (m_widgetUpdateSet
&& d
->m_nestedLayoutCount
<= 1) {
923 Vector
<RenderPartObject
*> objectVector
;
924 copyToVector(*m_widgetUpdateSet
, objectVector
);
925 size_t size
= objectVector
.size();
926 for (size_t i
= 0; i
< size
; ++i
) {
927 RenderPartObject
* object
= objectVector
[i
];
928 object
->updateWidget(false);
930 // updateWidget() can destroy the RenderPartObject, so we need to make sure it's
931 // alive by checking if it's still in m_widgetUpdateSet.
932 if (m_widgetUpdateSet
->contains(object
))
933 object
->updateWidgetPosition();
935 m_widgetUpdateSet
->clear();
938 resumeScheduledEvents();
940 if (!root
->printing()) {
941 IntSize currentSize
= IntSize(width(), height());
942 float currentZoomFactor
= root
->style()->zoom();
943 bool resized
= !d
->m_firstLayout
&& (currentSize
!= d
->m_lastLayoutSize
|| currentZoomFactor
!= d
->m_lastZoomFactor
);
944 d
->m_lastLayoutSize
= currentSize
;
945 d
->m_lastZoomFactor
= currentZoomFactor
;
947 m_frame
->sendResizeEvent();
951 void FrameView::postLayoutTimerFired(Timer
<FrameView
>*)
953 performPostLayoutTasks();
956 void FrameView::updateOverflowStatus(bool horizontalOverflow
, bool verticalOverflow
)
958 if (!d
->m_viewportRenderer
)
961 if (d
->m_overflowStatusDirty
) {
962 d
->m_horizontalOverflow
= horizontalOverflow
;
963 d
->m_verticalOverflow
= verticalOverflow
;
964 d
->m_overflowStatusDirty
= false;
968 bool horizontalOverflowChanged
= (d
->m_horizontalOverflow
!= horizontalOverflow
);
969 bool verticalOverflowChanged
= (d
->m_verticalOverflow
!= verticalOverflow
);
971 if (horizontalOverflowChanged
|| verticalOverflowChanged
) {
972 d
->m_horizontalOverflow
= horizontalOverflow
;
973 d
->m_verticalOverflow
= verticalOverflow
;
975 scheduleEvent(OverflowEvent::create(horizontalOverflowChanged
, horizontalOverflow
,
976 verticalOverflowChanged
, verticalOverflow
),
977 EventTargetNodeCast(d
->m_viewportRenderer
->element()));
982 void FrameView::dispatchScheduledEvents()
984 if (d
->m_scheduledEvents
.isEmpty())
987 Vector
<ScheduledEvent
*> scheduledEventsCopy
= d
->m_scheduledEvents
;
988 d
->m_scheduledEvents
.clear();
990 Vector
<ScheduledEvent
*>::iterator end
= scheduledEventsCopy
.end();
991 for (Vector
<ScheduledEvent
*>::iterator it
= scheduledEventsCopy
.begin(); it
!= end
; ++it
) {
992 ScheduledEvent
* scheduledEvent
= *it
;
994 ExceptionCode ec
= 0;
996 // Only dispatch events to nodes that are in the document
997 if (scheduledEvent
->m_eventTarget
->inDocument())
998 scheduledEvent
->m_eventTarget
->dispatchEvent(scheduledEvent
->m_event
, ec
);
1000 delete scheduledEvent
;
1004 IntRect
FrameView::windowClipRect(bool clipToContents
) const
1006 ASSERT(m_frame
->view() == this);
1008 // Set our clip rect to be our contents.
1009 IntRect clipRect
= contentsToWindow(visibleContentRect(!clipToContents
));
1010 if (!m_frame
|| !m_frame
->document() || !m_frame
->document()->ownerElement())
1013 // Take our owner element and get the clip rect from the enclosing layer.
1014 Element
* elt
= m_frame
->document()->ownerElement();
1015 RenderLayer
* layer
= elt
->renderer()->enclosingLayer();
1016 // FIXME: layer should never be null, but sometimes seems to be anyway.
1019 FrameView
* parentView
= elt
->document()->view();
1020 clipRect
.intersect(parentView
->windowClipRectForLayer(layer
, true));
1024 IntRect
FrameView::windowClipRectForLayer(const RenderLayer
* layer
, bool clipToLayerContents
) const
1026 // If we have no layer, just return our window clip rect.
1028 return windowClipRect();
1030 // Apply the clip from the layer.
1032 if (clipToLayerContents
)
1033 clipRect
= layer
->childrenClipRect();
1035 clipRect
= layer
->selfClipRect();
1036 clipRect
= contentsToWindow(clipRect
);
1037 return intersection(clipRect
, windowClipRect());
1040 bool FrameView::isActive() const
1042 Page
* page
= frame()->page();
1043 return page
&& page
->focusController()->isActive();
1046 void FrameView::valueChanged(Scrollbar
* bar
)
1048 // Figure out if we really moved.
1049 IntSize offset
= scrollOffset();
1050 ScrollView::valueChanged(bar
);
1051 if (offset
!= scrollOffset())
1052 frame()->sendScrollEvent();
1055 void FrameView::invalidateScrollbarRect(Scrollbar
* scrollbar
, const IntRect
& rect
)
1057 // Add in our offset within the FrameView.
1058 IntRect dirtyRect
= rect
;
1059 dirtyRect
.move(scrollbar
->x(), scrollbar
->y());
1060 invalidateRect(dirtyRect
);
1063 IntRect
FrameView::windowResizerRect() const
1065 Page
* page
= frame() ? frame()->page() : 0;
1068 return page
->chrome()->windowResizerRect();
1071 #if ENABLE(DASHBOARD_SUPPORT)
1072 void FrameView::updateDashboardRegions()
1074 Document
* document
= m_frame
->document();
1075 if (!document
->hasDashboardRegions())
1077 Vector
<DashboardRegionValue
> newRegions
;
1078 document
->renderer()->collectDashboardRegions(newRegions
);
1079 if (newRegions
== document
->dashboardRegions())
1081 document
->setDashboardRegions(newRegions
);
1082 Page
* page
= m_frame
->page();
1085 page
->chrome()->client()->dashboardRegionsChanged();
1089 void FrameView::updateControlTints()
1091 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
1092 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
1093 // This is only done if the theme supports control tinting. It's up to the theme and platform
1094 // to define when controls get the tint and to call this function when that changes.
1096 // Optimize the common case where we bring a window to the front while it's still empty.
1097 if (!m_frame
|| m_frame
->loader()->url().isEmpty())
1100 if (theme()->supportsControlTints() && m_frame
->contentRenderer()) {
1103 PlatformGraphicsContext
* const noContext
= 0;
1104 GraphicsContext
context(noContext
);
1105 context
.setUpdatingControlTints(true);
1106 if (platformWidget())
1107 paintContents(&context
, visibleContentRect());
1109 paint(&context
, frameRect());
1113 bool FrameView::wasScrolledByUser() const
1115 return d
->m_wasScrolledByUser
;
1118 void FrameView::setWasScrolledByUser(bool wasScrolledByUser
)
1120 if (d
->m_inProgrammaticScroll
)
1122 d
->m_wasScrolledByUser
= wasScrolledByUser
;
1125 void FrameView::paintContents(GraphicsContext
* p
, const IntRect
& rect
)
1130 Document
* document
= frame()->document();
1136 if (document
|| document
->printing())
1137 fillWithRed
= false; // Printing, don't fill with red (can't remember why).
1138 else if (document
->ownerElement())
1139 fillWithRed
= false; // Subframe, don't fill with red.
1140 else if (isTransparent())
1141 fillWithRed
= false; // Transparent, don't fill with red.
1142 else if (d
->m_paintRestriction
== PaintRestrictionSelectionOnly
|| d
->m_paintRestriction
== PaintRestrictionSelectionOnlyBlackText
)
1143 fillWithRed
= false; // Selections are transparent, don't fill with red.
1144 else if (d
->m_nodeToDraw
)
1145 fillWithRed
= false; // Element images are transparent, don't fill with red.
1150 p
->fillRect(rect
, Color(0xFF, 0, 0));
1153 bool isTopLevelPainter
= !sCurrentPaintTimeStamp
;
1154 if (isTopLevelPainter
)
1155 sCurrentPaintTimeStamp
= currentTime();
1157 RenderView
* contentRenderer
= frame()->contentRenderer();
1158 if (!contentRenderer
) {
1159 LOG_ERROR("called Frame::paint with nil renderer");
1163 ASSERT(!needsLayout());
1164 ASSERT(!d
->m_isPainting
);
1166 d
->m_isPainting
= true;
1168 // m_nodeToDraw is used to draw only one element (and its descendants)
1169 RenderObject
* eltRenderer
= d
->m_nodeToDraw
? d
->m_nodeToDraw
->renderer() : 0;
1170 if (d
->m_paintRestriction
== PaintRestrictionNone
)
1171 document
->invalidateRenderedRectsForMarkersInRect(rect
);
1172 contentRenderer
->layer()->paint(p
, rect
, d
->m_paintRestriction
, eltRenderer
);
1174 d
->m_isPainting
= false;
1176 #if ENABLE(DASHBOARD_SUPPORT)
1177 // Regions may have changed as a result of the visibility/z-index of element changing.
1178 if (document
->dashboardRegionsDirty())
1179 updateDashboardRegions();
1182 if (isTopLevelPainter
)
1183 sCurrentPaintTimeStamp
= 0;
1186 void FrameView::setPaintRestriction(PaintRestriction pr
)
1188 d
->m_paintRestriction
= pr
;
1191 bool FrameView::isPainting() const
1193 return d
->m_isPainting
;
1196 void FrameView::setNodeToDraw(Node
* node
)
1198 d
->m_nodeToDraw
= node
;
1201 void FrameView::layoutIfNeededRecursive()
1203 // We have to crawl our entire tree looking for any FrameViews that need
1204 // layout and make sure they are up to date.
1205 // Mac actually tests for intersection with the dirty region and tries not to
1206 // update layout for frames that are outside the dirty region. Not only does this seem
1207 // pointless (since those frames will have set a zero timer to layout anyway), but
1208 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
1209 // region but then become included later by the second frame adding rects to the dirty region
1210 // when it lays out.
1215 const HashSet
<Widget
*>* viewChildren
= children();
1216 HashSet
<Widget
*>::const_iterator end
= viewChildren
->end();
1217 for (HashSet
<Widget
*>::const_iterator current
= viewChildren
->begin(); current
!= end
; ++current
)
1218 if ((*current
)->isFrameView())
1219 static_cast<FrameView
*>(*current
)->layoutIfNeededRecursive();