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