Reviewed by Darin.
[WebKit-https.git] / WebCore / page / FrameView.cpp
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 Apple Inc. All rights reserved.
7  *           (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9  *
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.
14  *
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.
19  *
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.
24  */
25
26 #include "config.h"
27 #include "FrameView.h"
28
29 #include "AXObjectCache.h"
30 #include "EventHandler.h"
31 #include "FloatRect.h"
32 #include "Frame.h"
33 #include "FrameLoader.h"
34 #include "FrameLoaderClient.h"
35 #include "GraphicsContext.h"
36 #include "HTMLDocument.h"
37 #include "HTMLFrameSetElement.h"
38 #include "HTMLNames.h"
39 #include "OverflowEvent.h"
40 #include "RenderPart.h"
41 #include "RenderPartObject.h"
42 #include "RenderTheme.h"
43 #include "RenderView.h"
44
45 namespace WebCore {
46
47 using namespace HTMLNames;
48
49 struct ScheduledEvent {
50     RefPtr<Event> m_event;
51     RefPtr<EventTargetNode> m_eventTarget;
52     bool m_tempEvent;
53 };
54
55 class FrameViewPrivate {
56 public:
57     FrameViewPrivate(FrameView* view)
58         : m_slowRepaintObjectCount(0)
59         , layoutTimer(view, &FrameView::layoutTimerFired)
60         , layoutRoot(0)
61         , postLayoutTasksTimer(view, &FrameView::postLayoutTimerFired)
62         , m_mediaType("screen")
63         , m_enqueueEvents(0)
64         , m_overflowStatusDirty(true)
65         , m_viewportRenderer(0)
66         , m_wasScrolledByUser(false)
67         , m_inProgrammaticScroll(false)
68     {
69         isTransparent = false;
70         baseBackgroundColor = Color::white;
71         vmode = hmode = ScrollbarAuto;
72         needToInitScrollbars = true;
73         reset();
74     }
75     void reset()
76     {
77         useSlowRepaints = false;
78         borderX = 30;
79         borderY = 30;
80         layoutTimer.stop();
81         layoutRoot = 0;
82         delayedLayout = false;
83         doFullRepaint = true;
84         layoutSchedulingEnabled = true;
85         midLayout = false;
86         layoutCount = 0;
87         nestedLayoutCount = 0;
88         postLayoutTasksTimer.stop();
89         firstLayout = true;
90         repaintRects.clear();
91         m_wasScrolledByUser = false;
92         lastLayoutSize = IntSize();
93     }
94
95     bool doFullRepaint;
96     
97     ScrollbarMode vmode;
98     ScrollbarMode hmode;
99     bool useSlowRepaints;
100     unsigned m_slowRepaintObjectCount;
101
102     int borderX, borderY;
103
104     Timer<FrameView> layoutTimer;
105     bool delayedLayout;
106     RenderObject* layoutRoot;
107     
108     bool layoutSchedulingEnabled;
109     bool midLayout;
110     int layoutCount;
111     unsigned nestedLayoutCount;
112     Timer<FrameView> postLayoutTasksTimer;
113
114     bool firstLayout;
115     bool needToInitScrollbars;
116     bool isTransparent;
117     Color baseBackgroundColor;
118     IntSize lastLayoutSize;
119
120     // Used by objects during layout to communicate repaints that need to take place only
121     // after all layout has been completed.
122     Vector<RenderObject::RepaintInfo> repaintRects;
123     
124     String m_mediaType;
125     
126     unsigned m_enqueueEvents;
127     Vector<ScheduledEvent*> m_scheduledEvents;
128     
129     bool m_overflowStatusDirty;
130     bool horizontalOverflow;
131     bool m_verticalOverflow;    
132     RenderObject* m_viewportRenderer;
133
134     bool m_wasScrolledByUser;
135     bool m_inProgrammaticScroll;
136 };
137
138 FrameView::FrameView(Frame* frame)
139     : m_refCount(1)
140     , m_frame(frame)
141     , d(new FrameViewPrivate(this))
142 {
143     init();
144     show();
145 }
146
147 #if !PLATFORM(MAC)
148 FrameView::FrameView(Frame* frame, const IntSize& initialSize)
149     : m_refCount(1)
150     , m_frame(frame)
151     , d(new FrameViewPrivate(this))
152 {
153     init();
154     Widget::setFrameGeometry(IntRect(x(), y(), initialSize.width(), initialSize.height()));
155     show();
156 }
157 #endif
158
159 FrameView::~FrameView()
160 {
161     if (d->postLayoutTasksTimer.isActive()) {
162         d->postLayoutTasksTimer.stop();
163         d->m_scheduledEvents.clear();
164         d->m_enqueueEvents = 0;
165     }
166
167     resetScrollbars();
168
169     ASSERT(m_refCount == 0);
170     ASSERT(d->m_scheduledEvents.isEmpty());
171     ASSERT(!d->m_enqueueEvents);
172
173     if (m_frame) {
174         ASSERT(m_frame->view() != this || !m_frame->document() || !m_frame->document()->renderer());
175         RenderPart* renderer = m_frame->ownerRenderer();
176         if (renderer && renderer->widget() == this)
177             renderer->setWidget(0);
178     }
179
180     delete d;
181     d = 0;
182 }
183
184 bool FrameView::isFrameView() const 
185
186     return true; 
187 }
188
189 void FrameView::clearFrame()
190 {
191     m_frame = 0;
192 }
193
194 void FrameView::resetScrollbars()
195 {
196     // Reset the document's scrollbars back to our defaults before we yield the floor.
197     d->firstLayout = true;
198     suppressScrollbars(true);
199     ScrollView::setVScrollbarMode(d->vmode);
200     ScrollView::setHScrollbarMode(d->hmode);
201     suppressScrollbars(false);
202 }
203
204 void FrameView::init()
205 {
206     m_margins = IntSize(-1, -1); // undefined
207     m_size = IntSize();
208 }
209
210 void FrameView::clear()
211 {
212     setStaticBackground(false);
213     
214     d->reset();
215
216     if (m_frame)
217         if (RenderPart* renderer = m_frame->ownerRenderer())
218             renderer->viewCleared();
219
220     suppressScrollbars(true);
221 }
222
223 bool FrameView::didFirstLayout() const
224 {
225     return !d->firstLayout;
226 }
227
228 void FrameView::initScrollbars()
229 {
230     if (!d->needToInitScrollbars)
231         return;
232     d->needToInitScrollbars = false;
233     setScrollbarsMode(hScrollbarMode());
234 }
235
236 void FrameView::setMarginWidth(int w)
237 {
238     // make it update the rendering area when set
239     m_margins.setWidth(w);
240 }
241
242 void FrameView::setMarginHeight(int h)
243 {
244     // make it update the rendering area when set
245     m_margins.setHeight(h);
246 }
247
248 void FrameView::adjustViewSize()
249 {
250     ASSERT(m_frame->view() == this);
251     RenderView* root = static_cast<RenderView*>(m_frame->renderer());
252     if (!root)
253         return;
254     resizeContents(root->overflowWidth(), root->overflowHeight());
255 }
256
257 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
258 {
259     // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
260     // overflow:hidden and overflow:scroll on <body> as applying to the document's
261     // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
262     // use the root element.
263     switch (o->style()->overflowX()) {
264         case OHIDDEN:
265             hMode = ScrollbarAlwaysOff;
266             break;
267         case OSCROLL:
268             hMode = ScrollbarAlwaysOn;
269             break;
270         case OAUTO:
271             hMode = ScrollbarAuto;
272             break;
273         default:
274             // Don't set it at all.
275             ;
276     }
277     
278      switch (o->style()->overflowY()) {
279         case OHIDDEN:
280             vMode = ScrollbarAlwaysOff;
281             break;
282         case OSCROLL:
283             vMode = ScrollbarAlwaysOn;
284             break;
285         case OAUTO:
286             vMode = ScrollbarAuto;
287             break;
288         default:
289             // Don't set it at all.
290             ;
291     }
292
293     d->m_viewportRenderer = o;
294 }
295
296 int FrameView::layoutCount() const
297 {
298     return d->layoutCount;
299 }
300
301 bool FrameView::needsFullRepaint() const
302 {
303     return d->doFullRepaint;
304 }
305
306 void FrameView::addRepaintInfo(RenderObject* o, const IntRect& r)
307 {
308     d->repaintRects.append(RenderObject::RepaintInfo(o, r));
309 }
310
311 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
312 {
313     return onlyDuringLayout && layoutPending() ? 0 : d->layoutRoot;
314 }
315
316 void FrameView::layout(bool allowSubtree)
317 {
318     if (d->midLayout)
319         return;
320
321     d->layoutTimer.stop();
322     d->delayedLayout = false;
323
324     // Protect the view from being deleted during layout (in recalcStyle)
325     RefPtr<FrameView> protector(this);
326
327     if (!m_frame) {
328         // FIXME: Do we need to set m_size.width here?
329         // FIXME: Should we set m_size.height here too?
330         m_size.setWidth(visibleWidth());
331         return;
332     }
333     
334     // we shouldn't enter layout() while painting
335     ASSERT(!m_frame->isPainting());
336     if (m_frame->isPainting())
337         return;
338
339     if (!allowSubtree && d->layoutRoot) {
340         d->layoutRoot->markContainingBlocksForLayout(false);
341         d->layoutRoot = 0;
342     }
343
344     ASSERT(m_frame->view() == this);
345     // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a
346     // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful 
347     // failure instead.  
348     if (m_frame->view() != this)
349         return;
350
351     Document* document = m_frame->document();
352     if (!document) {
353         // FIXME: Should we set m_size.height here too?
354         m_size.setWidth(visibleWidth());
355         return;
356     }
357
358     d->layoutSchedulingEnabled = false;
359
360     if (!d->nestedLayoutCount && d->postLayoutTasksTimer.isActive()) {
361         // This is a new top-level layout. If there are any remaining tasks from the previous
362         // layout, finish them now.
363         d->postLayoutTasksTimer.stop();
364         performPostLayoutTasks();
365     }
366
367     // Always ensure our style info is up-to-date.  This can happen in situations where
368     // the layout beats any sort of style recalc update that needs to occur.
369     if (m_frame->needsReapplyStyles())
370         m_frame->reapplyStyles();
371     else if (document->hasChangedChild())
372         document->recalcStyle();
373     
374     bool subtree = d->layoutRoot;
375
376     // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, 
377     // so there's no point to continuing to layout
378     if (protector->hasOneRef())
379         return;
380
381     RenderObject* root = subtree ? d->layoutRoot : document->renderer();
382     if (!root) {
383         // FIXME: Do we need to set m_size here?
384         d->layoutSchedulingEnabled = true;
385         return;
386     }
387
388     d->nestedLayoutCount++;
389
390     ScrollbarMode hMode = d->hmode;
391     ScrollbarMode vMode = d->vmode;
392
393     if (!subtree) {
394         RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
395         if (document->isHTMLDocument()) {
396             Node* body = static_cast<HTMLDocument*>(document)->body();
397             if (body && body->renderer()) {
398                 if (body->hasTagName(framesetTag)) {
399                     body->renderer()->setChildNeedsLayout(true);
400                     vMode = ScrollbarAlwaysOff;
401                     hMode = ScrollbarAlwaysOff;
402                 } else if (body->hasTagName(bodyTag)) {
403                     if (!d->firstLayout && m_size.height() != visibleHeight()
404                             && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight())
405                         body->renderer()->setChildNeedsLayout(true);
406                     // It's sufficient to just check the X overflow,
407                     // since it's illegal to have visible in only one direction.
408                     RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE 
409                         ? body->renderer() : rootRenderer;
410                     applyOverflowToViewport(o, hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
411                 }
412             }
413         } else if (rootRenderer)
414             applyOverflowToViewport(rootRenderer, hMode, vMode); // XML/XHTML UAs use the root element.
415 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
416         if (d->firstLayout && !document->ownerElement())
417             printf("Elapsed time before first layout: %d\n", document->elapsedTime());
418 #endif
419     }
420
421     d->doFullRepaint = !subtree && (d->firstLayout || static_cast<RenderView*>(root)->printing());
422     ASSERT(d->nestedLayoutCount > 1 || d->repaintRects.isEmpty());
423
424     bool didFirstLayout = false;
425     if (!subtree) {
426         // Now set our scrollbar state for the layout.
427         ScrollbarMode currentHMode = hScrollbarMode();
428         ScrollbarMode currentVMode = vScrollbarMode();
429
430         if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
431             suppressScrollbars(true);
432             if (d->firstLayout) {
433                 d->firstLayout = false;
434                 didFirstLayout = true;
435                 d->lastLayoutSize = IntSize(width(), height());
436                 
437                 // Set the initial vMode to AlwaysOn if we're auto.
438                 if (vMode == ScrollbarAuto)
439                     ScrollView::setVScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
440                 // Set the initial hMode to AlwaysOff if we're auto.
441                 if (hMode == ScrollbarAuto)
442                     ScrollView::setHScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
443             }
444             
445             if (hMode == vMode)
446                 ScrollView::setScrollbarsMode(hMode);
447             else {
448                 ScrollView::setHScrollbarMode(hMode);
449                 ScrollView::setVScrollbarMode(vMode);
450             }
451
452             suppressScrollbars(false, true);
453         }
454
455         IntSize oldSize = m_size;
456
457         m_size = IntSize(visibleWidth(), visibleHeight());
458
459         if (oldSize != m_size)
460             d->doFullRepaint = true;
461     }
462     
463     RenderLayer* layer = root->enclosingLayer();
464
465     pauseScheduledEvents();
466
467     if (subtree)
468         root->view()->pushLayoutState(root);
469     d->midLayout = true;
470     root->layout();
471     d->midLayout = false;
472     if (subtree)
473         root->view()->popLayoutState();
474     d->layoutRoot = 0;
475
476     m_frame->invalidateSelection();
477    
478     d->layoutSchedulingEnabled = true;
479
480     if (!subtree && !static_cast<RenderView*>(root)->printing())
481         adjustViewSize();
482
483     // Now update the positions of all layers.
484     layer->updateLayerPositions(d->doFullRepaint);
485
486     // FIXME: Could optimize this and have objects removed from this list
487     // if they ever do full repaints.
488     Vector<RenderObject::RepaintInfo>::iterator end = d->repaintRects.end();
489     for (Vector<RenderObject::RepaintInfo>::iterator it = d->repaintRects.begin(); it != end; ++it)
490         it->m_object->repaintRectangle(it->m_repaintRect);
491     d->repaintRects.clear();
492     
493     d->layoutCount++;
494
495 #if PLATFORM(MAC)
496     if (AXObjectCache::accessibilityEnabled())
497         root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
498 #endif
499     updateDashboardRegions();
500
501     if (didFirstLayout)
502         m_frame->loader()->didFirstLayout();
503     
504     ASSERT(!root->needsLayout());
505
506     setStaticBackground(useSlowRepaints());
507
508     if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
509         updateOverflowStatus(visibleWidth() < contentsWidth(),
510                              visibleHeight() < contentsHeight());
511
512     if (!d->postLayoutTasksTimer.isActive()) {
513         // Calls resumeScheduledEvents()
514         performPostLayoutTasks();
515
516         if (needsLayout()) {
517             // Post-layout widget updates or an event handler made us need layout again.
518             // Lay out again, but this time defer widget updates and event dispatch until after
519             // we return.
520             d->postLayoutTasksTimer.startOneShot(0);
521             pauseScheduledEvents();
522             layout();
523         }
524     } else {
525         resumeScheduledEvents();
526         ASSERT(d->m_enqueueEvents);
527     }
528
529     d->nestedLayoutCount--;
530 }
531
532 void FrameView::addWidgetToUpdate(RenderPartObject* object)
533 {
534     if (!m_widgetUpdateSet)
535         m_widgetUpdateSet.set(new HashSet<RenderPartObject*>);
536
537     m_widgetUpdateSet->add(object);
538 }
539
540 void FrameView::removeWidgetToUpdate(RenderPartObject* object)
541 {
542     if (!m_widgetUpdateSet)
543         return;
544
545     m_widgetUpdateSet->remove(object);
546 }
547
548 //
549 // Event Handling
550 //
551 /////////////////
552
553 bool FrameView::scrollTo(const IntRect& bounds)
554 {
555     int x, y, xe, ye;
556     x = bounds.x();
557     y = bounds.y();
558     xe = bounds.right() - 1;
559     ye = bounds.bottom() - 1;
560     
561     int deltax;
562     int deltay;
563
564     int curHeight = visibleHeight();
565     int curWidth = visibleWidth();
566
567     if (ye - y>curHeight-d->borderY)
568         ye = y + curHeight - d->borderY;
569
570     if (xe - x>curWidth-d->borderX)
571         xe = x + curWidth - d->borderX;
572
573     // is xpos of target left of the view's border?
574     if (x < contentsX() + d->borderX)
575         deltax = x - contentsX() - d->borderX;
576     // is xpos of target right of the view's right border?
577     else if (xe + d->borderX > contentsX() + curWidth)
578         deltax = xe + d->borderX - (contentsX() + curWidth);
579     else
580         deltax = 0;
581
582     // is ypos of target above upper border?
583     if (y < contentsY() + d->borderY)
584         deltay = y - contentsY() - d->borderY;
585     // is ypos of target below lower border?
586     else if (ye + d->borderY > contentsY() + curHeight)
587         deltay = ye + d->borderY - (contentsY() + curHeight);
588     else
589         deltay = 0;
590
591     int maxx = curWidth - d->borderX;
592     int maxy = curHeight - d->borderY;
593
594     int scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax > -maxx ? deltax : -maxx);
595     int scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay > -maxy ? deltay : -maxy);
596
597     if (contentsX() + scrollX < 0)
598         scrollX = -contentsX();
599     else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
600         scrollX = contentsWidth() - visibleWidth() - contentsX();
601
602     if (contentsY() + scrollY < 0)
603         scrollY = -contentsY();
604     else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
605         scrollY = contentsHeight() - visibleHeight() - contentsY();
606
607     scrollBy(scrollX, scrollY);
608
609     // generate abs(scroll.)
610     if (scrollX < 0)
611         scrollX = -scrollX;
612     if (scrollY < 0)
613         scrollY = -scrollY;
614
615     return scrollX != maxx && scrollY != maxy;
616 }
617
618 void FrameView::setMediaType(const String& mediaType)
619 {
620     d->m_mediaType = mediaType;
621 }
622
623 String FrameView::mediaType() const
624 {
625     // See if we have an override type.
626     String overrideType = m_frame->loader()->client()->overrideMediaType();
627     if (!overrideType.isNull())
628         return overrideType;
629     return d->m_mediaType;
630 }
631
632 bool FrameView::useSlowRepaints() const
633 {
634     return d->useSlowRepaints || d->m_slowRepaintObjectCount > 0;
635 }
636
637 void FrameView::setUseSlowRepaints()
638 {
639     d->useSlowRepaints = true;
640     setStaticBackground(true);
641 }
642
643 void FrameView::addSlowRepaintObject()
644 {
645     if (!d->m_slowRepaintObjectCount)
646         setStaticBackground(true);
647     d->m_slowRepaintObjectCount++;
648 }
649
650 void FrameView::removeSlowRepaintObject()
651 {
652     ASSERT(d->m_slowRepaintObjectCount > 0);
653     d->m_slowRepaintObjectCount--;
654     if (!d->m_slowRepaintObjectCount)
655         setStaticBackground(d->useSlowRepaints);
656 }
657
658 void FrameView::setScrollbarsMode(ScrollbarMode mode)
659 {
660     d->vmode = mode;
661     d->hmode = mode;
662     
663     ScrollView::setScrollbarsMode(mode);
664 }
665
666 void FrameView::setVScrollbarMode(ScrollbarMode mode)
667 {
668     d->vmode = mode;
669     ScrollView::setVScrollbarMode(mode);
670 }
671
672 void FrameView::setHScrollbarMode(ScrollbarMode mode)
673 {
674     d->hmode = mode;
675     ScrollView::setHScrollbarMode(mode);
676 }
677
678 void FrameView::restoreScrollbar()
679 {
680     suppressScrollbars(false);
681 }
682
683 void FrameView::scrollRectIntoViewRecursively(const IntRect& r)
684 {
685     if (frame()->prohibitsScrolling())
686         return;
687     bool wasInProgrammaticScroll = d->m_inProgrammaticScroll;
688     d->m_inProgrammaticScroll = true;
689     ScrollView::scrollRectIntoViewRecursively(r);
690     d->m_inProgrammaticScroll = wasInProgrammaticScroll;
691 }
692
693 void FrameView::setContentsPos(int x, int y)
694 {
695     if (frame()->prohibitsScrolling())
696         return;
697     bool wasInProgrammaticScroll = d->m_inProgrammaticScroll;
698     d->m_inProgrammaticScroll = true;
699     ScrollView::setContentsPos(x, y);
700     d->m_inProgrammaticScroll = wasInProgrammaticScroll;
701 }
702
703 void FrameView::repaintRectangle(const IntRect& r, bool immediate)
704 {
705     updateContents(r, immediate);
706 }
707
708 void FrameView::layoutTimerFired(Timer<FrameView>*)
709 {
710 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
711     if (m_frame->document() && !m_frame->document()->ownerElement())
712         printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
713 #endif
714     layout();
715 }
716
717 void FrameView::scheduleRelayout()
718 {
719     ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
720     ASSERT(m_frame->view() == this);
721
722     if (d->layoutRoot) {
723         d->layoutRoot->markContainingBlocksForLayout(false);
724         d->layoutRoot = 0;
725     }
726     if (!d->layoutSchedulingEnabled)
727         return;
728
729     if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
730         return;
731
732     int delay = m_frame->document()->minimumLayoutDelay();
733     if (d->layoutTimer.isActive() && d->delayedLayout && !delay)
734         unscheduleRelayout();
735     if (d->layoutTimer.isActive())
736         return;
737
738     d->delayedLayout = delay != 0;
739
740 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
741     if (!m_frame->document()->ownerElement())
742         printf("Scheduling layout for %d\n", delay);
743 #endif
744
745     d->layoutTimer.startOneShot(delay * 0.001);
746 }
747
748 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
749 {
750     for (RenderObject* r = descendant; r; r = r->container()) {
751         if (r == ancestor)
752             return true;
753     }
754     return false;
755 }
756
757 void FrameView::scheduleRelayoutOfSubtree(RenderObject* o)
758 {
759     ASSERT(m_frame->view() == this);
760
761     if (!d->layoutSchedulingEnabled || (m_frame->document()
762             && m_frame->document()->renderer()
763             && m_frame->document()->renderer()->needsLayout())) {
764         if (o)
765             o->markContainingBlocksForLayout(false);
766         return;
767     }
768
769     if (layoutPending()) {
770         if (d->layoutRoot != o) {
771             if (isObjectAncestorContainerOf(d->layoutRoot, o)) {
772                 // Keep the current root
773                 o->markContainingBlocksForLayout(false, d->layoutRoot);
774             } else if (d->layoutRoot && isObjectAncestorContainerOf(o, d->layoutRoot)) {
775                 // Re-root at o
776                 d->layoutRoot->markContainingBlocksForLayout(false, o);
777                 d->layoutRoot = o;
778             } else {
779                 // Just do a full relayout
780                 if (d->layoutRoot)
781                     d->layoutRoot->markContainingBlocksForLayout(false);
782                 d->layoutRoot = 0;
783                 o->markContainingBlocksForLayout(false);
784             }
785         }
786     } else {
787         int delay = m_frame->document()->minimumLayoutDelay();
788         d->layoutRoot = o;
789         d->delayedLayout = delay != 0;
790         d->layoutTimer.startOneShot(delay * 0.001);
791     }
792 }
793
794 bool FrameView::layoutPending() const
795 {
796     return d->layoutTimer.isActive();
797 }
798
799 bool FrameView::needsLayout() const
800 {
801     // It is possible that our document will not have a body yet. If this is the case, 
802     // then we are not allowed to schedule layouts yet, so we won't be pending layout.
803     if (!m_frame)
804         return false;
805     RenderView* root = static_cast<RenderView*>(m_frame->renderer());
806     Document * doc = m_frame->document();
807     // doc->hasChangedChild() condition can occur when using WebKit ObjC interface
808     return layoutPending() || (root && root->needsLayout()) || d->layoutRoot || (doc && doc->hasChangedChild()) || m_frame->needsReapplyStyles();
809 }
810
811 void FrameView::setNeedsLayout()
812 {
813     if (m_frame->renderer())
814         m_frame->renderer()->setNeedsLayout(true);
815 }
816
817 void FrameView::unscheduleRelayout()
818 {
819     if (!d->layoutTimer.isActive())
820         return;
821
822 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
823     if (m_frame->document() && !m_frame->document()->ownerElement())
824         printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
825 #endif
826     
827     d->layoutTimer.stop();
828     d->delayedLayout = false;
829 }
830
831 bool FrameView::isTransparent() const
832 {
833     return d->isTransparent;
834 }
835
836 void FrameView::setTransparent(bool isTransparent)
837 {
838     d->isTransparent = isTransparent;
839 }
840
841 Color FrameView::baseBackgroundColor() const
842 {
843     return d->baseBackgroundColor;
844 }
845
846 void FrameView::setBaseBackgroundColor(Color bc)
847 {
848     if (!bc.isValid())
849         bc = Color::white;
850     d->baseBackgroundColor = bc;
851 }
852
853 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget, bool tempEvent)
854 {
855     if (!d->m_enqueueEvents) {
856         ExceptionCode ec = 0;
857         eventTarget->dispatchEvent(event, ec, tempEvent);
858         return;
859     }
860
861     ScheduledEvent* scheduledEvent = new ScheduledEvent;
862     scheduledEvent->m_event = event;
863     scheduledEvent->m_eventTarget = eventTarget;
864     scheduledEvent->m_tempEvent = tempEvent;
865     d->m_scheduledEvents.append(scheduledEvent);
866 }
867
868 void FrameView::pauseScheduledEvents()
869 {
870     ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents);
871     d->m_enqueueEvents++;
872 }
873
874 void FrameView::resumeScheduledEvents()
875 {
876     d->m_enqueueEvents--;
877     if (!d->m_enqueueEvents)
878         dispatchScheduledEvents();
879     ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents);
880 }
881
882 void FrameView::performPostLayoutTasks()
883 {
884     RenderView* root = static_cast<RenderView*>(m_frame->document()->renderer());
885
886     root->updateWidgetPositions();
887     if (m_widgetUpdateSet && d->nestedLayoutCount <= 1) {
888         Vector<RenderPartObject*> objectVector;
889         copyToVector(*m_widgetUpdateSet, objectVector);
890         size_t size = objectVector.size();
891         for (size_t i = 0; i < size; ++i) {
892             RenderPartObject* object = objectVector[i];
893             object->updateWidget(false);
894
895             // updateWidget() can destroy the RenderPartObject, so we need to make sure it's
896             // alive by checking if it's still in m_widgetUpdateSet.
897             if (m_widgetUpdateSet->contains(object))
898                 object->updateWidgetPosition();
899         }
900         m_widgetUpdateSet->clear();
901     }
902
903     resumeScheduledEvents();
904
905     if (!root->printing()) {
906         IntSize currentSize = IntSize(width(), height());
907         bool resized = !d->firstLayout && currentSize != d->lastLayoutSize;
908         d->lastLayoutSize = currentSize;
909         if (resized)
910             m_frame->sendResizeEvent();
911     }
912 }
913
914 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
915 {
916     performPostLayoutTasks();
917 }
918
919 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
920 {
921     if (!d->m_viewportRenderer)
922         return;
923     
924     if (d->m_overflowStatusDirty) {
925         d->horizontalOverflow = horizontalOverflow;
926         d->m_verticalOverflow = verticalOverflow;
927         d->m_overflowStatusDirty = false;
928         return;
929     }
930     
931     bool horizontalOverflowChanged = (d->horizontalOverflow != horizontalOverflow);
932     bool verticalOverflowChanged = (d->m_verticalOverflow != verticalOverflow);
933     
934     if (horizontalOverflowChanged || verticalOverflowChanged) {
935         d->horizontalOverflow = horizontalOverflow;
936         d->m_verticalOverflow = verticalOverflow;
937         
938         scheduleEvent(new OverflowEvent(horizontalOverflowChanged, horizontalOverflow,
939             verticalOverflowChanged, verticalOverflow),
940             EventTargetNodeCast(d->m_viewportRenderer->element()), true);
941     }
942     
943 }
944
945 void FrameView::dispatchScheduledEvents()
946 {
947     if (d->m_scheduledEvents.isEmpty())
948         return;
949
950     Vector<ScheduledEvent*> scheduledEventsCopy = d->m_scheduledEvents;
951     d->m_scheduledEvents.clear();
952     
953     Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end();
954     for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) {
955         ScheduledEvent* scheduledEvent = *it;
956         
957         ExceptionCode ec = 0;
958         
959         // Only dispatch events to nodes that are in the document
960         if (scheduledEvent->m_eventTarget->inDocument())
961             scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event,
962                 ec, scheduledEvent->m_tempEvent);
963         
964         delete scheduledEvent;
965     }
966 }
967
968 IntRect FrameView::windowClipRect() const
969 {
970     return windowClipRect(true);
971 }
972
973 IntRect FrameView::windowClipRect(bool clipToContents) const
974 {
975     ASSERT(m_frame->view() == this);
976
977     // Set our clip rect to be our contents.
978     IntRect clipRect;
979     if (clipToContents)
980         clipRect = enclosingIntRect(visibleContentRect());
981     else
982         clipRect = IntRect(contentsX(), contentsY(), width(), height());
983     clipRect = contentsToWindow(clipRect);
984
985     if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement())
986         return clipRect;
987
988     // Take our owner element and get the clip rect from the enclosing layer.
989     Element* elt = m_frame->document()->ownerElement();
990     RenderLayer* layer = elt->renderer()->enclosingLayer();
991     // FIXME: layer should never be null, but sometimes seems to be anyway.
992     if (!layer)
993         return clipRect;
994     FrameView* parentView = elt->document()->view();
995     clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
996     return clipRect;
997 }
998
999 IntRect FrameView::windowClipRectForLayer(const RenderLayer* layer, bool clipToLayerContents) const
1000 {
1001     // If we have no layer, just return our window clip rect.
1002     if (!layer)
1003         return windowClipRect();
1004
1005     // Apply the clip from the layer.
1006     IntRect clipRect;
1007     if (clipToLayerContents)
1008         clipRect = layer->childrenClipRect();
1009     else
1010         clipRect = layer->selfClipRect();
1011     clipRect = contentsToWindow(clipRect); 
1012     return intersection(clipRect, windowClipRect());
1013 }
1014
1015 void FrameView::updateDashboardRegions()
1016 {
1017     Document* doc = m_frame->document();
1018     if (doc->hasDashboardRegions()) {
1019         Vector<DashboardRegionValue> newRegions;
1020         doc->renderer()->collectDashboardRegions(newRegions);
1021         doc->setDashboardRegions(newRegions);
1022         m_frame.get()->dashboardRegionsChanged();
1023     }
1024 }
1025
1026 void FrameView::updateControlTints()
1027 {
1028     // This is called when control tints are changed from aqua/graphite to clear and vice versa.
1029     // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
1030     // This is only done if the theme supports control tinting. It's up to the theme and platform
1031     // to define when controls get the tint and to call this function when that changes.
1032     
1033     // Optimize the common case where we bring a window to the front while it's still empty.
1034     if (!m_frame || m_frame->loader()->url().isEmpty()) 
1035         return;
1036     
1037     if (theme()->supportsControlTints() && m_frame->renderer()) {
1038         if (needsLayout())
1039             layout();
1040         PlatformGraphicsContext* const noContext = 0;
1041         GraphicsContext context(noContext);
1042         context.setUpdatingControlTints(true);
1043 #if !PLATFORM(MAC)
1044         ScrollView::paint(&context, frameGeometry());
1045 #else
1046         m_frame->paint(&context, enclosingIntRect(visibleContentRect()));
1047 #endif
1048     }
1049 }
1050
1051 bool FrameView::wasScrolledByUser() const
1052 {
1053     return d->m_wasScrolledByUser;
1054 }
1055
1056 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
1057 {
1058     if (d->m_inProgrammaticScroll)
1059         return;
1060     d->m_wasScrolledByUser = wasScrolledByUser;
1061 }
1062
1063 #if PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(QT)
1064 void FrameView::layoutIfNeededRecursive()
1065 {
1066     // We have to crawl our entire tree looking for any FrameViews that need
1067     // layout and make sure they are up to date.
1068     // Mac actually tests for intersection with the dirty region and tries not to
1069     // update layout for frames that are outside the dirty region.  Not only does this seem
1070     // pointless (since those frames will have set a zero timer to layout anyway), but
1071     // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
1072     // region but then become included later by the second frame adding rects to the dirty region
1073     // when it lays out.
1074
1075     if (needsLayout())
1076         layout();
1077
1078     HashSet<Widget*>* viewChildren = children();
1079     HashSet<Widget*>::iterator end = viewChildren->end();
1080     for (HashSet<Widget*>::iterator current = viewChildren->begin(); current != end; ++current)
1081         if ((*current)->isFrameView())
1082             static_cast<FrameView*>(*current)->layoutIfNeededRecursive();
1083 }
1084 #endif
1085
1086 }