• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "config.h"
26 #include "FrameView.h"
27 
28 #include "AXObjectCache.h"
29 #include "CSSStyleSelector.h"
30 #include "ChromeClient.h"
31 #include "EventHandler.h"
32 #include "FloatRect.h"
33 #include "FocusController.h"
34 #include "Frame.h"
35 #include "FrameLoader.h"
36 #include "FrameLoaderClient.h"
37 #include "FrameTree.h"
38 #include "GraphicsContext.h"
39 #include "HTMLDocument.h"
40 #include "HTMLFrameElement.h"
41 #include "HTMLFrameSetElement.h"
42 #include "HTMLNames.h"
43 #include "OverflowEvent.h"
44 #include "Page.h"
45 #include "RenderPart.h"
46 #include "RenderPartObject.h"
47 #include "RenderScrollbar.h"
48 #include "RenderTheme.h"
49 #include "RenderView.h"
50 #include "Settings.h"
51 #include <wtf/CurrentTime.h>
52 
53 #ifdef ANDROID_INSTRUMENT
54 #include "FrameTree.h"
55 #include "TimeCounter.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<EventTargetNode> m_eventTarget;
67 };
68 
FrameView(Frame * frame)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 
FrameView(Frame * frame,const IntSize & initialSize)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 
~FrameView()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->document() || !m_frame->contentRenderer());
136         RenderPart* renderer = m_frame->ownerRenderer();
137         if (renderer && renderer->widget() == this)
138             renderer->setWidget(0);
139     }
140 }
141 
reset()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 
isFrameView() const171 bool FrameView::isFrameView() const
172 {
173     return true;
174 }
175 
clearFrame()176 void FrameView::clearFrame()
177 {
178     m_frame = 0;
179 }
180 
resetScrollbars()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 
init()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 
clear()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 
didFirstLayout() const226 bool FrameView::didFirstLayout() const
227 {
228     return !m_firstLayout;
229 }
230 
initScrollbars()231 void FrameView::initScrollbars()
232 {
233     if (!m_needToInitScrollbars)
234         return;
235     m_needToInitScrollbars = false;
236     updateDefaultScrollbarState();
237 }
238 
updateDefaultScrollbarState()239 void FrameView::updateDefaultScrollbarState()
240 {
241     m_hmode = horizontalScrollbarMode();
242     m_vmode = verticalScrollbarMode();
243     setScrollbarModes(m_hmode, m_vmode);
244 }
245 
invalidateRect(const IntRect & rect)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 
setMarginWidth(int w)267 void FrameView::setMarginWidth(int w)
268 {
269     // make it update the rendering area when set
270     m_margins.setWidth(w);
271 }
272 
setMarginHeight(int h)273 void FrameView::setMarginHeight(int h)
274 {
275     // make it update the rendering area when set
276     m_margins.setHeight(h);
277 }
278 
setCanHaveScrollbars(bool canScroll)279 void FrameView::setCanHaveScrollbars(bool canScroll)
280 {
281     ScrollView::setCanHaveScrollbars(canScroll);
282     scrollbarModes(m_hmode, m_vmode);
283 }
284 
createScrollbar(ScrollbarOrientation orientation)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     if (!doc)
290         return ScrollView::createScrollbar(orientation);
291 
292     // Try the <body> element first as a scrollbar source.
293     Element* body = doc->body();
294     if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
295         return RenderScrollbar::createCustomScrollbar(this, orientation, body->renderBox());
296 
297     // If the <body> didn't have a custom style, then the root element might.
298     Element* docElement = doc->documentElement();
299     if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
300         return RenderScrollbar::createCustomScrollbar(this, orientation, docElement->renderBox());
301 
302     // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
303     RenderPart* frameRenderer = m_frame->ownerRenderer();
304     if (frameRenderer && frameRenderer->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
305         return RenderScrollbar::createCustomScrollbar(this, orientation, frameRenderer);
306 
307     // Nobody set a custom style, so we just use a native scrollbar.
308     return ScrollView::createScrollbar(orientation);
309 }
310 
setContentsSize(const IntSize & size)311 void FrameView::setContentsSize(const IntSize& size)
312 {
313     ScrollView::setContentsSize(size);
314 
315     Page* page = frame() ? frame()->page() : 0;
316     if (!page)
317         return;
318 
319     page->chrome()->contentsSizeChanged(frame(), size); //notify only
320 }
321 
adjustViewSize()322 void FrameView::adjustViewSize()
323 {
324     ASSERT(m_frame->view() == this);
325     RenderView* root = m_frame->contentRenderer();
326     if (!root)
327         return;
328     setContentsSize(IntSize(root->overflowWidth(), root->overflowHeight()));
329 }
330 
applyOverflowToViewport(RenderObject * o,ScrollbarMode & hMode,ScrollbarMode & vMode)331 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
332 {
333     // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
334     // overflow:hidden and overflow:scroll on <body> as applying to the document's
335     // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
336     // use the root element.
337     switch (o->style()->overflowX()) {
338         case OHIDDEN:
339             hMode = ScrollbarAlwaysOff;
340             break;
341         case OSCROLL:
342             hMode = ScrollbarAlwaysOn;
343             break;
344         case OAUTO:
345             hMode = ScrollbarAuto;
346             break;
347         default:
348             // Don't set it at all.
349             ;
350     }
351 
352      switch (o->style()->overflowY()) {
353         case OHIDDEN:
354             vMode = ScrollbarAlwaysOff;
355             break;
356         case OSCROLL:
357             vMode = ScrollbarAlwaysOn;
358             break;
359         case OAUTO:
360             vMode = ScrollbarAuto;
361             break;
362         default:
363             // Don't set it at all.
364             ;
365     }
366 
367     m_viewportRenderer = o;
368 }
369 
layoutRoot(bool onlyDuringLayout) const370 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
371 {
372     return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot;
373 }
374 
layout(bool allowSubtree)375 void FrameView::layout(bool allowSubtree)
376 {
377     if (m_midLayout)
378         return;
379 
380     m_layoutTimer.stop();
381     m_delayedLayout = false;
382 
383     // Protect the view from being deleted during layout (in recalcStyle)
384     RefPtr<FrameView> protector(this);
385 
386     if (!m_frame) {
387         // FIXME: Do we need to set m_size.width here?
388         // FIXME: Should we set m_size.height here too?
389         m_size.setWidth(layoutWidth());
390         return;
391     }
392 
393     // we shouldn't enter layout() while painting
394     ASSERT(!isPainting());
395     if (isPainting())
396         return;
397 
398     if (!allowSubtree && m_layoutRoot) {
399         m_layoutRoot->markContainingBlocksForLayout(false);
400         m_layoutRoot = 0;
401     }
402 
403     ASSERT(m_frame->view() == this);
404     // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a
405     // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful
406     // failure instead.
407     if (m_frame->view() != this)
408         return;
409 
410     Document* document = m_frame->document();
411     if (!document) {
412         // FIXME: Should we set m_size.height here too?
413         m_size.setWidth(layoutWidth());
414         return;
415     }
416 
417     m_layoutSchedulingEnabled = false;
418 
419     if (!m_nestedLayoutCount && m_postLayoutTasksTimer.isActive()) {
420         // This is a new top-level layout. If there are any remaining tasks from the previous
421         // layout, finish them now.
422         m_postLayoutTasksTimer.stop();
423         performPostLayoutTasks();
424     }
425 
426     // Viewport-dependent media queries may cause us to need completely different style information.
427     // Check that here.
428     if (document->styleSelector()->affectedByViewportChange())
429         document->updateStyleSelector();
430 
431     // Always ensure our style info is up-to-date.  This can happen in situations where
432     // the layout beats any sort of style recalc update that needs to occur.
433     if (m_frame->needsReapplyStyles())
434         m_frame->reapplyStyles();
435     else if (document->hasChangedChild())
436         document->recalcStyle();
437 
438     bool subtree = m_layoutRoot;
439 
440     // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
441     // so there's no point to continuing to layout
442     if (protector->hasOneRef())
443         return;
444 
445     RenderObject* root = subtree ? m_layoutRoot : document->renderer();
446     if (!root) {
447         // FIXME: Do we need to set m_size here?
448         m_layoutSchedulingEnabled = true;
449         return;
450     }
451 
452 #ifdef ANDROID_INSTRUMENT
453     if (!m_frame->tree() || !m_frame->tree()->parent())
454         android::TimeCounter::start(android::TimeCounter::LayoutTimeCounter);
455 #endif
456 
457     m_nestedLayoutCount++;
458 
459     ScrollbarMode hMode = m_hmode;
460     ScrollbarMode vMode = m_vmode;
461 
462     if (!subtree) {
463         RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
464         Node* body = document->body();
465         if (body && body->renderer()) {
466             if (body->hasTagName(framesetTag)) {
467                 body->renderer()->setChildNeedsLayout(true);
468                 vMode = ScrollbarAlwaysOff;
469                 hMode = ScrollbarAlwaysOff;
470             } else if (body->hasTagName(bodyTag)) {
471                 if (!m_firstLayout && m_size.height() != layoutHeight()
472                         && toRenderBox(body->renderer())->stretchesToViewHeight())
473                     body->renderer()->setChildNeedsLayout(true);
474                 // It's sufficient to just check the X overflow,
475                 // since it's illegal to have visible in only one direction.
476                 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
477                 applyOverflowToViewport(o, hMode, vMode);
478             }
479         } else if (rootRenderer)
480             applyOverflowToViewport(rootRenderer, hMode, vMode);
481 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
482         if (m_firstLayout && !document->ownerElement())
483             printf("Elapsed time before first layout: %d\n", document->elapsedTime());
484 #endif
485     }
486 
487     m_doFullRepaint = !subtree && (m_firstLayout || static_cast<RenderView*>(root)->printing());
488 
489     if (!subtree) {
490         // Now set our scrollbar state for the layout.
491         ScrollbarMode currentHMode = horizontalScrollbarMode();
492         ScrollbarMode currentVMode = verticalScrollbarMode();
493 
494         if (m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
495             setScrollbarsSuppressed(true);
496             if (m_firstLayout) {
497                 m_firstLayout = false;
498                 m_firstLayoutCallbackPending = true;
499                 m_lastLayoutSize = IntSize(width(), height());
500                 m_lastZoomFactor = root->style()->zoom();
501 
502                 // Set the initial vMode to AlwaysOn if we're auto.
503                 if (vMode == ScrollbarAuto)
504                     setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
505                 // Set the initial hMode to AlwaysOff if we're auto.
506                 if (hMode == ScrollbarAuto)
507                     setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
508             }
509             setScrollbarModes(hMode, vMode);
510             setScrollbarsSuppressed(false, true);
511         }
512 
513         IntSize oldSize = m_size;
514 
515         m_size = IntSize(layoutWidth(), layoutHeight());
516 
517         if (oldSize != m_size)
518             m_doFullRepaint = true;
519     }
520 
521     RenderLayer* layer = root->enclosingLayer();
522 
523     pauseScheduledEvents();
524 
525     if (subtree)
526         root->view()->pushLayoutState(root);
527 
528     m_midLayout = true;
529     beginDeferredRepaints();
530     root->layout();
531     endDeferredRepaints();
532     m_midLayout = false;
533 
534     if (subtree)
535         root->view()->popLayoutState();
536     m_layoutRoot = 0;
537 
538     m_frame->invalidateSelection();
539 
540     m_layoutSchedulingEnabled = true;
541 
542     if (!subtree && !static_cast<RenderView*>(root)->printing())
543         adjustViewSize();
544 
545     // Now update the positions of all layers.
546     beginDeferredRepaints();
547     layer->updateLayerPositions(m_doFullRepaint);
548     endDeferredRepaints();
549 
550     m_layoutCount++;
551 
552 #if PLATFORM(MAC)
553     if (AXObjectCache::accessibilityEnabled())
554         root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
555 #endif
556 #if ENABLE(DASHBOARD_SUPPORT)
557     updateDashboardRegions();
558 #endif
559 
560 #ifdef ANDROID_INSTRUMENT
561     if (!m_frame->tree()->parent())
562         android::TimeCounter::record(android::TimeCounter::LayoutTimeCounter, __FUNCTION__);
563 #endif
564     ASSERT(!root->needsLayout());
565 
566     setCanBlitOnScroll(!useSlowRepaints());
567 
568     if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
569         updateOverflowStatus(layoutWidth() < contentsWidth(),
570                              layoutHeight() < contentsHeight());
571 
572     if (!m_postLayoutTasksTimer.isActive()) {
573         // Calls resumeScheduledEvents()
574         performPostLayoutTasks();
575 
576         if (needsLayout()) {
577             // Post-layout widget updates or an event handler made us need layout again.
578             // Lay out again, but this time defer widget updates and event dispatch until after
579             // we return.
580             m_postLayoutTasksTimer.startOneShot(0);
581             pauseScheduledEvents();
582             layout();
583         }
584     } else {
585         resumeScheduledEvents();
586         ASSERT(m_enqueueEvents);
587     }
588 
589     m_nestedLayoutCount--;
590 }
591 
addWidgetToUpdate(RenderPartObject * object)592 void FrameView::addWidgetToUpdate(RenderPartObject* object)
593 {
594     if (!m_widgetUpdateSet)
595         m_widgetUpdateSet.set(new HashSet<RenderPartObject*>);
596 
597     m_widgetUpdateSet->add(object);
598 }
599 
removeWidgetToUpdate(RenderPartObject * object)600 void FrameView::removeWidgetToUpdate(RenderPartObject* object)
601 {
602     if (!m_widgetUpdateSet)
603         return;
604 
605     m_widgetUpdateSet->remove(object);
606 }
607 
setMediaType(const String & mediaType)608 void FrameView::setMediaType(const String& mediaType)
609 {
610     m_mediaType = mediaType;
611 }
612 
mediaType() const613 String FrameView::mediaType() const
614 {
615     // See if we have an override type.
616     String overrideType = m_frame->loader()->client()->overrideMediaType();
617     if (!overrideType.isNull())
618         return overrideType;
619     return m_mediaType;
620 }
621 
useSlowRepaints() const622 bool FrameView::useSlowRepaints() const
623 {
624     return m_useSlowRepaints || m_slowRepaintObjectCount > 0;
625 }
626 
setUseSlowRepaints()627 void FrameView::setUseSlowRepaints()
628 {
629     m_useSlowRepaints = true;
630     setCanBlitOnScroll(false);
631 }
632 
addSlowRepaintObject()633 void FrameView::addSlowRepaintObject()
634 {
635     if (!m_slowRepaintObjectCount)
636         setCanBlitOnScroll(false);
637     m_slowRepaintObjectCount++;
638 }
639 
removeSlowRepaintObject()640 void FrameView::removeSlowRepaintObject()
641 {
642     ASSERT(m_slowRepaintObjectCount > 0);
643     m_slowRepaintObjectCount--;
644     if (!m_slowRepaintObjectCount)
645         setCanBlitOnScroll(!m_useSlowRepaints);
646 }
647 
restoreScrollbar()648 void FrameView::restoreScrollbar()
649 {
650     setScrollbarsSuppressed(false);
651 }
652 
scrollRectIntoViewRecursively(const IntRect & r)653 void FrameView::scrollRectIntoViewRecursively(const IntRect& r)
654 {
655     bool wasInProgrammaticScroll = m_inProgrammaticScroll;
656     m_inProgrammaticScroll = true;
657     ScrollView::scrollRectIntoViewRecursively(r);
658     m_inProgrammaticScroll = wasInProgrammaticScroll;
659 }
660 
setScrollPosition(const IntPoint & scrollPoint)661 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
662 {
663     bool wasInProgrammaticScroll = m_inProgrammaticScroll;
664     m_inProgrammaticScroll = true;
665     ScrollView::setScrollPosition(scrollPoint);
666     m_inProgrammaticScroll = wasInProgrammaticScroll;
667 }
668 
hostWindow() const669 HostWindow* FrameView::hostWindow() const
670 {
671     Page* page = frame() ? frame()->page() : 0;
672     if (!page)
673         return 0;
674     return page->chrome();
675 }
676 
677 const unsigned cRepaintRectUnionThreshold = 25;
678 
repaintContentRectangle(const IntRect & r,bool immediate)679 void FrameView::repaintContentRectangle(const IntRect& r, bool immediate)
680 {
681     ASSERT(!m_frame->document()->ownerElement());
682 
683     if (m_deferringRepaints && !immediate) {
684         IntRect visibleContent = visibleContentRect();
685         visibleContent.intersect(r);
686         if (!visibleContent.isEmpty()) {
687             m_repaintCount++;
688             m_repaintRect.unite(r);
689             if (m_repaintCount == cRepaintRectUnionThreshold)
690                 m_repaintRects.clear();
691             else if (m_repaintCount < cRepaintRectUnionThreshold)
692                 m_repaintRects.append(r);
693         }
694 #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
695         else
696             ScrollView::platformOffscreenContentRectangle(r);
697 #endif
698         return;
699     }
700 
701     if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen())
702         return;
703 
704     ScrollView::repaintContentRectangle(r, immediate);
705 }
706 
beginDeferredRepaints()707 void FrameView::beginDeferredRepaints()
708 {
709     Page* page = m_frame->page();
710     if (page->mainFrame() != m_frame)
711         return page->mainFrame()->view()->beginDeferredRepaints();
712 
713     m_deferringRepaints++;
714 #ifdef ANDROID_FIX // This allows sub frames to accumulate deferred repaints
715     if (m_deferringRepaints == 1) {
716 #endif
717     m_repaintCount = 0;
718     m_repaintRect = IntRect();
719     m_repaintRects.clear();
720 #ifdef ANDROID_FIX
721     }
722 #endif
723 }
724 
725 
endDeferredRepaints()726 void FrameView::endDeferredRepaints()
727 {
728     Page* page = m_frame->page();
729     if (page->mainFrame() != m_frame)
730         return page->mainFrame()->view()->endDeferredRepaints();
731 
732     ASSERT(m_deferringRepaints > 0);
733     if (--m_deferringRepaints == 0) {
734         if (m_repaintCount >= cRepaintRectUnionThreshold)
735             repaintContentRectangle(m_repaintRect, false);
736         else {
737             unsigned size = m_repaintRects.size();
738             for (unsigned i = 0; i < size; i++)
739                 repaintContentRectangle(m_repaintRects[i], false);
740             m_repaintRects.clear();
741         }
742     }
743 }
744 
layoutTimerFired(Timer<FrameView> *)745 void FrameView::layoutTimerFired(Timer<FrameView>*)
746 {
747 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
748     if (m_frame->document() && !m_frame->document()->ownerElement())
749         printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
750 #endif
751     layout();
752 }
753 
scheduleRelayout()754 void FrameView::scheduleRelayout()
755 {
756     ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
757     ASSERT(m_frame->view() == this);
758 
759     if (m_layoutRoot) {
760         m_layoutRoot->markContainingBlocksForLayout(false);
761         m_layoutRoot = 0;
762     }
763     if (!m_layoutSchedulingEnabled)
764         return;
765     if (!needsLayout())
766         return;
767     if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
768         return;
769 
770 #if defined(FLATTEN_IFRAME) || defined(FLATTEN_FRAMESET)
771     if (m_frame->ownerRenderer())
772         m_frame->ownerRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
773 #endif
774 
775 #ifdef ANDROID_MOBILE
776     int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay();
777 #else
778     int delay = m_frame->document()->minimumLayoutDelay();
779 #endif
780     if (m_layoutTimer.isActive() && m_delayedLayout && !delay)
781         unscheduleRelayout();
782     if (m_layoutTimer.isActive())
783         return;
784 
785     m_delayedLayout = delay != 0;
786 
787 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
788     if (!m_frame->document()->ownerElement())
789         printf("Scheduling layout for %d\n", delay);
790 #endif
791 
792     m_layoutTimer.startOneShot(delay * 0.001);
793 }
794 
isObjectAncestorContainerOf(RenderObject * ancestor,RenderObject * descendant)795 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
796 {
797     for (RenderObject* r = descendant; r; r = r->container()) {
798         if (r == ancestor)
799             return true;
800     }
801     return false;
802 }
803 
scheduleRelayoutOfSubtree(RenderObject * relayoutRoot)804 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
805 {
806     ASSERT(m_frame->view() == this);
807 
808     if (!m_layoutSchedulingEnabled || (m_frame->contentRenderer()
809             && m_frame->contentRenderer()->needsLayout())) {
810         if (relayoutRoot)
811             relayoutRoot->markContainingBlocksForLayout(false);
812         return;
813     }
814 
815     if (layoutPending()) {
816         if (m_layoutRoot != relayoutRoot) {
817             if (isObjectAncestorContainerOf(m_layoutRoot, relayoutRoot)) {
818                 // Keep the current root
819                 relayoutRoot->markContainingBlocksForLayout(false, m_layoutRoot);
820             } else if (m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, m_layoutRoot)) {
821                 // Re-root at relayoutRoot
822                 m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot);
823                 m_layoutRoot = relayoutRoot;
824             } else {
825                 // Just do a full relayout
826                 if (m_layoutRoot)
827                     m_layoutRoot->markContainingBlocksForLayout(false);
828                 m_layoutRoot = 0;
829                 relayoutRoot->markContainingBlocksForLayout(false);
830             }
831         }
832     } else {
833 #ifdef ANDROID_MOBILE
834         int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay();
835 #else
836         int delay = m_frame->document()->minimumLayoutDelay();
837 #endif
838         m_layoutRoot = relayoutRoot;
839         m_delayedLayout = delay != 0;
840         m_layoutTimer.startOneShot(delay * 0.001);
841     }
842 }
843 
layoutPending() const844 bool FrameView::layoutPending() const
845 {
846     return m_layoutTimer.isActive();
847 }
848 
needsLayout() const849 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 && document->hasChangedChild()) // can occur when using WebKit ObjC interface
862         || m_frame->needsReapplyStyles();
863 }
864 
setNeedsLayout()865 void FrameView::setNeedsLayout()
866 {
867     RenderView* root = m_frame->contentRenderer();
868     if (root)
869         root->setNeedsLayout(true);
870 }
871 
unscheduleRelayout()872 void FrameView::unscheduleRelayout()
873 {
874     if (!m_layoutTimer.isActive())
875         return;
876 
877 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
878     if (m_frame->document() && !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 
isTransparent() const886 bool FrameView::isTransparent() const
887 {
888     return m_isTransparent;
889 }
890 
setTransparent(bool isTransparent)891 void FrameView::setTransparent(bool isTransparent)
892 {
893     m_isTransparent = isTransparent;
894 }
895 
baseBackgroundColor() const896 Color FrameView::baseBackgroundColor() const
897 {
898     return m_baseBackgroundColor;
899 }
900 
setBaseBackgroundColor(Color bc)901 void FrameView::setBaseBackgroundColor(Color bc)
902 {
903     if (!bc.isValid())
904         bc = Color::white;
905     m_baseBackgroundColor = bc;
906 }
907 
updateBackgroundRecursively(const Color & backgroundColor,bool transparent)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 
shouldUpdateWhileOffscreen() const920 bool FrameView::shouldUpdateWhileOffscreen() const
921 {
922     return m_shouldUpdateWhileOffscreen;
923 }
924 
setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)925 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
926 {
927     m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
928 }
929 
scheduleEvent(PassRefPtr<Event> event,PassRefPtr<EventTargetNode> eventTarget)930 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> 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 
pauseScheduledEvents()944 void FrameView::pauseScheduledEvents()
945 {
946     ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents);
947     m_enqueueEvents++;
948 }
949 
resumeScheduledEvents()950 void FrameView::resumeScheduledEvents()
951 {
952     m_enqueueEvents--;
953     if (!m_enqueueEvents)
954         dispatchScheduledEvents();
955     ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents);
956 }
957 
performPostLayoutTasks()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->sendResizeEvent();
999     }
1000 }
1001 
postLayoutTimerFired(Timer<FrameView> *)1002 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
1003 {
1004     performPostLayoutTasks();
1005 }
1006 
updateOverflowStatus(bool horizontalOverflow,bool verticalOverflow)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             EventTargetNodeCast(m_viewportRenderer->element()));
1029     }
1030 
1031 }
1032 
dispatchScheduledEvents()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 
windowClipRect(bool clipToContents) const1055 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() || !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 
windowClipRectForLayer(const RenderLayer * layer,bool clipToLayerContents) const1075 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 
isActive() const1091 bool FrameView::isActive() const
1092 {
1093     Page* page = frame()->page();
1094     return page && page->focusController()->isActive();
1095 }
1096 
valueChanged(Scrollbar * bar)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()->sendScrollEvent();
1104 }
1105 
invalidateScrollbarRect(Scrollbar * scrollbar,const IntRect & rect)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 
getTickmarks(Vector<IntRect> & tickmarks) const1114 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
1115 {
1116     tickmarks = frame()->document()->renderedRectsForMarkers(DocumentMarker::TextMatch);
1117 }
1118 
windowResizerRect() const1119 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)
updateDashboardRegions()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 
updateControlTints()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 
wasScrolledByUser() const1169 bool FrameView::wasScrolledByUser() const
1170 {
1171     return m_wasScrolledByUser;
1172 }
1173 
setWasScrolledByUser(bool wasScrolledByUser)1174 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
1175 {
1176     if (m_inProgrammaticScroll)
1177         return;
1178     m_wasScrolledByUser = wasScrolledByUser;
1179 }
1180 
paintContents(GraphicsContext * p,const IntRect & rect)1181 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
1182 {
1183     if (!frame())
1184         return;
1185 
1186     Document* document = frame()->document();
1187     if (!document)
1188         return;
1189 
1190 #ifndef NDEBUG
1191     bool fillWithRed;
1192     if (document || document->printing())
1193         fillWithRed = false; // Printing, don't fill with red (can't remember why).
1194     else if (document->ownerElement())
1195         fillWithRed = false; // Subframe, don't fill with red.
1196     else if (isTransparent())
1197         fillWithRed = false; // Transparent, don't fill with red.
1198     else if (m_paintRestriction == PaintRestrictionSelectionOnly || m_paintRestriction == PaintRestrictionSelectionOnlyBlackText)
1199         fillWithRed = false; // Selections are transparent, don't fill with red.
1200     else if (m_nodeToDraw)
1201         fillWithRed = false; // Element images are transparent, don't fill with red.
1202     else
1203         fillWithRed = true;
1204 
1205     if (fillWithRed)
1206         p->fillRect(rect, Color(0xFF, 0, 0));
1207 #endif
1208 
1209     bool isTopLevelPainter = !sCurrentPaintTimeStamp;
1210     if (isTopLevelPainter)
1211         sCurrentPaintTimeStamp = currentTime();
1212 
1213     RenderView* contentRenderer = frame()->contentRenderer();
1214     if (!contentRenderer) {
1215         LOG_ERROR("called Frame::paint with nil renderer");
1216         return;
1217     }
1218 
1219     ASSERT(!needsLayout());
1220     ASSERT(!m_isPainting);
1221 
1222     m_isPainting = true;
1223 
1224     // m_nodeToDraw is used to draw only one element (and its descendants)
1225     RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
1226     if (m_paintRestriction == PaintRestrictionNone)
1227         document->invalidateRenderedRectsForMarkersInRect(rect);
1228     contentRenderer->layer()->paint(p, rect, m_paintRestriction, eltRenderer);
1229 
1230     m_isPainting = false;
1231 
1232 #if ENABLE(DASHBOARD_SUPPORT)
1233     // Regions may have changed as a result of the visibility/z-index of element changing.
1234     if (document->dashboardRegionsDirty())
1235         updateDashboardRegions();
1236 #endif
1237 
1238     if (isTopLevelPainter)
1239         sCurrentPaintTimeStamp = 0;
1240 }
1241 
setPaintRestriction(PaintRestriction pr)1242 void FrameView::setPaintRestriction(PaintRestriction pr)
1243 {
1244     m_paintRestriction = pr;
1245 }
1246 
isPainting() const1247 bool FrameView::isPainting() const
1248 {
1249     return m_isPainting;
1250 }
1251 
setNodeToDraw(Node * node)1252 void FrameView::setNodeToDraw(Node* node)
1253 {
1254     m_nodeToDraw = node;
1255 }
1256 
layoutIfNeededRecursive()1257 void FrameView::layoutIfNeededRecursive()
1258 {
1259     // We have to crawl our entire tree looking for any FrameViews that need
1260     // layout and make sure they are up to date.
1261     // Mac actually tests for intersection with the dirty region and tries not to
1262     // update layout for frames that are outside the dirty region.  Not only does this seem
1263     // pointless (since those frames will have set a zero timer to layout anyway), but
1264     // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
1265     // region but then become included later by the second frame adding rects to the dirty region
1266     // when it lays out.
1267 
1268     if (needsLayout())
1269         layout();
1270 
1271     const HashSet<Widget*>* viewChildren = children();
1272     HashSet<Widget*>::const_iterator end = viewChildren->end();
1273     for (HashSet<Widget*>::const_iterator current = viewChildren->begin(); current != end; ++current)
1274         if ((*current)->isFrameView())
1275             static_cast<FrameView*>(*current)->layoutIfNeededRecursive();
1276 }
1277 
1278 } // namespace WebCore
1279