Fixes QWebFrame::setScrollBarPolicy(..) to actually work. Also happens
[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, 2008 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 "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 "FrameTree.h"
39 #include "GraphicsContext.h"
40 #include "HTMLDocument.h"
41 #include "HTMLFrameElement.h"
42 #include "HTMLFrameSetElement.h"
43 #include "HTMLNames.h"
44 #include "OverflowEvent.h"
45 #include "Page.h"
46 #include "RenderPart.h"
47 #include "RenderPartObject.h"
48 #include "RenderScrollbar.h"
49 #include "RenderTheme.h"
50 #include "RenderView.h"
51 #include "Settings.h"
52 #include "SystemTime.h"
53
54 namespace WebCore {
55
56 using namespace HTMLNames;
57
58 double FrameView::sCurrentPaintTimeStamp = 0.0;
59
60 struct ScheduledEvent {
61     RefPtr<Event> m_event;
62     RefPtr<EventTargetNode> m_eventTarget;
63 };
64
65 class FrameViewPrivate {
66 public:
67     FrameViewPrivate(FrameView* view)
68         : m_slowRepaintObjectCount(0)
69         , m_layoutTimer(view, &FrameView::layoutTimerFired)
70         , m_layoutRoot(0)
71         , m_postLayoutTasksTimer(view, &FrameView::postLayoutTimerFired)
72         , m_mediaType("screen")
73         , m_enqueueEvents(0)
74         , m_overflowStatusDirty(true)
75         , m_viewportRenderer(0)
76         , m_wasScrolledByUser(false)
77         , m_inProgrammaticScroll(false)
78         , m_shouldUpdateWhileOffscreen(true)
79     {
80         m_isTransparent = false;
81         m_baseBackgroundColor = Color::white;
82         m_vmode = m_hmode = ScrollbarAuto;
83         m_needToInitScrollbars = true;
84         reset();
85     }
86     void reset()
87     {
88         m_useSlowRepaints = false;
89         m_borderX = 30;
90         m_borderY = 30;
91         m_layoutTimer.stop();
92         m_layoutRoot = 0;
93         m_delayedLayout = false;
94         m_doFullRepaint = true;
95         m_layoutSchedulingEnabled = true;
96         m_midLayout = false;
97         m_layoutCount = 0;
98         m_nestedLayoutCount = 0;
99         m_postLayoutTasksTimer.stop();
100         m_firstLayout = true;
101         m_firstLayoutCallbackPending = false;
102         m_wasScrolledByUser = false;
103         m_lastLayoutSize = IntSize();
104         m_lastZoomFactor = 1.0f;
105         m_deferringRepaints = 0;
106         m_repaintCount = 0;
107         m_repaintRect = IntRect();
108         m_repaintRects.clear();
109         m_paintRestriction = PaintRestrictionNone;
110         m_isPainting = false;
111         m_isVisuallyNonEmpty = false;
112         m_firstVisuallyNonEmptyLayoutCallbackPending = true;
113     }
114
115     bool m_doFullRepaint;
116     
117     ScrollbarMode m_vmode;
118     ScrollbarMode m_hmode;
119     bool m_useSlowRepaints;
120     unsigned m_slowRepaintObjectCount;
121
122     int m_borderX, m_borderY;
123
124     Timer<FrameView> m_layoutTimer;
125     bool m_delayedLayout;
126     RenderObject* m_layoutRoot;
127     
128     bool m_layoutSchedulingEnabled;
129     bool m_midLayout;
130     int m_layoutCount;
131     unsigned m_nestedLayoutCount;
132     Timer<FrameView> m_postLayoutTasksTimer;
133     bool m_firstLayoutCallbackPending;
134
135     bool m_firstLayout;
136     bool m_needToInitScrollbars;
137     bool m_isTransparent;
138     Color m_baseBackgroundColor;
139     IntSize m_lastLayoutSize;
140     float m_lastZoomFactor;
141
142     String m_mediaType;
143     
144     unsigned m_enqueueEvents;
145     Vector<ScheduledEvent*> m_scheduledEvents;
146     
147     bool m_overflowStatusDirty;
148     bool m_horizontalOverflow;
149     bool m_verticalOverflow;    
150     RenderObject* m_viewportRenderer;
151
152     bool m_wasScrolledByUser;
153     bool m_inProgrammaticScroll;
154     
155     unsigned m_deferringRepaints;
156     unsigned m_repaintCount;
157     IntRect m_repaintRect;
158     Vector<IntRect> m_repaintRects;
159
160     bool m_shouldUpdateWhileOffscreen;
161
162     RefPtr<Node> m_nodeToDraw;
163     PaintRestriction m_paintRestriction;
164     bool m_isPainting;
165
166     bool m_isVisuallyNonEmpty;
167     bool m_firstVisuallyNonEmptyLayoutCallbackPending;
168 };
169
170 FrameView::FrameView(Frame* frame)
171     : m_refCount(1)
172     , m_frame(frame)
173     , d(new FrameViewPrivate(this))
174 {
175     init();
176     show();
177 }
178
179 FrameView::FrameView(Frame* frame, const IntSize& initialSize)
180     : m_refCount(1)
181     , m_frame(frame)
182     , d(new FrameViewPrivate(this))
183 {
184     init();
185     Widget::setFrameRect(IntRect(x(), y(), initialSize.width(), initialSize.height()));
186     show();
187 }
188
189 FrameView::~FrameView()
190 {
191     if (d->m_postLayoutTasksTimer.isActive()) {
192         d->m_postLayoutTasksTimer.stop();
193         d->m_scheduledEvents.clear();
194         d->m_enqueueEvents = 0;
195     }
196
197     resetScrollbars();
198     setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
199     setHasVerticalScrollbar(false);
200     
201     ASSERT(m_refCount == 0);
202     ASSERT(d->m_scheduledEvents.isEmpty());
203     ASSERT(!d->m_enqueueEvents);
204
205     if (m_frame) {
206         ASSERT(m_frame->view() != this || !m_frame->document() || !m_frame->contentRenderer());
207         RenderPart* renderer = m_frame->ownerRenderer();
208         if (renderer && renderer->widget() == this)
209             renderer->setWidget(0);
210     }
211
212     delete d;
213     d = 0;
214 }
215
216 bool FrameView::isFrameView() const 
217
218     return true; 
219 }
220
221 void FrameView::clearFrame()
222 {
223     m_frame = 0;
224 }
225
226 void FrameView::resetScrollbars()
227 {
228     // Reset the document's scrollbars back to our defaults before we yield the floor.
229     d->m_firstLayout = true;
230     setScrollbarsSuppressed(true);
231     setScrollbarModes(d->m_hmode, d->m_vmode);
232     setScrollbarsSuppressed(false);
233 }
234
235 void FrameView::init()
236 {
237     m_margins = IntSize(-1, -1); // undefined
238     m_size = IntSize();
239
240     // Propagate the marginwidth/height and scrolling modes to the view.
241     Element* ownerElement = m_frame && m_frame->document() ? m_frame->document()->ownerElement() : 0;
242     if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
243         HTMLFrameElement* frameElt = static_cast<HTMLFrameElement*>(ownerElement);
244         if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
245             setCanHaveScrollbars(false);
246         int marginWidth = frameElt->getMarginWidth();
247         int marginHeight = frameElt->getMarginHeight();
248         if (marginWidth != -1)
249             setMarginWidth(marginWidth);
250         if (marginHeight != -1)
251             setMarginHeight(marginHeight);
252     }
253 }
254
255 void FrameView::clear()
256 {
257     setCanBlitOnScroll(true);
258     
259     d->reset();
260
261     if (m_frame)
262         if (RenderPart* renderer = m_frame->ownerRenderer())
263             renderer->viewCleared();
264
265     setScrollbarsSuppressed(true);
266 }
267
268 bool FrameView::didFirstLayout() const
269 {
270     return !d->m_firstLayout;
271 }
272
273 void FrameView::initScrollbars()
274 {
275     if (!d->m_needToInitScrollbars)
276         return;
277     d->m_needToInitScrollbars = false;
278     updateDefaultScrollbarState();
279 }
280
281 void FrameView::updateDefaultScrollbarState()
282 {
283     d->m_hmode = horizontalScrollbarMode();
284     d->m_vmode = verticalScrollbarMode();
285     setScrollbarModes(d->m_hmode, d->m_vmode);
286 }
287
288 void FrameView::invalidateRect(const IntRect& rect)
289 {
290     if (!parent()) {
291         if (hostWindow())
292             hostWindow()->repaint(rect, true);
293         return;
294     }
295
296     if (!m_frame)
297         return;
298
299     RenderPart* renderer = m_frame->ownerRenderer();
300     if (!renderer)
301         return;
302
303     IntRect repaintRect = rect;
304     repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
305                      renderer->borderTop() + renderer->paddingTop());
306     renderer->repaintRectangle(repaintRect);
307 }
308
309 void FrameView::setMarginWidth(int w)
310 {
311     // make it update the rendering area when set
312     m_margins.setWidth(w);
313 }
314
315 void FrameView::setMarginHeight(int h)
316 {
317     // make it update the rendering area when set
318     m_margins.setHeight(h);
319 }
320
321 void FrameView::setCanHaveScrollbars(bool canScroll)
322 {
323     ScrollView::setCanHaveScrollbars(canScroll);
324     scrollbarModes(d->m_hmode, d->m_vmode);
325 }
326
327 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
328 {
329     // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
330     Document* doc = m_frame->document();
331     if (!doc)
332         return ScrollView::createScrollbar(orientation);
333
334     // Try the <body> element first as a scrollbar source.
335     Element* body = doc->body();
336     if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
337         return RenderScrollbar::createCustomScrollbar(this, orientation, body->renderer());
338     
339     // If the <body> didn't have a custom style, then the root element might.
340     Element* docElement = doc->documentElement();
341     if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
342         return RenderScrollbar::createCustomScrollbar(this, orientation, docElement->renderer());
343         
344     // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
345     RenderPart* frameRenderer = m_frame->ownerRenderer();
346     if (frameRenderer && frameRenderer->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
347         return RenderScrollbar::createCustomScrollbar(this, orientation, frameRenderer);
348     
349     // Nobody set a custom style, so we just use a native scrollbar.
350     return ScrollView::createScrollbar(orientation);
351 }
352
353 void FrameView::adjustViewSize()
354 {
355     ASSERT(m_frame->view() == this);
356     RenderView* root = m_frame->contentRenderer();
357     if (!root)
358         return;
359     setContentsSize(IntSize(root->overflowWidth(), root->overflowHeight()));
360 }
361
362 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
363 {
364     // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
365     // overflow:hidden and overflow:scroll on <body> as applying to the document's
366     // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
367     // use the root element.
368     switch (o->style()->overflowX()) {
369         case OHIDDEN:
370             hMode = ScrollbarAlwaysOff;
371             break;
372         case OSCROLL:
373             hMode = ScrollbarAlwaysOn;
374             break;
375         case OAUTO:
376             hMode = ScrollbarAuto;
377             break;
378         default:
379             // Don't set it at all.
380             ;
381     }
382     
383      switch (o->style()->overflowY()) {
384         case OHIDDEN:
385             vMode = ScrollbarAlwaysOff;
386             break;
387         case OSCROLL:
388             vMode = ScrollbarAlwaysOn;
389             break;
390         case OAUTO:
391             vMode = ScrollbarAuto;
392             break;
393         default:
394             // Don't set it at all.
395             ;
396     }
397
398     d->m_viewportRenderer = o;
399 }
400
401 int FrameView::layoutCount() const
402 {
403     return d->m_layoutCount;
404 }
405
406 bool FrameView::needsFullRepaint() const
407 {
408     return d->m_doFullRepaint;
409 }
410
411 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
412 {
413     return onlyDuringLayout && layoutPending() ? 0 : d->m_layoutRoot;
414 }
415
416 void FrameView::layout(bool allowSubtree)
417 {
418     if (d->m_midLayout)
419         return;
420
421     d->m_layoutTimer.stop();
422     d->m_delayedLayout = false;
423
424     // Protect the view from being deleted during layout (in recalcStyle)
425     RefPtr<FrameView> protector(this);
426
427     if (!m_frame) {
428         // FIXME: Do we need to set m_size.width here?
429         // FIXME: Should we set m_size.height here too?
430         m_size.setWidth(layoutWidth());
431         return;
432     }
433     
434     // we shouldn't enter layout() while painting
435     ASSERT(!isPainting());
436     if (isPainting())
437         return;
438
439     if (!allowSubtree && d->m_layoutRoot) {
440         d->m_layoutRoot->markContainingBlocksForLayout(false);
441         d->m_layoutRoot = 0;
442     }
443
444     ASSERT(m_frame->view() == this);
445     // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a
446     // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful 
447     // failure instead.  
448     if (m_frame->view() != this)
449         return;
450
451     Document* document = m_frame->document();
452     if (!document) {
453         // FIXME: Should we set m_size.height here too?
454         m_size.setWidth(layoutWidth());
455         return;
456     }
457
458     d->m_layoutSchedulingEnabled = false;
459
460     if (!d->m_nestedLayoutCount && d->m_postLayoutTasksTimer.isActive()) {
461         // This is a new top-level layout. If there are any remaining tasks from the previous
462         // layout, finish them now.
463         d->m_postLayoutTasksTimer.stop();
464         performPostLayoutTasks();
465     }
466
467     // Viewport-dependent media queries may cause us to need completely different style information.
468     // Check that here.
469     if (document->styleSelector()->affectedByViewportChange())
470         document->updateStyleSelector();
471
472     // Always ensure our style info is up-to-date.  This can happen in situations where
473     // the layout beats any sort of style recalc update that needs to occur.
474     if (m_frame->needsReapplyStyles())
475         m_frame->reapplyStyles();
476     else if (document->hasChangedChild())
477         document->recalcStyle();
478     
479     bool subtree = d->m_layoutRoot;
480
481     // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, 
482     // so there's no point to continuing to layout
483     if (protector->hasOneRef())
484         return;
485
486     RenderObject* root = subtree ? d->m_layoutRoot : document->renderer();
487     if (!root) {
488         // FIXME: Do we need to set m_size here?
489         d->m_layoutSchedulingEnabled = true;
490         return;
491     }
492
493     d->m_nestedLayoutCount++;
494
495     ScrollbarMode hMode = d->m_hmode;
496     ScrollbarMode vMode = d->m_vmode;
497
498     if (!subtree) {
499         RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
500         Node* body = document->body();
501         if (body && body->renderer()) {
502             if (body->hasTagName(framesetTag)) {
503                 body->renderer()->setChildNeedsLayout(true);
504                 vMode = ScrollbarAlwaysOff;
505                 hMode = ScrollbarAlwaysOff;
506             } else if (body->hasTagName(bodyTag)) {
507                 if (!d->m_firstLayout && m_size.height() != layoutHeight()
508                         && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight())
509                     body->renderer()->setChildNeedsLayout(true);
510                 // It's sufficient to just check the X overflow,
511                 // since it's illegal to have visible in only one direction.
512                 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
513                 applyOverflowToViewport(o, hMode, vMode);
514             }
515         } else if (rootRenderer)
516             applyOverflowToViewport(rootRenderer, hMode, vMode);
517 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
518         if (d->m_firstLayout && !document->ownerElement())
519             printf("Elapsed time before first layout: %d\n", document->elapsedTime());
520 #endif
521     }
522
523     d->m_doFullRepaint = !subtree && (d->m_firstLayout || static_cast<RenderView*>(root)->printing());
524
525     if (!subtree) {
526         // Now set our scrollbar state for the layout.
527         ScrollbarMode currentHMode = horizontalScrollbarMode();
528         ScrollbarMode currentVMode = verticalScrollbarMode();
529
530         if (d->m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
531             setScrollbarsSuppressed(true);
532             if (d->m_firstLayout) {
533                 d->m_firstLayout = false;
534                 d->m_firstLayoutCallbackPending = true;
535                 d->m_lastLayoutSize = IntSize(width(), height());
536                 d->m_lastZoomFactor = root->style()->zoom();
537
538                 // Set the initial vMode to AlwaysOn if we're auto.
539                 if (vMode == ScrollbarAuto)
540                     setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
541                 // Set the initial hMode to AlwaysOff if we're auto.
542                 if (hMode == ScrollbarAuto)
543                     setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
544             }
545             setScrollbarModes(hMode, vMode);
546             setScrollbarsSuppressed(false, true);
547         }
548
549         IntSize oldSize = m_size;
550
551         m_size = IntSize(layoutWidth(), layoutHeight());
552
553         if (oldSize != m_size)
554             d->m_doFullRepaint = true;
555     }
556
557     RenderLayer* layer = root->enclosingLayer();
558
559     pauseScheduledEvents();
560
561     if (subtree)
562         root->view()->pushLayoutState(root);
563         
564     d->m_midLayout = true;
565     beginDeferredRepaints();
566     root->layout();
567     endDeferredRepaints();
568     d->m_midLayout = false;
569
570     if (subtree)
571         root->view()->popLayoutState();
572     d->m_layoutRoot = 0;
573
574     m_frame->invalidateSelection();
575    
576     d->m_layoutSchedulingEnabled = true;
577
578     if (!subtree && !static_cast<RenderView*>(root)->printing())
579         adjustViewSize();
580
581     // Now update the positions of all layers.
582     beginDeferredRepaints();
583     layer->updateLayerPositions(d->m_doFullRepaint);
584     endDeferredRepaints();
585     
586     d->m_layoutCount++;
587
588 #if PLATFORM(MAC)
589     if (AXObjectCache::accessibilityEnabled())
590         root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
591 #endif
592 #if ENABLE(DASHBOARD_SUPPORT)
593     updateDashboardRegions();
594 #endif
595
596     ASSERT(!root->needsLayout());
597
598     setCanBlitOnScroll(!useSlowRepaints());
599
600     if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
601         updateOverflowStatus(layoutWidth() < contentsWidth(),
602                              layoutHeight() < contentsHeight());
603
604     if (!d->m_postLayoutTasksTimer.isActive()) {
605         // Calls resumeScheduledEvents()
606         performPostLayoutTasks();
607
608         if (needsLayout()) {
609             // Post-layout widget updates or an event handler made us need layout again.
610             // Lay out again, but this time defer widget updates and event dispatch until after
611             // we return.
612             d->m_postLayoutTasksTimer.startOneShot(0);
613             pauseScheduledEvents();
614             layout();
615         }
616     } else {
617         resumeScheduledEvents();
618         ASSERT(d->m_enqueueEvents);
619     }
620
621     d->m_nestedLayoutCount--;
622 }
623
624 void FrameView::addWidgetToUpdate(RenderPartObject* object)
625 {
626     if (!m_widgetUpdateSet)
627         m_widgetUpdateSet.set(new HashSet<RenderPartObject*>);
628
629     m_widgetUpdateSet->add(object);
630 }
631
632 void FrameView::removeWidgetToUpdate(RenderPartObject* object)
633 {
634     if (!m_widgetUpdateSet)
635         return;
636
637     m_widgetUpdateSet->remove(object);
638 }
639
640 void FrameView::setMediaType(const String& mediaType)
641 {
642     d->m_mediaType = mediaType;
643 }
644
645 String FrameView::mediaType() const
646 {
647     // See if we have an override type.
648     String overrideType = m_frame->loader()->client()->overrideMediaType();
649     if (!overrideType.isNull())
650         return overrideType;
651     return d->m_mediaType;
652 }
653
654 bool FrameView::useSlowRepaints() const
655 {
656     return d->m_useSlowRepaints || d->m_slowRepaintObjectCount > 0;
657 }
658
659 void FrameView::setUseSlowRepaints()
660 {
661     d->m_useSlowRepaints = true;
662     setCanBlitOnScroll(false);
663 }
664
665 void FrameView::addSlowRepaintObject()
666 {
667     if (!d->m_slowRepaintObjectCount)
668         setCanBlitOnScroll(false);
669     d->m_slowRepaintObjectCount++;
670 }
671
672 void FrameView::removeSlowRepaintObject()
673 {
674     ASSERT(d->m_slowRepaintObjectCount > 0);
675     d->m_slowRepaintObjectCount--;
676     if (!d->m_slowRepaintObjectCount)
677         setCanBlitOnScroll(!d->m_useSlowRepaints);
678 }
679
680 void FrameView::restoreScrollbar()
681 {
682     setScrollbarsSuppressed(false);
683 }
684
685 void FrameView::scrollRectIntoViewRecursively(const IntRect& r)
686 {
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::setScrollPosition(const IntPoint& scrollPoint)
694 {
695     bool wasInProgrammaticScroll = d->m_inProgrammaticScroll;
696     d->m_inProgrammaticScroll = true;
697     ScrollView::setScrollPosition(scrollPoint);
698     d->m_inProgrammaticScroll = wasInProgrammaticScroll;
699 }
700
701 HostWindow* FrameView::hostWindow() const
702 {
703     Page* page = frame() ? frame()->page() : 0;
704     if (!page)
705         return 0;
706     return page->chrome();
707 }
708
709 const unsigned cRepaintRectUnionThreshold = 25;
710
711 void FrameView::repaintContentRectangle(const IntRect& r, bool immediate)
712 {
713     ASSERT(!m_frame->document()->ownerElement());
714
715     if (d->m_deferringRepaints && !immediate) {
716         IntRect visibleContent = visibleContentRect();
717         visibleContent.intersect(r);
718         if (!visibleContent.isEmpty()) {
719             d->m_repaintCount++;
720             d->m_repaintRect.unite(r);
721             if (d->m_repaintCount == cRepaintRectUnionThreshold)
722                 d->m_repaintRects.clear();
723             else if (d->m_repaintCount < cRepaintRectUnionThreshold)
724                 d->m_repaintRects.append(r);
725         }
726         return;
727     }
728     
729     if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen())
730         return;
731
732     ScrollView::repaintContentRectangle(r, immediate);
733 }
734
735 void FrameView::beginDeferredRepaints()
736 {
737     Page* page = m_frame->page();
738     if (page->mainFrame() != m_frame)
739         return page->mainFrame()->view()->beginDeferredRepaints();
740
741     d->m_deferringRepaints++;
742     d->m_repaintCount = 0;
743     d->m_repaintRect = IntRect();
744     d->m_repaintRects.clear();
745 }
746
747
748 void FrameView::endDeferredRepaints()
749 {
750     Page* page = m_frame->page();
751     if (page->mainFrame() != m_frame)
752         return page->mainFrame()->view()->endDeferredRepaints();
753
754     ASSERT(d->m_deferringRepaints > 0);
755     if (--d->m_deferringRepaints == 0) {
756         if (d->m_repaintCount >= cRepaintRectUnionThreshold)
757             repaintContentRectangle(d->m_repaintRect, false);
758         else {
759             unsigned size = d->m_repaintRects.size();
760             for (unsigned i = 0; i < size; i++)
761                 repaintContentRectangle(d->m_repaintRects[i], false);
762             d->m_repaintRects.clear();
763         }
764     }
765 }
766
767 void FrameView::layoutTimerFired(Timer<FrameView>*)
768 {
769 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
770     if (m_frame->document() && !m_frame->document()->ownerElement())
771         printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
772 #endif
773     layout();
774 }
775
776 void FrameView::scheduleRelayout()
777 {
778     ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
779     ASSERT(m_frame->view() == this);
780
781     if (d->m_layoutRoot) {
782         d->m_layoutRoot->markContainingBlocksForLayout(false);
783         d->m_layoutRoot = 0;
784     }
785     if (!d->m_layoutSchedulingEnabled)
786         return;
787     if (!needsLayout())
788         return;
789     if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
790         return;
791
792     int delay = m_frame->document()->minimumLayoutDelay();
793     if (d->m_layoutTimer.isActive() && d->m_delayedLayout && !delay)
794         unscheduleRelayout();
795     if (d->m_layoutTimer.isActive())
796         return;
797
798     d->m_delayedLayout = delay != 0;
799
800 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
801     if (!m_frame->document()->ownerElement())
802         printf("Scheduling layout for %d\n", delay);
803 #endif
804
805     d->m_layoutTimer.startOneShot(delay * 0.001);
806 }
807
808 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
809 {
810     for (RenderObject* r = descendant; r; r = r->container()) {
811         if (r == ancestor)
812             return true;
813     }
814     return false;
815 }
816
817 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
818 {
819     ASSERT(m_frame->view() == this);
820
821     if (!d->m_layoutSchedulingEnabled || (m_frame->contentRenderer()
822             && m_frame->contentRenderer()->needsLayout())) {
823         if (relayoutRoot)
824             relayoutRoot->markContainingBlocksForLayout(false);
825         return;
826     }
827
828     if (layoutPending()) {
829         if (d->m_layoutRoot != relayoutRoot) {
830             if (isObjectAncestorContainerOf(d->m_layoutRoot, relayoutRoot)) {
831                 // Keep the current root
832                 relayoutRoot->markContainingBlocksForLayout(false, d->m_layoutRoot);
833             } else if (d->m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, d->m_layoutRoot)) {
834                 // Re-root at relayoutRoot
835                 d->m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot);
836                 d->m_layoutRoot = relayoutRoot;
837             } else {
838                 // Just do a full relayout
839                 if (d->m_layoutRoot)
840                     d->m_layoutRoot->markContainingBlocksForLayout(false);
841                 d->m_layoutRoot = 0;
842                 relayoutRoot->markContainingBlocksForLayout(false);
843             }
844         }
845     } else {
846         int delay = m_frame->document()->minimumLayoutDelay();
847         d->m_layoutRoot = relayoutRoot;
848         d->m_delayedLayout = delay != 0;
849         d->m_layoutTimer.startOneShot(delay * 0.001);
850     }
851 }
852
853 bool FrameView::layoutPending() const
854 {
855     return d->m_layoutTimer.isActive();
856 }
857
858 bool FrameView::needsLayout() const
859 {
860     // This can return true in cases where the document does not have a body yet.
861     // Document::shouldScheduleLayout takes care of preventing us from scheduling
862     // layout in that case.
863     if (!m_frame)
864         return false;
865     RenderView* root = m_frame->contentRenderer();
866     Document* document = m_frame->document();
867     return layoutPending()
868         || (root && root->needsLayout())
869         || d->m_layoutRoot
870         || (document && document->hasChangedChild()) // can occur when using WebKit ObjC interface
871         || m_frame->needsReapplyStyles();
872 }
873
874 void FrameView::setNeedsLayout()
875 {
876     RenderView* root = m_frame->contentRenderer();
877     if (root)
878         root->setNeedsLayout(true);
879 }
880
881 void FrameView::unscheduleRelayout()
882 {
883     if (!d->m_layoutTimer.isActive())
884         return;
885
886 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
887     if (m_frame->document() && !m_frame->document()->ownerElement())
888         printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
889 #endif
890     
891     d->m_layoutTimer.stop();
892     d->m_delayedLayout = false;
893 }
894
895 bool FrameView::isTransparent() const
896 {
897     return d->m_isTransparent;
898 }
899
900 void FrameView::setTransparent(bool isTransparent)
901 {
902     d->m_isTransparent = isTransparent;
903 }
904
905 Color FrameView::baseBackgroundColor() const
906 {
907     return d->m_baseBackgroundColor;
908 }
909
910 void FrameView::setBaseBackgroundColor(Color bc)
911 {
912     if (!bc.isValid())
913         bc = Color::white;
914     d->m_baseBackgroundColor = bc;
915 }
916
917 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
918 {
919     for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) {
920         FrameView* view = frame->view();
921         if (!view)
922             continue;
923
924         view->setTransparent(transparent);
925         view->setBaseBackgroundColor(backgroundColor);
926     }
927 }
928
929 bool FrameView::shouldUpdateWhileOffscreen() const
930 {
931     return d->m_shouldUpdateWhileOffscreen;
932 }
933
934 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
935 {
936     d->m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
937 }
938
939 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget)
940 {
941     if (!d->m_enqueueEvents) {
942         ExceptionCode ec = 0;
943         eventTarget->dispatchEvent(event, ec);
944         return;
945     }
946
947     ScheduledEvent* scheduledEvent = new ScheduledEvent;
948     scheduledEvent->m_event = event;
949     scheduledEvent->m_eventTarget = eventTarget;
950     d->m_scheduledEvents.append(scheduledEvent);
951 }
952
953 void FrameView::pauseScheduledEvents()
954 {
955     ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents);
956     d->m_enqueueEvents++;
957 }
958
959 void FrameView::resumeScheduledEvents()
960 {
961     d->m_enqueueEvents--;
962     if (!d->m_enqueueEvents)
963         dispatchScheduledEvents();
964     ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents);
965 }
966
967 void FrameView::performPostLayoutTasks()
968 {
969     if (d->m_firstLayoutCallbackPending) {
970         d->m_firstLayoutCallbackPending = false;
971         m_frame->loader()->didFirstLayout();
972     }
973
974     if (d->m_isVisuallyNonEmpty && d->m_firstVisuallyNonEmptyLayoutCallbackPending) {
975         d->m_firstVisuallyNonEmptyLayoutCallbackPending = false;
976         m_frame->loader()->didFirstVisuallyNonEmptyLayout();
977     }
978
979     RenderView* root = m_frame->contentRenderer();
980
981     root->updateWidgetPositions();
982     if (m_widgetUpdateSet && d->m_nestedLayoutCount <= 1) {
983         Vector<RenderPartObject*> objectVector;
984         copyToVector(*m_widgetUpdateSet, objectVector);
985         size_t size = objectVector.size();
986         for (size_t i = 0; i < size; ++i) {
987             RenderPartObject* object = objectVector[i];
988             object->updateWidget(false);
989
990             // updateWidget() can destroy the RenderPartObject, so we need to make sure it's
991             // alive by checking if it's still in m_widgetUpdateSet.
992             if (m_widgetUpdateSet->contains(object))
993                 object->updateWidgetPosition();
994         }
995         m_widgetUpdateSet->clear();
996     }
997
998     resumeScheduledEvents();
999
1000     if (!root->printing()) {
1001         IntSize currentSize = IntSize(width(), height());
1002         float currentZoomFactor = root->style()->zoom();
1003         bool resized = !d->m_firstLayout && (currentSize != d->m_lastLayoutSize || currentZoomFactor != d->m_lastZoomFactor);
1004         d->m_lastLayoutSize = currentSize;
1005         d->m_lastZoomFactor = currentZoomFactor;
1006         if (resized)
1007             m_frame->sendResizeEvent();
1008     }
1009 }
1010
1011 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
1012 {
1013     performPostLayoutTasks();
1014 }
1015
1016 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
1017 {
1018     if (!d->m_viewportRenderer)
1019         return;
1020     
1021     if (d->m_overflowStatusDirty) {
1022         d->m_horizontalOverflow = horizontalOverflow;
1023         d->m_verticalOverflow = verticalOverflow;
1024         d->m_overflowStatusDirty = false;
1025         return;
1026     }
1027     
1028     bool horizontalOverflowChanged = (d->m_horizontalOverflow != horizontalOverflow);
1029     bool verticalOverflowChanged = (d->m_verticalOverflow != verticalOverflow);
1030     
1031     if (horizontalOverflowChanged || verticalOverflowChanged) {
1032         d->m_horizontalOverflow = horizontalOverflow;
1033         d->m_verticalOverflow = verticalOverflow;
1034         
1035         scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
1036             verticalOverflowChanged, verticalOverflow),
1037             EventTargetNodeCast(d->m_viewportRenderer->element()));
1038     }
1039     
1040 }
1041
1042 void FrameView::dispatchScheduledEvents()
1043 {
1044     if (d->m_scheduledEvents.isEmpty())
1045         return;
1046
1047     Vector<ScheduledEvent*> scheduledEventsCopy = d->m_scheduledEvents;
1048     d->m_scheduledEvents.clear();
1049     
1050     Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end();
1051     for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) {
1052         ScheduledEvent* scheduledEvent = *it;
1053         
1054         ExceptionCode ec = 0;
1055         
1056         // Only dispatch events to nodes that are in the document
1057         if (scheduledEvent->m_eventTarget->inDocument())
1058             scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event, ec);
1059         
1060         delete scheduledEvent;
1061     }
1062 }
1063
1064 IntRect FrameView::windowClipRect(bool clipToContents) const
1065 {
1066     ASSERT(m_frame->view() == this);
1067
1068     // Set our clip rect to be our contents.
1069     IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents));
1070     if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement())
1071         return clipRect;
1072
1073     // Take our owner element and get the clip rect from the enclosing layer.
1074     Element* elt = m_frame->document()->ownerElement();
1075     RenderLayer* layer = elt->renderer()->enclosingLayer();
1076     // FIXME: layer should never be null, but sometimes seems to be anyway.
1077     if (!layer)
1078         return clipRect;
1079     FrameView* parentView = elt->document()->view();
1080     clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
1081     return clipRect;
1082 }
1083
1084 IntRect FrameView::windowClipRectForLayer(const RenderLayer* layer, bool clipToLayerContents) const
1085 {
1086     // If we have no layer, just return our window clip rect.
1087     if (!layer)
1088         return windowClipRect();
1089
1090     // Apply the clip from the layer.
1091     IntRect clipRect;
1092     if (clipToLayerContents)
1093         clipRect = layer->childrenClipRect();
1094     else
1095         clipRect = layer->selfClipRect();
1096     clipRect = contentsToWindow(clipRect); 
1097     return intersection(clipRect, windowClipRect());
1098 }
1099
1100 bool FrameView::isActive() const
1101 {
1102     Page* page = frame()->page();
1103     return page && page->focusController()->isActive();
1104 }
1105
1106 void FrameView::valueChanged(Scrollbar* bar)
1107 {
1108     // Figure out if we really moved.
1109     IntSize offset = scrollOffset();
1110     ScrollView::valueChanged(bar);
1111     if (offset != scrollOffset())
1112         frame()->sendScrollEvent();
1113 }
1114
1115 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
1116 {
1117     // Add in our offset within the FrameView.
1118     IntRect dirtyRect = rect;
1119     dirtyRect.move(scrollbar->x(), scrollbar->y());
1120     invalidateRect(dirtyRect);
1121 }
1122
1123 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
1124 {
1125     tickmarks = frame()->document()->renderedRectsForMarkers(DocumentMarker::TextMatch);
1126 }
1127
1128 IntRect FrameView::windowResizerRect() const
1129 {
1130     Page* page = frame() ? frame()->page() : 0;
1131     if (!page)
1132         return IntRect();
1133     return page->chrome()->windowResizerRect();
1134 }
1135
1136 #if ENABLE(DASHBOARD_SUPPORT)
1137 void FrameView::updateDashboardRegions()
1138 {
1139     Document* document = m_frame->document();
1140     if (!document->hasDashboardRegions())
1141         return;
1142     Vector<DashboardRegionValue> newRegions;
1143     document->renderer()->collectDashboardRegions(newRegions);
1144     if (newRegions == document->dashboardRegions())
1145         return;
1146     document->setDashboardRegions(newRegions);
1147     Page* page = m_frame->page();
1148     if (!page)
1149         return;
1150     page->chrome()->client()->dashboardRegionsChanged();
1151 }
1152 #endif
1153
1154 void FrameView::updateControlTints()
1155 {
1156     // This is called when control tints are changed from aqua/graphite to clear and vice versa.
1157     // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
1158     // This is only done if the theme supports control tinting. It's up to the theme and platform
1159     // to define when controls get the tint and to call this function when that changes.
1160     
1161     // Optimize the common case where we bring a window to the front while it's still empty.
1162     if (!m_frame || m_frame->loader()->url().isEmpty()) 
1163         return;
1164     
1165     if (theme()->supportsControlTints() && m_frame->contentRenderer()) {
1166         if (needsLayout())
1167             layout();
1168         PlatformGraphicsContext* const noContext = 0;
1169         GraphicsContext context(noContext);
1170         context.setUpdatingControlTints(true);
1171         if (platformWidget())
1172             paintContents(&context, visibleContentRect());
1173         else
1174             paint(&context, frameRect());
1175     }
1176 }
1177
1178 bool FrameView::wasScrolledByUser() const
1179 {
1180     return d->m_wasScrolledByUser;
1181 }
1182
1183 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
1184 {
1185     if (d->m_inProgrammaticScroll)
1186         return;
1187     d->m_wasScrolledByUser = wasScrolledByUser;
1188 }
1189
1190 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
1191 {
1192     if (!frame())
1193         return;
1194     
1195     Document* document = frame()->document();
1196     if (!document)
1197         return;
1198
1199 #ifndef NDEBUG
1200     bool fillWithRed;
1201     if (document || document->printing())
1202         fillWithRed = false; // Printing, don't fill with red (can't remember why).
1203     else if (document->ownerElement())
1204         fillWithRed = false; // Subframe, don't fill with red.
1205     else if (isTransparent())
1206         fillWithRed = false; // Transparent, don't fill with red.
1207     else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyBlackText)
1208         fillWithRed = false; // Selections are transparent, don't fill with red.
1209     else if (d->m_nodeToDraw)
1210         fillWithRed = false; // Element images are transparent, don't fill with red.
1211     else
1212         fillWithRed = true;
1213     
1214     if (fillWithRed)
1215         p->fillRect(rect, Color(0xFF, 0, 0));
1216 #endif
1217
1218     bool isTopLevelPainter = !sCurrentPaintTimeStamp;
1219     if (isTopLevelPainter)
1220         sCurrentPaintTimeStamp = currentTime();
1221     
1222     RenderView* contentRenderer = frame()->contentRenderer();
1223     if (!contentRenderer) {
1224         LOG_ERROR("called Frame::paint with nil renderer");
1225         return;
1226     }
1227
1228     ASSERT(!needsLayout());
1229     ASSERT(!d->m_isPainting);
1230         
1231     d->m_isPainting = true;
1232         
1233     // m_nodeToDraw is used to draw only one element (and its descendants)
1234     RenderObject* eltRenderer = d->m_nodeToDraw ? d->m_nodeToDraw->renderer() : 0;
1235     if (d->m_paintRestriction == PaintRestrictionNone)
1236         document->invalidateRenderedRectsForMarkersInRect(rect);
1237     contentRenderer->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
1238         
1239     d->m_isPainting = false;
1240
1241 #if ENABLE(DASHBOARD_SUPPORT)
1242     // Regions may have changed as a result of the visibility/z-index of element changing.
1243     if (document->dashboardRegionsDirty())
1244         updateDashboardRegions();
1245 #endif
1246
1247     if (isTopLevelPainter)
1248         sCurrentPaintTimeStamp = 0;
1249 }
1250
1251 void FrameView::setPaintRestriction(PaintRestriction pr)
1252 {
1253     d->m_paintRestriction = pr;
1254 }
1255     
1256 bool FrameView::isPainting() const
1257 {
1258     return d->m_isPainting;
1259 }
1260
1261 void FrameView::setNodeToDraw(Node* node)
1262 {
1263     d->m_nodeToDraw = node;
1264 }
1265
1266 void FrameView::layoutIfNeededRecursive()
1267 {
1268     // We have to crawl our entire tree looking for any FrameViews that need
1269     // layout and make sure they are up to date.
1270     // Mac actually tests for intersection with the dirty region and tries not to
1271     // update layout for frames that are outside the dirty region.  Not only does this seem
1272     // pointless (since those frames will have set a zero timer to layout anyway), but
1273     // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
1274     // region but then become included later by the second frame adding rects to the dirty region
1275     // when it lays out.
1276
1277     if (needsLayout())
1278         layout();
1279
1280     const HashSet<Widget*>* viewChildren = children();
1281     HashSet<Widget*>::const_iterator end = viewChildren->end();
1282     for (HashSet<Widget*>::const_iterator current = viewChildren->begin(); current != end; ++current)
1283         if ((*current)->isFrameView())
1284             static_cast<FrameView*>(*current)->layoutIfNeededRecursive();
1285 }
1286
1287 void FrameView::setIsVisuallyNonEmpty()
1288 {
1289     d->m_isVisuallyNonEmpty = true;
1290 }
1291
1292 } // namespace WebCore