2008-11-04 Anders Carlsson <andersca@apple.com>
[webkit/qt.git] / WebCore / page / FrameView.cpp
blobbb4119a494272cefa1c9c2c7a4f90ee476313ff5
1 /*
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.
26 #include "config.h"
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"
35 #include "Frame.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"
44 #include "Page.h"
45 #include "RenderPart.h"
46 #include "RenderPartObject.h"
47 #include "RenderTheme.h"
48 #include "RenderView.h"
49 #include "Settings.h"
50 #include "SystemTime.h"
52 namespace WebCore {
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 {
64 public:
65 FrameViewPrivate(FrameView* view)
66 : m_slowRepaintObjectCount(0)
67 , m_layoutTimer(view, &FrameView::layoutTimerFired)
68 , m_layoutRoot(0)
69 , m_postLayoutTasksTimer(view, &FrameView::postLayoutTimerFired)
70 , m_mediaType("screen")
71 , m_enqueueEvents(0)
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;
82 reset();
84 void reset()
86 m_useSlowRepaints = false;
87 m_borderX = 30;
88 m_borderY = 30;
89 m_layoutTimer.stop();
90 m_layoutRoot = 0;
91 m_delayedLayout = false;
92 m_doFullRepaint = true;
93 m_layoutSchedulingEnabled = true;
94 m_midLayout = false;
95 m_layoutCount = 0;
96 m_nestedLayoutCount = 0;
97 m_postLayoutTasksTimer.stop();
98 m_firstLayout = true;
99 m_firstLayoutCallbackPending = false;
100 m_wasScrolledByUser = false;
101 m_lastLayoutSize = IntSize();
102 m_lastZoomFactor = 1.0f;
103 m_deferringRepaints = 0;
104 m_repaintCount = 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;
125 bool m_midLayout;
126 int m_layoutCount;
127 unsigned m_nestedLayoutCount;
128 Timer<FrameView> m_postLayoutTasksTimer;
129 bool m_firstLayoutCallbackPending;
131 bool m_firstLayout;
132 bool m_needToInitScrollbars;
133 bool m_isTransparent;
134 Color m_baseBackgroundColor;
135 IntSize m_lastLayoutSize;
136 float m_lastZoomFactor;
138 String m_mediaType;
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;
160 bool m_isPainting;
163 FrameView::FrameView(Frame* frame)
164 : m_refCount(1)
165 , m_frame(frame)
166 , d(new FrameViewPrivate(this))
168 init();
169 show();
172 FrameView::FrameView(Frame* frame, const IntSize& initialSize)
173 : m_refCount(1)
174 , m_frame(frame)
175 , d(new FrameViewPrivate(this))
177 init();
178 Widget::setFrameRect(IntRect(x(), y(), initialSize.width(), initialSize.height()));
179 show();
182 FrameView::~FrameView()
184 if (d->m_postLayoutTasksTimer.isActive()) {
185 d->m_postLayoutTasksTimer.stop();
186 d->m_scheduledEvents.clear();
187 d->m_enqueueEvents = 0;
190 resetScrollbars();
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);
198 if (m_frame) {
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);
205 delete d;
206 d = 0;
209 bool FrameView::isFrameView() const
211 return true;
214 void FrameView::clearFrame()
216 m_frame = 0;
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
231 m_size = IntSize();
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);
252 d->reset();
254 if (m_frame)
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)
269 return;
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)
278 if (!parent()) {
279 if (hostWindow())
280 hostWindow()->repaint(rect, true);
281 return;
284 if (!m_frame)
285 return;
287 RenderPart* renderer = m_frame->ownerRenderer();
288 if (!renderer)
289 return;
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();
319 if (!root)
320 return;
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()) {
331 case OHIDDEN:
332 hMode = ScrollbarAlwaysOff;
333 break;
334 case OSCROLL:
335 hMode = ScrollbarAlwaysOn;
336 break;
337 case OAUTO:
338 hMode = ScrollbarAuto;
339 break;
340 default:
341 // Don't set it at all.
345 switch (o->style()->overflowY()) {
346 case OHIDDEN:
347 vMode = ScrollbarAlwaysOff;
348 break;
349 case OSCROLL:
350 vMode = ScrollbarAlwaysOn;
351 break;
352 case OAUTO:
353 vMode = ScrollbarAuto;
354 break;
355 default:
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)
380 if (d->m_midLayout)
381 return;
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);
389 if (!m_frame) {
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());
393 return;
396 // we shouldn't enter layout() while painting
397 ASSERT(!isPainting());
398 if (isPainting())
399 return;
401 if (!allowSubtree && d->m_layoutRoot) {
402 d->m_layoutRoot->markContainingBlocksForLayout(false);
403 d->m_layoutRoot = 0;
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
409 // failure instead.
410 if (m_frame->view() != this)
411 return;
413 Document* document = m_frame->document();
414 if (!document) {
415 // FIXME: Should we set m_size.height here too?
416 m_size.setWidth(visibleWidth());
417 return;
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.
430 // Check that here.
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())
446 return;
448 RenderObject* root = subtree ? d->m_layoutRoot : document->renderer();
449 if (!root) {
450 // FIXME: Do we need to set m_size here?
451 d->m_layoutSchedulingEnabled = true;
452 return;
455 d->m_nestedLayoutCount++;
457 ScrollbarMode hMode = d->m_hmode;
458 ScrollbarMode vMode = d->m_vmode;
460 if (!subtree) {
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());
482 #endif
485 d->m_doFullRepaint = !subtree && (d->m_firstLayout || static_cast<RenderView*>(root)->printing());
487 if (!subtree) {
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();
523 if (subtree)
524 root->view()->pushLayoutState(root);
526 d->m_midLayout = true;
527 beginDeferredRepaints();
528 root->layout();
529 endDeferredRepaints();
530 d->m_midLayout = false;
532 if (subtree)
533 root->view()->popLayoutState();
534 d->m_layoutRoot = 0;
536 m_frame->invalidateSelection();
538 d->m_layoutSchedulingEnabled = true;
540 if (!subtree && !static_cast<RenderView*>(root)->printing())
541 adjustViewSize();
543 // Now update the positions of all layers.
544 beginDeferredRepaints();
545 layer->updateLayerPositions(d->m_doFullRepaint);
546 endDeferredRepaints();
548 d->m_layoutCount++;
550 #if PLATFORM(MAC)
551 if (AXObjectCache::accessibilityEnabled())
552 root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
553 #endif
554 #if ENABLE(DASHBOARD_SUPPORT)
555 updateDashboardRegions();
556 #endif
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();
570 if (needsLayout()) {
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
573 // we return.
574 d->m_postLayoutTasksTimer.startOneShot(0);
575 pauseScheduledEvents();
576 layout();
578 } else {
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)
597 return;
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())
612 return overrideType;
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;
666 if (!page)
667 return 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()) {
681 d->m_repaintCount++;
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);
688 return;
691 if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen())
692 return;
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);
720 else {
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());
734 #endif
735 layout();
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);
745 d->m_layoutRoot = 0;
747 if (!d->m_layoutSchedulingEnabled)
748 return;
750 if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
751 return;
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())
757 return;
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);
764 #endif
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()) {
772 if (r == ancestor)
773 return true;
775 return false;
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())) {
784 if (relayoutRoot)
785 relayoutRoot->markContainingBlocksForLayout(false);
786 return;
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;
798 } else {
799 // Just do a full relayout
800 if (d->m_layoutRoot)
801 d->m_layoutRoot->markContainingBlocksForLayout(false);
802 d->m_layoutRoot = 0;
803 relayoutRoot->markContainingBlocksForLayout(false);
806 } else {
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.
823 if (!m_frame)
824 return false;
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();
834 if (root)
835 root->setNeedsLayout(true);
838 void FrameView::unscheduleRelayout()
840 if (!d->m_layoutTimer.isActive())
841 return;
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());
846 #endif
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)
869 if (!bc.isValid())
870 bc = Color::white;
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);
889 return;
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;
946 if (resized)
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)
959 return;
961 if (d->m_overflowStatusDirty) {
962 d->m_horizontalOverflow = horizontalOverflow;
963 d->m_verticalOverflow = verticalOverflow;
964 d->m_overflowStatusDirty = false;
965 return;
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())
985 return;
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())
1011 return clipRect;
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.
1017 if (!layer)
1018 return clipRect;
1019 FrameView* parentView = elt->document()->view();
1020 clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
1021 return clipRect;
1024 IntRect FrameView::windowClipRectForLayer(const RenderLayer* layer, bool clipToLayerContents) const
1026 // If we have no layer, just return our window clip rect.
1027 if (!layer)
1028 return windowClipRect();
1030 // Apply the clip from the layer.
1031 IntRect clipRect;
1032 if (clipToLayerContents)
1033 clipRect = layer->childrenClipRect();
1034 else
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;
1066 if (!page)
1067 return IntRect();
1068 return page->chrome()->windowResizerRect();
1071 #if ENABLE(DASHBOARD_SUPPORT)
1072 void FrameView::updateDashboardRegions()
1074 Document* document = m_frame->document();
1075 if (!document->hasDashboardRegions())
1076 return;
1077 Vector<DashboardRegionValue> newRegions;
1078 document->renderer()->collectDashboardRegions(newRegions);
1079 if (newRegions == document->dashboardRegions())
1080 return;
1081 document->setDashboardRegions(newRegions);
1082 Page* page = m_frame->page();
1083 if (!page)
1084 return;
1085 page->chrome()->client()->dashboardRegionsChanged();
1087 #endif
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())
1098 return;
1100 if (theme()->supportsControlTints() && m_frame->contentRenderer()) {
1101 if (needsLayout())
1102 layout();
1103 PlatformGraphicsContext* const noContext = 0;
1104 GraphicsContext context(noContext);
1105 context.setUpdatingControlTints(true);
1106 if (platformWidget())
1107 paintContents(&context, visibleContentRect());
1108 else
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)
1121 return;
1122 d->m_wasScrolledByUser = wasScrolledByUser;
1125 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
1127 if (!frame())
1128 return;
1130 Document* document = frame()->document();
1131 if (!document)
1132 return;
1134 #ifndef NDEBUG
1135 bool fillWithRed;
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.
1146 else
1147 fillWithRed = true;
1149 if (fillWithRed)
1150 p->fillRect(rect, Color(0xFF, 0, 0));
1151 #endif
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");
1160 return;
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();
1180 #endif
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.
1212 if (needsLayout())
1213 layout();
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();