• 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  * Copyright (C) 2009 Google Inc. All rights reserved.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB.  If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26 
27 #include "config.h"
28 #include "core/frame/FrameView.h"
29 
30 #include "core/HTMLNames.h"
31 #include "core/accessibility/AXObjectCache.h"
32 #include "core/css/FontFaceSet.h"
33 #include "core/css/resolver/StyleResolver.h"
34 #include "core/dom/DocumentMarkerController.h"
35 #include "core/dom/ScriptForbiddenScope.h"
36 #include "core/editing/FrameSelection.h"
37 #include "core/events/OverflowEvent.h"
38 #include "core/fetch/ResourceFetcher.h"
39 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
40 #include "core/frame/FrameHost.h"
41 #include "core/frame/LocalFrame.h"
42 #include "core/frame/Settings.h"
43 #include "core/html/HTMLFrameElement.h"
44 #include "core/html/HTMLPlugInElement.h"
45 #include "core/html/parser/TextResourceDecoder.h"
46 #include "core/inspector/InspectorInstrumentation.h"
47 #include "core/inspector/InspectorTraceEvents.h"
48 #include "core/loader/FrameLoader.h"
49 #include "core/loader/FrameLoaderClient.h"
50 #include "core/page/Chrome.h"
51 #include "core/page/ChromeClient.h"
52 #include "core/page/EventHandler.h"
53 #include "core/page/FocusController.h"
54 #include "core/page/FrameTree.h"
55 #include "core/page/scrolling/ScrollingCoordinator.h"
56 #include "core/rendering/FastTextAutosizer.h"
57 #include "core/rendering/RenderCounter.h"
58 #include "core/rendering/RenderEmbeddedObject.h"
59 #include "core/rendering/RenderLayer.h"
60 #include "core/rendering/RenderListBox.h"
61 #include "core/rendering/RenderPart.h"
62 #include "core/rendering/RenderScrollbar.h"
63 #include "core/rendering/RenderScrollbarPart.h"
64 #include "core/rendering/RenderTheme.h"
65 #include "core/rendering/RenderView.h"
66 #include "core/rendering/RenderWidget.h"
67 #include "core/rendering/TextAutosizer.h"
68 #include "core/rendering/compositing/CompositedLayerMapping.h"
69 #include "core/rendering/compositing/RenderLayerCompositor.h"
70 #include "core/rendering/style/RenderStyle.h"
71 #include "core/rendering/svg/RenderSVGRoot.h"
72 #include "core/svg/SVGDocumentExtensions.h"
73 #include "core/svg/SVGSVGElement.h"
74 #include "platform/RuntimeEnabledFeatures.h"
75 #include "platform/TraceEvent.h"
76 #include "platform/fonts/FontCache.h"
77 #include "platform/geometry/FloatRect.h"
78 #include "platform/graphics/GraphicsContext.h"
79 #include "platform/graphics/GraphicsLayerDebugInfo.h"
80 #include "platform/scroll/ScrollAnimator.h"
81 #include "platform/scroll/ScrollbarTheme.h"
82 #include "platform/text/TextStream.h"
83 #include "wtf/CurrentTime.h"
84 #include "wtf/TemporaryChange.h"
85 
86 namespace WebCore {
87 
88 using namespace HTMLNames;
89 
90 double FrameView::s_currentFrameTimeStamp = 0.0;
91 bool FrameView::s_inPaintContents = false;
92 
93 // The maximum number of updateWidgets iterations that should be done before returning.
94 static const unsigned maxUpdateWidgetsIterations = 2;
95 static const double resourcePriorityUpdateDelayAfterScroll = 0.250;
96 
updateLayerPositionFlags(RenderLayer * layer,bool isRelayoutingSubtree,bool didFullPaintInvalidation)97 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullPaintInvalidation)
98 {
99     RenderLayer::UpdateLayerPositionsFlags flags = didFullPaintInvalidation ? RenderLayer::NeedsFullRepaintInBacking : RenderLayer::CheckForRepaint;
100 
101     if (isRelayoutingSubtree && (layer->isPaginated() || layer->enclosingPaginationLayer()))
102         flags |= RenderLayer::UpdatePagination;
103 
104     return flags;
105 }
106 
FrameView(LocalFrame * frame)107 FrameView::FrameView(LocalFrame* frame)
108     : m_frame(frame)
109     , m_canHaveScrollbars(true)
110     , m_slowRepaintObjectCount(0)
111     , m_hasPendingLayout(false)
112     , m_layoutSubtreeRoot(0)
113     , m_inSynchronousPostLayout(false)
114     , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
115     , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
116     , m_isTransparent(false)
117     , m_baseBackgroundColor(Color::white)
118     , m_mediaType("screen")
119     , m_overflowStatusDirty(true)
120     , m_viewportRenderer(0)
121     , m_wasScrolledByUser(false)
122     , m_inProgrammaticScroll(false)
123     , m_safeToPropagateScrollToParent(true)
124     , m_isTrackingPaintInvalidations(false)
125     , m_scrollCorner(0)
126     , m_shouldAutoSize(false)
127     , m_inAutoSize(false)
128     , m_didRunAutosize(false)
129     , m_hasSoftwareFilters(false)
130     , m_visibleContentScaleFactor(1)
131     , m_inputEventsScaleFactorForEmulation(1)
132     , m_layoutSizeFixedToFrameSize(true)
133     , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
134 {
135     ASSERT(m_frame);
136     init();
137 
138     if (!m_frame->isMainFrame())
139         return;
140 
141     ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed);
142     ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed);
143 }
144 
create(LocalFrame * frame)145 PassRefPtr<FrameView> FrameView::create(LocalFrame* frame)
146 {
147     RefPtr<FrameView> view = adoptRef(new FrameView(frame));
148     view->show();
149     return view.release();
150 }
151 
create(LocalFrame * frame,const IntSize & initialSize)152 PassRefPtr<FrameView> FrameView::create(LocalFrame* frame, const IntSize& initialSize)
153 {
154     RefPtr<FrameView> view = adoptRef(new FrameView(frame));
155     view->Widget::setFrameRect(IntRect(view->location(), initialSize));
156     view->setLayoutSizeInternal(initialSize);
157 
158     view->show();
159     return view.release();
160 }
161 
~FrameView()162 FrameView::~FrameView()
163 {
164     if (m_postLayoutTasksTimer.isActive())
165         m_postLayoutTasksTimer.stop();
166 
167     if (m_didScrollTimer.isActive())
168         m_didScrollTimer.stop();
169 
170     removeFromAXObjectCache();
171     resetScrollbars();
172 
173     // Custom scrollbars should already be destroyed at this point
174     ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
175     ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
176 
177     setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
178     setHasVerticalScrollbar(false);
179 
180     ASSERT(!m_scrollCorner);
181 
182     ASSERT(m_frame);
183     ASSERT(m_frame->view() != this || !m_frame->contentRenderer());
184     // FIXME: Do we need to do something here for OOPI?
185     HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
186     if (ownerElement && ownerElement->ownedWidget() == this)
187         ownerElement->setWidget(nullptr);
188 }
189 
reset()190 void FrameView::reset()
191 {
192     m_cannotBlitToWindow = false;
193     m_isOverlapped = false;
194     m_contentIsOpaque = false;
195     m_hasPendingLayout = false;
196     m_layoutSubtreeRoot = 0;
197     m_doFullPaintInvalidation = false;
198     m_layoutSchedulingEnabled = true;
199     m_inPerformLayout = false;
200     m_canInvalidatePaintDuringPerformLayout = false;
201     m_inSynchronousPostLayout = false;
202     m_layoutCount = 0;
203     m_nestedLayoutCount = 0;
204     m_postLayoutTasksTimer.stop();
205     m_updateWidgetsTimer.stop();
206     m_firstLayout = true;
207     m_firstLayoutCallbackPending = false;
208     m_wasScrolledByUser = false;
209     m_safeToPropagateScrollToParent = true;
210     m_lastViewportSize = IntSize();
211     m_lastZoomFactor = 1.0f;
212     m_isTrackingPaintInvalidations = false;
213     m_trackedPaintInvalidationRects.clear();
214     m_lastPaintTime = 0;
215     m_paintBehavior = PaintBehaviorNormal;
216     m_isPainting = false;
217     m_visuallyNonEmptyCharacterCount = 0;
218     m_visuallyNonEmptyPixelCount = 0;
219     m_isVisuallyNonEmpty = false;
220     m_firstVisuallyNonEmptyLayoutCallbackPending = true;
221     m_maintainScrollPositionAnchor = nullptr;
222     m_viewportConstrainedObjects.clear();
223 }
224 
removeFromAXObjectCache()225 void FrameView::removeFromAXObjectCache()
226 {
227     if (AXObjectCache* cache = axObjectCache())
228         cache->remove(this);
229 }
230 
resetScrollbars()231 void FrameView::resetScrollbars()
232 {
233     // Reset the document's scrollbars back to our defaults before we yield the floor.
234     m_firstLayout = true;
235     setScrollbarsSuppressed(true);
236     if (m_canHaveScrollbars)
237         setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
238     else
239         setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
240     setScrollbarsSuppressed(false);
241 }
242 
init()243 void FrameView::init()
244 {
245     reset();
246 
247     m_size = LayoutSize();
248 
249     // Propagate the marginwidth/height and scrolling modes to the view.
250     // FIXME: Do we need to do this for OOPI?
251     Element* ownerElement = m_frame->deprecatedLocalOwner();
252     if (ownerElement && (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))) {
253         HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
254         if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
255             setCanHaveScrollbars(false);
256     }
257 }
258 
prepareForDetach()259 void FrameView::prepareForDetach()
260 {
261     RELEASE_ASSERT(!isInPerformLayout());
262 
263     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
264         scrollAnimator->cancelAnimations();
265 
266     detachCustomScrollbars();
267     // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
268     // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
269     removeFromAXObjectCache();
270 
271     if (m_frame->page()) {
272         if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
273             scrollingCoordinator->willDestroyScrollableArea(this);
274     }
275 }
276 
detachCustomScrollbars()277 void FrameView::detachCustomScrollbars()
278 {
279     Scrollbar* horizontalBar = horizontalScrollbar();
280     if (horizontalBar && horizontalBar->isCustomScrollbar())
281         setHasHorizontalScrollbar(false);
282 
283     Scrollbar* verticalBar = verticalScrollbar();
284     if (verticalBar && verticalBar->isCustomScrollbar())
285         setHasVerticalScrollbar(false);
286 
287     if (m_scrollCorner) {
288         m_scrollCorner->destroy();
289         m_scrollCorner = 0;
290     }
291 }
292 
recalculateScrollbarOverlayStyle()293 void FrameView::recalculateScrollbarOverlayStyle()
294 {
295     ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
296     ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
297 
298     Color backgroundColor = documentBackgroundColor();
299     // Reduce the background color from RGB to a lightness value
300     // and determine which scrollbar style to use based on a lightness
301     // heuristic.
302     double hue, saturation, lightness;
303     backgroundColor.getHSL(hue, saturation, lightness);
304     if (lightness <= .5)
305         overlayStyle = ScrollbarOverlayStyleLight;
306 
307     if (oldOverlayStyle != overlayStyle)
308         setScrollbarOverlayStyle(overlayStyle);
309 }
310 
clear()311 void FrameView::clear()
312 {
313     reset();
314     setScrollbarsSuppressed(true);
315 }
316 
didFirstLayout() const317 bool FrameView::didFirstLayout() const
318 {
319     return !m_firstLayout;
320 }
321 
invalidateRect(const IntRect & rect)322 void FrameView::invalidateRect(const IntRect& rect)
323 {
324     if (!parent()) {
325         if (HostWindow* window = hostWindow())
326             window->invalidateContentsAndRootView(rect);
327         return;
328     }
329 
330     RenderPart* renderer = m_frame->ownerRenderer();
331     if (!renderer)
332         return;
333 
334     IntRect paintInvalidationRect = rect;
335     paintInvalidationRect.move(renderer->borderLeft() + renderer->paddingLeft(),
336                      renderer->borderTop() + renderer->paddingTop());
337     renderer->invalidatePaintRectangle(paintInvalidationRect);
338 }
339 
setFrameRect(const IntRect & newRect)340 void FrameView::setFrameRect(const IntRect& newRect)
341 {
342     IntRect oldRect = frameRect();
343     if (newRect == oldRect)
344         return;
345 
346     // Autosized font sizes depend on the width of the viewing area.
347     bool autosizerNeedsUpdating = false;
348     if (newRect.width() != oldRect.width()) {
349         if (m_frame->isMainFrame() && m_frame->settings()->textAutosizingEnabled()) {
350             autosizerNeedsUpdating = true;
351             for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) {
352                 if (!frame->isLocalFrame())
353                     continue;
354                 if (TextAutosizer* textAutosizer = toLocalFrame(frame)->document()->textAutosizer())
355                     textAutosizer->recalculateMultipliers();
356             }
357         }
358     }
359 
360     ScrollView::setFrameRect(newRect);
361 
362     updateScrollableAreaSet();
363 
364     if (autosizerNeedsUpdating) {
365         // This needs to be after the call to ScrollView::setFrameRect, because it reads the new width.
366         if (FastTextAutosizer* textAutosizer = m_frame->document()->fastTextAutosizer())
367             textAutosizer->updatePageInfoInAllFrames();
368     }
369 
370     if (RenderView* renderView = this->renderView()) {
371         if (renderView->usesCompositing())
372             renderView->compositor()->frameViewDidChangeSize();
373     }
374 
375     viewportConstrainedVisibleContentSizeChanged(newRect.width() != oldRect.width(), newRect.height() != oldRect.height());
376 
377     if (oldRect.size() != newRect.size()
378         && m_frame->isMainFrame()
379         && m_frame->settings()->pinchVirtualViewportEnabled())
380         page()->frameHost().pinchViewport().mainFrameDidChangeSize();
381 }
382 
scheduleAnimation()383 bool FrameView::scheduleAnimation()
384 {
385     if (HostWindow* window = hostWindow()) {
386         window->scheduleAnimation();
387         return true;
388     }
389     return false;
390 }
391 
page() const392 Page* FrameView::page() const
393 {
394     return frame().page();
395 }
396 
renderView() const397 RenderView* FrameView::renderView() const
398 {
399     return frame().contentRenderer();
400 }
401 
setCanHaveScrollbars(bool canHaveScrollbars)402 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
403 {
404     m_canHaveScrollbars = canHaveScrollbars;
405     ScrollView::setCanHaveScrollbars(canHaveScrollbars);
406 }
407 
shouldUseCustomScrollbars(Element * & customScrollbarElement,LocalFrame * & customScrollbarFrame)408 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, LocalFrame*& customScrollbarFrame)
409 {
410     customScrollbarElement = 0;
411     customScrollbarFrame = 0;
412 
413     if (Settings* settings = m_frame->settings()) {
414         if (!settings->allowCustomScrollbarInMainFrame() && m_frame->isMainFrame())
415             return false;
416     }
417 
418     // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
419     Document* doc = m_frame->document();
420 
421     // Try the <body> element first as a scrollbar source.
422     Element* body = doc ? doc->body() : 0;
423     if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
424         customScrollbarElement = body;
425         return true;
426     }
427 
428     // If the <body> didn't have a custom style, then the root element might.
429     Element* docElement = doc ? doc->documentElement() : 0;
430     if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
431         customScrollbarElement = docElement;
432         return true;
433     }
434 
435     // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
436     RenderPart* frameRenderer = m_frame->ownerRenderer();
437     if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) {
438         customScrollbarFrame = m_frame.get();
439         return true;
440     }
441 
442     return false;
443 }
444 
createScrollbar(ScrollbarOrientation orientation)445 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
446 {
447     Element* customScrollbarElement = 0;
448     LocalFrame* customScrollbarFrame = 0;
449     if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame))
450         return RenderScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame);
451 
452     // Nobody set a custom style, so we just use a native scrollbar.
453     return ScrollView::createScrollbar(orientation);
454 }
455 
setContentsSize(const IntSize & size)456 void FrameView::setContentsSize(const IntSize& size)
457 {
458     if (size == contentsSize())
459         return;
460 
461     ScrollView::setContentsSize(size);
462     ScrollView::contentsResized();
463 
464     Page* page = frame().page();
465     if (!page)
466         return;
467 
468     updateScrollableAreaSet();
469 
470     page->chrome().contentsSizeChanged(m_frame.get(), size);
471 }
472 
clampOffsetAtScale(const IntPoint & offset,float scale) const473 IntPoint FrameView::clampOffsetAtScale(const IntPoint& offset, float scale) const
474 {
475     IntPoint maxScrollExtent(contentsSize().width() - scrollOrigin().x(), contentsSize().height() - scrollOrigin().y());
476     FloatSize scaledSize = unscaledVisibleContentSize();
477     if (scale)
478         scaledSize.scale(1 / scale);
479 
480     IntPoint clampedOffset = offset;
481     clampedOffset = clampedOffset.shrunkTo(maxScrollExtent - expandedIntSize(scaledSize));
482     clampedOffset = clampedOffset.expandedTo(-scrollOrigin());
483 
484     return clampedOffset;
485 }
486 
adjustViewSize()487 void FrameView::adjustViewSize()
488 {
489     RenderView* renderView = this->renderView();
490     if (!renderView)
491         return;
492 
493     ASSERT(m_frame->view() == this);
494 
495     const IntRect rect = renderView->documentRect();
496     const IntSize& size = rect.size();
497     ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize());
498 
499     setContentsSize(size);
500 }
501 
applyOverflowToViewportAndSetRenderer(RenderObject * o,ScrollbarMode & hMode,ScrollbarMode & vMode)502 void FrameView::applyOverflowToViewportAndSetRenderer(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
503 {
504     // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
505     // overflow:hidden and overflow:scroll on <body> as applying to the document's
506     // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
507     // use the root element.
508 
509     EOverflow overflowX = o->style()->overflowX();
510     EOverflow overflowY = o->style()->overflowY();
511 
512     if (o->isSVGRoot()) {
513         // Don't allow overflow to affect <img> and css backgrounds
514         if (toRenderSVGRoot(o)->isEmbeddedThroughSVGImage())
515             return;
516 
517         // FIXME: evaluate if we can allow overflow for these cases too.
518         // Overflow is always hidden when stand-alone SVG documents are embedded.
519         if (toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) {
520             overflowX = OHIDDEN;
521             overflowY = OHIDDEN;
522         }
523     }
524 
525     bool ignoreOverflowHidden = false;
526     if (m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame())
527         ignoreOverflowHidden = true;
528 
529     switch (overflowX) {
530         case OHIDDEN:
531             if (!ignoreOverflowHidden)
532                 hMode = ScrollbarAlwaysOff;
533             break;
534         case OSCROLL:
535             hMode = ScrollbarAlwaysOn;
536             break;
537         case OAUTO:
538             hMode = ScrollbarAuto;
539             break;
540         default:
541             // Don't set it at all.
542             ;
543     }
544 
545      switch (overflowY) {
546         case OHIDDEN:
547             if (!ignoreOverflowHidden)
548                 vMode = ScrollbarAlwaysOff;
549             break;
550         case OSCROLL:
551             vMode = ScrollbarAlwaysOn;
552             break;
553         case OAUTO:
554             vMode = ScrollbarAuto;
555             break;
556         default:
557             // Don't set it at all.
558             ;
559     }
560 
561     m_viewportRenderer = o;
562 }
563 
calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode & hMode,ScrollbarMode & vMode,ScrollbarModesCalculationStrategy strategy)564 void FrameView::calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
565 {
566     m_viewportRenderer = 0;
567 
568     // FIXME: How do we handle this for OOPI?
569     const HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
570     if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
571         hMode = ScrollbarAlwaysOff;
572         vMode = ScrollbarAlwaysOff;
573         return;
574     }
575 
576     if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
577         hMode = ScrollbarAuto;
578         vMode = ScrollbarAuto;
579     } else {
580         hMode = ScrollbarAlwaysOff;
581         vMode = ScrollbarAlwaysOff;
582     }
583 
584     if (!isSubtreeLayout()) {
585         Document* document = m_frame->document();
586         Node* body = document->body();
587         if (isHTMLFrameSetElement(body) && body->renderer()) {
588             vMode = ScrollbarAlwaysOff;
589             hMode = ScrollbarAlwaysOff;
590         } else if (Element* viewportElement = document->viewportDefiningElement()) {
591             if (RenderObject* viewportRenderer = viewportElement->renderer()) {
592                 if (viewportRenderer->style())
593                     applyOverflowToViewportAndSetRenderer(viewportRenderer, hMode, vMode);
594             }
595         }
596     }
597 }
598 
updateAcceleratedCompositingSettings()599 void FrameView::updateAcceleratedCompositingSettings()
600 {
601     if (RenderView* renderView = this->renderView())
602         renderView->compositor()->updateAcceleratedCompositingSettings();
603 }
604 
recalcOverflowAfterStyleChange()605 void FrameView::recalcOverflowAfterStyleChange()
606 {
607     RenderView* renderView = this->renderView();
608     ASSERT(renderView);
609     if (!renderView->needsOverflowRecalcAfterStyleChange())
610         return;
611 
612     renderView->recalcOverflowAfterStyleChange();
613 
614     if (needsLayout())
615         return;
616 
617     InUpdateScrollbarsScope inUpdateScrollbarsScope(this);
618 
619     bool shouldHaveHorizontalScrollbar = false;
620     bool shouldHaveVerticalScrollbar = false;
621     computeScrollbarExistence(shouldHaveHorizontalScrollbar, shouldHaveVerticalScrollbar);
622 
623     bool hasHorizontalScrollbar = horizontalScrollbar();
624     bool hasVerticalScrollbar = verticalScrollbar();
625     if (hasHorizontalScrollbar != shouldHaveHorizontalScrollbar
626         || hasVerticalScrollbar != shouldHaveVerticalScrollbar) {
627         setNeedsLayout();
628         return;
629     }
630 
631     adjustViewSize();
632     updateScrollbarGeometry();
633 }
634 
usesCompositedScrolling() const635 bool FrameView::usesCompositedScrolling() const
636 {
637     RenderView* renderView = this->renderView();
638     if (!renderView)
639         return false;
640     if (m_frame->settings() && m_frame->settings()->compositedScrollingForFramesEnabled())
641         return renderView->compositor()->inCompositingMode();
642     return false;
643 }
644 
layerForScrolling() const645 GraphicsLayer* FrameView::layerForScrolling() const
646 {
647     RenderView* renderView = this->renderView();
648     if (!renderView)
649         return 0;
650     return renderView->compositor()->scrollLayer();
651 }
652 
layerForHorizontalScrollbar() const653 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
654 {
655     RenderView* renderView = this->renderView();
656     if (!renderView)
657         return 0;
658     return renderView->compositor()->layerForHorizontalScrollbar();
659 }
660 
layerForVerticalScrollbar() const661 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
662 {
663     RenderView* renderView = this->renderView();
664     if (!renderView)
665         return 0;
666     return renderView->compositor()->layerForVerticalScrollbar();
667 }
668 
layerForScrollCorner() const669 GraphicsLayer* FrameView::layerForScrollCorner() const
670 {
671     RenderView* renderView = this->renderView();
672     if (!renderView)
673         return 0;
674     return renderView->compositor()->layerForScrollCorner();
675 }
676 
hasCompositedContent() const677 bool FrameView::hasCompositedContent() const
678 {
679     // FIXME: change to inCompositingMode. Fails fast/repaint/iframe-scroll-repaint.html.
680     if (RenderView* renderView = this->renderView())
681         return renderView->compositor()->staleInCompositingMode();
682     return false;
683 }
684 
isEnclosedInCompositingLayer() const685 bool FrameView::isEnclosedInCompositingLayer() const
686 {
687     // FIXME: It's a bug that compositing state isn't always up to date when this is called. crbug.com/366314
688     DisableCompositingQueryAsserts disabler;
689 
690     RenderObject* frameOwnerRenderer = m_frame->ownerRenderer();
691     if (frameOwnerRenderer && frameOwnerRenderer->enclosingLayer()->enclosingCompositingLayerForRepaint())
692         return true;
693 
694     if (FrameView* parentView = parentFrameView())
695         return parentView->isEnclosedInCompositingLayer();
696 
697     return false;
698 }
699 
layoutRoot(bool onlyDuringLayout) const700 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
701 {
702     return onlyDuringLayout && layoutPending() ? 0 : m_layoutSubtreeRoot;
703 }
704 
forceLayoutParentViewIfNeeded()705 inline void FrameView::forceLayoutParentViewIfNeeded()
706 {
707     RenderPart* ownerRenderer = m_frame->ownerRenderer();
708     if (!ownerRenderer || !ownerRenderer->frame())
709         return;
710 
711     RenderBox* contentBox = embeddedContentBox();
712     if (!contentBox)
713         return;
714 
715     RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
716     if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
717         return;
718 
719     // If the embedded SVG document appears the first time, the ownerRenderer has already finished
720     // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
721     // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
722     // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
723     // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
724     // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
725     // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
726     RefPtr<FrameView> frameView = ownerRenderer->frame()->view();
727 
728     // Mark the owner renderer as needing layout.
729     ownerRenderer->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
730 
731     // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
732     ASSERT(frameView);
733     frameView->layout();
734 }
735 
performPreLayoutTasks()736 void FrameView::performPreLayoutTasks()
737 {
738     TRACE_EVENT0("webkit", "FrameView::performPreLayoutTasks");
739     lifecycle().advanceTo(DocumentLifecycle::InPreLayout);
740 
741     // Don't schedule more layouts, we're in one.
742     TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
743 
744     if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) {
745         // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now.
746         m_inSynchronousPostLayout = true;
747         performPostLayoutTasks();
748         m_inSynchronousPostLayout = false;
749     }
750 
751     Document* document = m_frame->document();
752     document->notifyResizeForViewportUnits();
753 
754     // Viewport-dependent media queries may cause us to need completely different style information.
755     if (!document->styleResolver() || document->styleResolver()->mediaQueryAffectedByViewportChange()) {
756         document->styleResolverChanged();
757         document->mediaQueryAffectingValueChanged();
758 
759         // FIXME: This instrumentation event is not strictly accurate since cached media query results
760         //        do not persist across StyleResolver rebuilds.
761         InspectorInstrumentation::mediaQueryResultChanged(document);
762     } else {
763         document->evaluateMediaQueryList();
764     }
765 
766     document->updateRenderTreeIfNeeded();
767     lifecycle().advanceTo(DocumentLifecycle::StyleClean);
768 }
769 
performLayout(RenderObject * rootForThisLayout,bool inSubtreeLayout)770 void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout)
771 {
772     TRACE_EVENT0("webkit", "FrameView::performLayout");
773 
774     ScriptForbiddenScope forbidScript;
775 
776     ASSERT(!isInPerformLayout());
777     lifecycle().advanceTo(DocumentLifecycle::InPerformLayout);
778 
779     TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true);
780 
781     // performLayout is the actual guts of layout().
782     // FIXME: The 300 other lines in layout() probably belong in other helper functions
783     // so that a single human could understand what layout() is actually doing.
784 
785     LayoutState layoutState(*rootForThisLayout);
786 
787     forceLayoutParentViewIfNeeded();
788 
789     // FIXME (crbug.com/256657): Do not do two layouts for text autosizing.
790     rootForThisLayout->layout();
791     gatherDebugLayoutRects(rootForThisLayout);
792 
793     ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
794 
795     TextAutosizer* textAutosizer = frame().document()->textAutosizer();
796     bool autosized;
797     {
798         AllowPaintInvalidationScope paintInvalidationAllowed(this);
799         autosized = textAutosizer && textAutosizer->processSubtree(rootForThisLayout);
800     }
801 
802     if (autosized && rootForThisLayout->needsLayout()) {
803         TRACE_EVENT0("webkit", "2nd layout due to Text Autosizing");
804         UseCounter::count(*frame().document(), UseCounter::TextAutosizingLayout);
805         rootForThisLayout->layout();
806         gatherDebugLayoutRects(rootForThisLayout);
807     }
808 
809     lifecycle().advanceTo(DocumentLifecycle::AfterPerformLayout);
810 }
811 
scheduleOrPerformPostLayoutTasks()812 void FrameView::scheduleOrPerformPostLayoutTasks()
813 {
814     if (m_postLayoutTasksTimer.isActive())
815         return;
816 
817     if (!m_inSynchronousPostLayout) {
818         m_inSynchronousPostLayout = true;
819         // Calls resumeScheduledEvents()
820         performPostLayoutTasks();
821         m_inSynchronousPostLayout = false;
822     }
823 
824     if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout)) {
825         // If we need layout or are already in a synchronous call to postLayoutTasks(),
826         // defer widget updates and event dispatch until after we return. postLayoutTasks()
827         // can make us need to update again, and we can get stuck in a nasty cycle unless
828         // we call it through the timer here.
829         m_postLayoutTasksTimer.startOneShot(0, FROM_HERE);
830         if (needsLayout())
831             layout();
832     }
833 }
834 
layout(bool allowSubtree)835 void FrameView::layout(bool allowSubtree)
836 {
837     // We should never layout a Document which is not in a LocalFrame.
838     ASSERT(m_frame);
839     ASSERT(m_frame->view() == this);
840     ASSERT(m_frame->page());
841 
842     if (isInPerformLayout() || !m_frame->document()->isActive())
843         return;
844 
845     TRACE_EVENT0("webkit", "FrameView::layout");
846     TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "Layout");
847 
848     // Protect the view from being deleted during layout (in recalcStyle)
849     RefPtr<FrameView> protector(this);
850 
851     // Every scroll that happens during layout is programmatic.
852     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
853 
854     m_hasPendingLayout = false;
855     DocumentLifecycle::Scope lifecycleScope(lifecycle(), DocumentLifecycle::LayoutClean);
856 
857     RELEASE_ASSERT(!isPainting());
858 
859     TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "beginData", InspectorLayoutEvent::beginData(this));
860     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
861     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
862     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get());
863 
864     if (!allowSubtree && isSubtreeLayout()) {
865         m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
866         m_layoutSubtreeRoot = 0;
867     }
868 
869     performPreLayoutTasks();
870 
871     // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
872     // so there's no point to continuing to layout
873     if (protector->hasOneRef())
874         return;
875 
876     Document* document = m_frame->document();
877     bool inSubtreeLayout = isSubtreeLayout();
878     RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderView();
879     if (!rootForThisLayout) {
880         // FIXME: Do we need to set m_size here?
881         ASSERT_NOT_REACHED();
882         return;
883     }
884 
885     FontCachePurgePreventer fontCachePurgePreventer;
886     RenderLayer* layer;
887     {
888         TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
889 
890         m_nestedLayoutCount++;
891         if (!inSubtreeLayout) {
892             Document* document = m_frame->document();
893             Node* body = document->body();
894             if (body && body->renderer()) {
895                 if (isHTMLFrameSetElement(*body)) {
896                     body->renderer()->setChildNeedsLayout();
897                 } else if (isHTMLBodyElement(*body)) {
898                     if (!m_firstLayout && m_size.height() != layoutSize().height() && body->renderer()->enclosingBox()->stretchesToViewport())
899                         body->renderer()->setChildNeedsLayout();
900                 }
901             }
902         }
903         updateCounters();
904         autoSizeIfEnabled();
905 
906         ScrollbarMode hMode;
907         ScrollbarMode vMode;
908         calculateScrollbarModesForLayoutAndSetViewportRenderer(hMode, vMode);
909 
910         if (!inSubtreeLayout) {
911             // Now set our scrollbar state for the layout.
912             ScrollbarMode currentHMode = horizontalScrollbarMode();
913             ScrollbarMode currentVMode = verticalScrollbarMode();
914 
915             if (m_firstLayout) {
916                 setScrollbarsSuppressed(true);
917 
918                 m_doFullPaintInvalidation = true;
919                 m_firstLayout = false;
920                 m_firstLayoutCallbackPending = true;
921                 m_lastViewportSize = layoutSize(IncludeScrollbars);
922                 m_lastZoomFactor = rootForThisLayout->style()->zoom();
923 
924                 // Set the initial vMode to AlwaysOn if we're auto.
925                 if (vMode == ScrollbarAuto)
926                     setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
927                 // Set the initial hMode to AlwaysOff if we're auto.
928                 if (hMode == ScrollbarAuto)
929                     setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
930 
931                 setScrollbarModes(hMode, vMode);
932                 setScrollbarsSuppressed(false, true);
933             } else if (hMode != currentHMode || vMode != currentVMode) {
934                 setScrollbarModes(hMode, vMode);
935             }
936 
937             LayoutSize oldSize = m_size;
938 
939             m_size = LayoutSize(layoutSize().width(), layoutSize().height());
940 
941             if (oldSize != m_size && !m_firstLayout) {
942                 RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0;
943                 RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0;
944                 if (bodyRenderer && bodyRenderer->stretchesToViewport())
945                     bodyRenderer->setChildNeedsLayout();
946                 else if (rootRenderer && rootRenderer->stretchesToViewport())
947                     rootRenderer->setChildNeedsLayout();
948             }
949 
950             // We need to set m_doFullPaintInvalidation before triggering layout as RenderObject::checkForPaintInvalidation
951             // checks the boolean to disable local paint invalidations.
952             m_doFullPaintInvalidation |= renderView()->shouldDoFullRepaintForNextLayout();
953         }
954 
955         layer = rootForThisLayout->enclosingLayer();
956 
957         performLayout(rootForThisLayout, inSubtreeLayout);
958 
959         m_layoutSubtreeRoot = 0;
960     } // Reset m_layoutSchedulingEnabled to its previous value.
961 
962     if (!inSubtreeLayout && !toRenderView(rootForThisLayout)->document().printing())
963         adjustViewSize();
964 
965     layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, inSubtreeLayout, m_doFullPaintInvalidation));
966     renderView()->compositor()->didLayout();
967 
968     m_layoutCount++;
969 
970     if (AXObjectCache* cache = rootForThisLayout->document().axObjectCache()) {
971         const KURL& url = rootForThisLayout->document().url();
972         if (url.isValid() && !url.isAboutBlankURL())
973             cache->handleLayoutComplete(rootForThisLayout);
974     }
975     updateAnnotatedRegions();
976 
977     ASSERT(!rootForThisLayout->needsLayout());
978 
979     if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
980         updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight());
981 
982     scheduleOrPerformPostLayoutTasks();
983 
984     TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "endData", InspectorLayoutEvent::endData(rootForThisLayout));
985     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
986     InspectorInstrumentation::didLayout(cookie, rootForThisLayout);
987 
988     m_nestedLayoutCount--;
989     if (m_nestedLayoutCount)
990         return;
991 
992     if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) {
993         invalidateTree(rootForThisLayout);
994     } else if (m_doFullPaintInvalidation) {
995         // FIXME: This isn't really right, since the RenderView doesn't fully encompass
996         // the visibleContentRect(). It just happens to work out most of the time,
997         // since first layouts and printing don't have you scrolled anywhere.
998         renderView()->paintInvalidationForWholeRenderer();
999     }
1000 
1001     m_doFullPaintInvalidation = false;
1002 
1003 #ifndef NDEBUG
1004     // Post-layout assert that nobody was re-marked as needing layout during layout.
1005     document->renderView()->assertSubtreeIsLaidOut();
1006 #endif
1007 
1008     // FIXME: It should be not possible to remove the FrameView from the frame/page during layout
1009     // however m_inPerformLayout is not set for most of this function, so none of our RELEASE_ASSERTS
1010     // in LocalFrame/Page will fire. One of the post-layout tasks is disconnecting the LocalFrame from
1011     // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html
1012     // necessitating this check here.
1013     // ASSERT(frame()->page());
1014     if (frame().page())
1015         frame().page()->chrome().client().layoutUpdated(m_frame.get());
1016 }
1017 
1018 // The plan is to move to compositor-queried paint invalidation, in which case this
1019 // method would setNeedsRedraw on the GraphicsLayers with invalidations and
1020 // let the compositor pick which to actually draw.
1021 // See http://crbug.com/306706
invalidateTree(RenderObject * root)1022 void FrameView::invalidateTree(RenderObject* root)
1023 {
1024     ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled());
1025     ASSERT(!root->needsLayout());
1026     // We should only invalidate paints for the outer most layout. This works as
1027     // we continue to track paint invalidation rects until this function is called.
1028     ASSERT(!m_nestedLayoutCount);
1029 
1030     TRACE_EVENT1("blink", "FrameView::invalidateTree", "root", root->debugName().ascii());
1031 
1032     // FIXME: really, we're in the paint invalidation phase here, and the compositing queries are legal.
1033     // Until those states are fully fledged, I'll just disable the ASSERTS.
1034     DisableCompositingQueryAsserts compositingQueryAssertsDisabler;
1035 
1036     LayoutState rootLayoutState(*root);
1037 
1038     root->invalidateTreeAfterLayout(*root->containerForPaintInvalidation());
1039 
1040     // Invalidate the paint of the frameviews scrollbars if needed
1041     if (hasVerticalBarDamage())
1042         invalidateRect(verticalBarDamage());
1043     if (hasHorizontalBarDamage())
1044         invalidateRect(horizontalBarDamage());
1045     resetScrollbarDamage();
1046 }
1047 
lifecycle() const1048 DocumentLifecycle& FrameView::lifecycle() const
1049 {
1050     return m_frame->document()->lifecycle();
1051 }
1052 
gatherDebugLayoutRects(RenderObject * layoutRoot)1053 void FrameView::gatherDebugLayoutRects(RenderObject* layoutRoot)
1054 {
1055     bool isTracing;
1056     TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
1057     if (!isTracing)
1058         return;
1059     if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping())
1060         return;
1061     GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer();
1062     if (!graphicsLayer)
1063         return;
1064 
1065     GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo();
1066 
1067     debugInfo.currentLayoutRects().clear();
1068     for (RenderObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) {
1069         if (renderer->layoutDidGetCalled()) {
1070             FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->previousPaintInvalidationRect()));
1071             LayoutRect rect = quad.enclosingBoundingBox();
1072             debugInfo.currentLayoutRects().append(rect);
1073             renderer->setLayoutDidGetCalled(false);
1074         }
1075     }
1076 }
1077 
embeddedContentBox() const1078 RenderBox* FrameView::embeddedContentBox() const
1079 {
1080     RenderView* renderView = this->renderView();
1081     if (!renderView)
1082         return 0;
1083 
1084     RenderObject* firstChild = renderView->firstChild();
1085     if (!firstChild || !firstChild->isBox())
1086         return 0;
1087 
1088     // Curently only embedded SVG documents participate in the size-negotiation logic.
1089     if (firstChild->isSVGRoot())
1090         return toRenderBox(firstChild);
1091 
1092     return 0;
1093 }
1094 
1095 
addWidget(RenderWidget * object)1096 void FrameView::addWidget(RenderWidget* object)
1097 {
1098     m_widgets.add(object);
1099 }
1100 
removeWidget(RenderWidget * object)1101 void FrameView::removeWidget(RenderWidget* object)
1102 {
1103     m_widgets.remove(object);
1104 }
1105 
updateWidgetPositions()1106 void FrameView::updateWidgetPositions()
1107 {
1108     Vector<RefPtr<RenderWidget> > widgets;
1109     copyToVector(m_widgets, widgets);
1110 
1111     // Script or plugins could detach the frame so abort processing if that happens.
1112 
1113     for (size_t i = 0; i < widgets.size() && renderView(); ++i)
1114         widgets[i]->updateWidgetPosition();
1115 
1116     for (size_t i = 0; i < widgets.size() && renderView(); ++i)
1117         widgets[i]->widgetPositionsUpdated();
1118 }
1119 
addWidgetToUpdate(RenderEmbeddedObject & object)1120 void FrameView::addWidgetToUpdate(RenderEmbeddedObject& object)
1121 {
1122     ASSERT(isInPerformLayout());
1123     // Tell the DOM element that it needs a widget update.
1124     Node* node = object.node();
1125     ASSERT(node);
1126     if (isHTMLObjectElement(*node) || isHTMLEmbedElement(*node))
1127         toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true);
1128 
1129     m_widgetUpdateSet.add(&object);
1130 }
1131 
setMediaType(const AtomicString & mediaType)1132 void FrameView::setMediaType(const AtomicString& mediaType)
1133 {
1134     ASSERT(m_frame->document());
1135     m_frame->document()->mediaQueryAffectingValueChanged();
1136     m_mediaType = mediaType;
1137 }
1138 
mediaType() const1139 AtomicString FrameView::mediaType() const
1140 {
1141     // See if we have an override type.
1142     String overrideType;
1143     InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType);
1144     if (!overrideType.isNull())
1145         return AtomicString(overrideType);
1146     return m_mediaType;
1147 }
1148 
adjustMediaTypeForPrinting(bool printing)1149 void FrameView::adjustMediaTypeForPrinting(bool printing)
1150 {
1151     if (printing) {
1152         if (m_mediaTypeWhenNotPrinting.isNull())
1153             m_mediaTypeWhenNotPrinting = mediaType();
1154             setMediaType("print");
1155     } else {
1156         if (!m_mediaTypeWhenNotPrinting.isNull())
1157             setMediaType(m_mediaTypeWhenNotPrinting);
1158         m_mediaTypeWhenNotPrinting = nullAtom;
1159     }
1160 }
1161 
useSlowRepaints(bool considerOverlap) const1162 bool FrameView::useSlowRepaints(bool considerOverlap) const
1163 {
1164     // FIXME: It is incorrect to determine blit-scrolling eligibility using dirty compositing state.
1165     // https://code.google.com/p/chromium/issues/detail?id=357345
1166     DisableCompositingQueryAsserts disabler;
1167 
1168     if (m_slowRepaintObjectCount > 0)
1169         return true;
1170 
1171     if (contentsInCompositedLayer())
1172         return false;
1173 
1174     // The chromium compositor does not support scrolling a non-composited frame within a composited page through
1175     // the fast scrolling path, so force slow scrolling in that case.
1176     if (m_frame->owner() && !hasCompositedContent() && m_frame->page() && m_frame->page()->mainFrame()->isLocalFrame() && m_frame->page()->deprecatedLocalMainFrame()->view()->hasCompositedContent())
1177         return true;
1178 
1179     if (m_isOverlapped && considerOverlap)
1180         return true;
1181 
1182     if (m_cannotBlitToWindow)
1183         return true;
1184 
1185     if (!m_contentIsOpaque)
1186         return true;
1187 
1188     if (FrameView* parentView = parentFrameView())
1189         return parentView->useSlowRepaints(considerOverlap);
1190 
1191     return false;
1192 }
1193 
useSlowRepaintsIfNotOverlapped() const1194 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1195 {
1196     return useSlowRepaints(false);
1197 }
1198 
shouldAttemptToScrollUsingFastPath() const1199 bool FrameView::shouldAttemptToScrollUsingFastPath() const
1200 {
1201     return !useSlowRepaints();
1202 }
1203 
contentsInCompositedLayer() const1204 bool FrameView::contentsInCompositedLayer() const
1205 {
1206     RenderView* renderView = this->renderView();
1207     if (renderView && renderView->compositingState() == PaintsIntoOwnBacking) {
1208         GraphicsLayer* layer = renderView->layer()->compositedLayerMapping()->mainGraphicsLayer();
1209         if (layer && layer->drawsContent())
1210             return true;
1211     }
1212 
1213     return false;
1214 }
1215 
setCannotBlitToWindow()1216 void FrameView::setCannotBlitToWindow()
1217 {
1218     m_cannotBlitToWindow = true;
1219 }
1220 
addSlowRepaintObject()1221 void FrameView::addSlowRepaintObject()
1222 {
1223     if (!m_slowRepaintObjectCount++) {
1224         if (Page* page = m_frame->page()) {
1225             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1226                 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1227         }
1228     }
1229 }
1230 
removeSlowRepaintObject()1231 void FrameView::removeSlowRepaintObject()
1232 {
1233     ASSERT(m_slowRepaintObjectCount > 0);
1234     m_slowRepaintObjectCount--;
1235     if (!m_slowRepaintObjectCount) {
1236         if (Page* page = m_frame->page()) {
1237             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1238                 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1239         }
1240     }
1241 }
1242 
addViewportConstrainedObject(RenderObject * object)1243 void FrameView::addViewportConstrainedObject(RenderObject* object)
1244 {
1245     if (!m_viewportConstrainedObjects)
1246         m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet);
1247 
1248     if (!m_viewportConstrainedObjects->contains(object)) {
1249         m_viewportConstrainedObjects->add(object);
1250 
1251         if (Page* page = m_frame->page()) {
1252             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1253                 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1254         }
1255     }
1256 }
1257 
removeViewportConstrainedObject(RenderObject * object)1258 void FrameView::removeViewportConstrainedObject(RenderObject* object)
1259 {
1260     if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) {
1261         m_viewportConstrainedObjects->remove(object);
1262 
1263         if (Page* page = m_frame->page()) {
1264             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1265                 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1266         }
1267     }
1268 }
1269 
viewportConstrainedVisibleContentRect() const1270 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1271 {
1272     LayoutRect viewportRect = visibleContentRect();
1273     // Ignore overhang. No-op when not using rubber banding.
1274     viewportRect.setLocation(clampScrollPosition(scrollPosition()));
1275     return viewportRect;
1276 }
1277 
viewportConstrainedVisibleContentSizeChanged(bool widthChanged,bool heightChanged)1278 void FrameView::viewportConstrainedVisibleContentSizeChanged(bool widthChanged, bool heightChanged)
1279 {
1280     if (!hasViewportConstrainedObjects())
1281         return;
1282 
1283     // If viewport is not enabled, frameRect change will cause layout size change and then layout.
1284     // Otherwise, viewport constrained objects need their layout flags set separately to ensure
1285     // they are positioned correctly. In the virtual-viewport pinch mode frame rect changes wont
1286     // necessarily cause a layout size change so only take this early-out if we're in old-style
1287     // pinch.
1288     if (m_frame->settings()
1289         && !m_frame->settings()->viewportEnabled()
1290         && !m_frame->settings()->pinchVirtualViewportEnabled())
1291         return;
1292 
1293     ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1294     for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1295         RenderObject* renderer = *it;
1296         RenderStyle* style = renderer->style();
1297         if (widthChanged) {
1298             if (style->width().isFixed() && (style->left().isAuto() || style->right().isAuto()))
1299                 renderer->setNeedsPositionedMovementLayout();
1300             else
1301                 renderer->setNeedsLayoutAndFullPaintInvalidation();
1302         }
1303         if (heightChanged) {
1304             if (style->height().isFixed() && (style->top().isAuto() || style->bottom().isAuto()))
1305                 renderer->setNeedsPositionedMovementLayout();
1306             else
1307                 renderer->setNeedsLayoutAndFullPaintInvalidation();
1308         }
1309     }
1310 }
1311 
scrollOffsetForFixedPosition() const1312 IntSize FrameView::scrollOffsetForFixedPosition() const
1313 {
1314     return toIntSize(clampScrollPosition(scrollPosition()));
1315 }
1316 
lastKnownMousePosition() const1317 IntPoint FrameView::lastKnownMousePosition() const
1318 {
1319     return m_frame->eventHandler().lastKnownMousePosition();
1320 }
1321 
shouldSetCursor() const1322 bool FrameView::shouldSetCursor() const
1323 {
1324     Page* page = frame().page();
1325     return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive() && page->settings().deviceSupportsMouse();
1326 }
1327 
scrollContentsIfNeededRecursive()1328 void FrameView::scrollContentsIfNeededRecursive()
1329 {
1330     scrollContentsIfNeeded();
1331 
1332     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
1333         if (!child->isLocalFrame())
1334             continue;
1335         if (FrameView* view = toLocalFrame(child)->view())
1336             view->scrollContentsIfNeededRecursive();
1337     }
1338 }
1339 
scrollContentsIfNeeded()1340 void FrameView::scrollContentsIfNeeded()
1341 {
1342     bool didScroll = !pendingScrollDelta().isZero();
1343     ScrollView::scrollContentsIfNeeded();
1344     if (didScroll)
1345         updateFixedElementPaintInvalidationRectsAfterScroll();
1346 }
1347 
scrollContentsFastPath(const IntSize & scrollDelta,const IntRect & rectToScroll,const IntRect & clipRect)1348 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1349 {
1350     if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1351         hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1352         return true;
1353     }
1354 
1355     const bool isCompositedContentLayer = contentsInCompositedLayer();
1356 
1357     // Get the rects of the fixed objects visible in the rectToScroll
1358     Region regionToUpdate;
1359     ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1360     for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1361         RenderObject* renderer = *it;
1362         // m_viewportConstrainedObjects should not contain non-viewport constrained objects.
1363         ASSERT(renderer->style()->hasViewportConstrainedPosition());
1364 
1365         // Fixed items should always have layers.
1366         ASSERT(renderer->hasLayer());
1367         RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1368 
1369         // Layers that paint into their ancestor or into a grouped backing will still need
1370         // to apply a paint invalidation. If the layer paints into its own backing, then
1371         // it does not need paint invalidation just to scroll.
1372         if (layer->compositingState() == PaintsIntoOwnBacking)
1373             continue;
1374 
1375         if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1376             || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1377             // Don't invalidate for invisible fixed layers.
1378             continue;
1379         }
1380 
1381         if (layer->hasAncestorWithFilterOutsets()) {
1382             // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1383             // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1384             return false;
1385         }
1386 
1387         IntRect updateRect = pixelSnappedIntRect(layer->repainter().repaintRectIncludingNonCompositingDescendants());
1388 
1389         const RenderLayerModelObject* repaintContainer = layer->renderer()->containerForPaintInvalidation();
1390         if (repaintContainer && !repaintContainer->isRenderView()) {
1391             // If the fixed-position layer is contained by a composited layer that is not its containing block,
1392             // then we have to invalidate that enclosing layer, not the RenderView.
1393             // FIXME: Why do we need to issue this invalidation? Won't the fixed position element just scroll
1394             //        with the enclosing layer.
1395             updateRect.moveBy(scrollPosition());
1396             IntRect previousRect = updateRect;
1397             previousRect.move(scrollDelta);
1398             updateRect.unite(previousRect);
1399             layer->renderer()->invalidatePaintUsingContainer(repaintContainer, updateRect, InvalidationScroll);
1400         } else {
1401             // Coalesce the paint invalidations that will be issued to the renderView.
1402             updateRect = contentsToRootView(updateRect);
1403             if (!isCompositedContentLayer && clipsPaintInvalidations())
1404                 updateRect.intersect(rectToScroll);
1405             if (!updateRect.isEmpty())
1406                 regionToUpdate.unite(updateRect);
1407         }
1408     }
1409 
1410     // 1) scroll
1411     hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1412 
1413     // 2) update the area of fixed objects that has been invalidated
1414     Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1415     size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1416     for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1417         IntRect updateRect = subRectsToUpdate[i];
1418         IntRect scrolledRect = updateRect;
1419         scrolledRect.move(-scrollDelta);
1420         updateRect.unite(scrolledRect);
1421         if (isCompositedContentLayer) {
1422             updateRect = rootViewToContents(updateRect);
1423             ASSERT(renderView());
1424             renderView()->layer()->repainter().setBackingNeedsRepaintInRect(updateRect);
1425             continue;
1426         }
1427         if (clipsPaintInvalidations())
1428             updateRect.intersect(rectToScroll);
1429         hostWindow()->invalidateContentsAndRootView(updateRect);
1430     }
1431 
1432     return true;
1433 }
1434 
scrollContentsSlowPath(const IntRect & updateRect)1435 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1436 {
1437     if (contentsInCompositedLayer()) {
1438         IntRect updateRect = visibleContentRect();
1439         ASSERT(renderView());
1440         renderView()->layer()->repainter().setBackingNeedsRepaintInRect(updateRect);
1441     }
1442     if (RenderPart* frameRenderer = m_frame->ownerRenderer()) {
1443         if (isEnclosedInCompositingLayer()) {
1444             LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1445                             frameRenderer->borderTop() + frameRenderer->paddingTop(),
1446                             visibleWidth(), visibleHeight());
1447             frameRenderer->invalidatePaintRectangle(rect);
1448             return;
1449         }
1450     }
1451 
1452     ScrollView::scrollContentsSlowPath(updateRect);
1453 }
1454 
1455 // Note that this gets called at painting time.
setIsOverlapped(bool isOverlapped)1456 void FrameView::setIsOverlapped(bool isOverlapped)
1457 {
1458     m_isOverlapped = isOverlapped;
1459 }
1460 
setContentIsOpaque(bool contentIsOpaque)1461 void FrameView::setContentIsOpaque(bool contentIsOpaque)
1462 {
1463     m_contentIsOpaque = contentIsOpaque;
1464 }
1465 
restoreScrollbar()1466 void FrameView::restoreScrollbar()
1467 {
1468     setScrollbarsSuppressed(false);
1469 }
1470 
scrollToFragment(const KURL & url)1471 bool FrameView::scrollToFragment(const KURL& url)
1472 {
1473     // If our URL has no ref, then we have no place we need to jump to.
1474     // OTOH If CSS target was set previously, we want to set it to 0, recalc
1475     // and possibly paint invalidation because :target pseudo class may have been
1476     // set (see bug 11321).
1477     if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget())
1478         return false;
1479 
1480     String fragmentIdentifier = url.fragmentIdentifier();
1481     if (scrollToAnchor(fragmentIdentifier))
1482         return true;
1483 
1484     // Try again after decoding the ref, based on the document's encoding.
1485     if (m_frame->document()->encoding().isValid())
1486         return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding()));
1487 
1488     return false;
1489 }
1490 
scrollToAnchor(const String & name)1491 bool FrameView::scrollToAnchor(const String& name)
1492 {
1493     ASSERT(m_frame->document());
1494 
1495     if (!m_frame->document()->isRenderingReady()) {
1496         m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1497         return false;
1498     }
1499 
1500     m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1501 
1502     Element* anchorNode = m_frame->document()->findAnchor(name);
1503 
1504     // Setting to null will clear the current target.
1505     m_frame->document()->setCSSTarget(anchorNode);
1506 
1507     if (m_frame->document()->isSVGDocument()) {
1508         if (SVGSVGElement* svg = SVGDocumentExtensions::rootElement(*m_frame->document())) {
1509             svg->setupInitialView(name, anchorNode);
1510             if (!anchorNode)
1511                 return true;
1512         }
1513     }
1514 
1515     // Implement the rule that "" and "top" both mean top of page as in other browsers.
1516     if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1517         return false;
1518 
1519     maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
1520 
1521     // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1522     if (anchorNode && anchorNode->isFocusable())
1523         m_frame->document()->setFocusedElement(anchorNode);
1524 
1525     return true;
1526 }
1527 
maintainScrollPositionAtAnchor(Node * anchorNode)1528 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1529 {
1530     m_maintainScrollPositionAnchor = anchorNode;
1531     if (!m_maintainScrollPositionAnchor)
1532         return;
1533 
1534     // We need to update the layout before scrolling, otherwise we could
1535     // really mess things up if an anchor scroll comes at a bad moment.
1536     m_frame->document()->updateRenderTreeIfNeeded();
1537     // Only do a layout if changes have occurred that make it necessary.
1538     RenderView* renderView = this->renderView();
1539     if (renderView && renderView->needsLayout())
1540         layout();
1541     else
1542         scrollToAnchor();
1543 }
1544 
scrollElementToRect(Element * element,const IntRect & rect)1545 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1546 {
1547     // FIXME(http://crbug.com/371896) - This method shouldn't be manually doing
1548     // coordinate transformations to the PinchViewport.
1549     IntRect targetRect(rect);
1550 
1551     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1552 
1553     bool pinchVirtualViewportEnabled = m_frame->settings()->pinchVirtualViewportEnabled();
1554 
1555     if (pinchVirtualViewportEnabled) {
1556         PinchViewport& pinchViewport = m_frame->page()->frameHost().pinchViewport();
1557 
1558         IntSize pinchViewportSize = expandedIntSize(pinchViewport.visibleRect().size());
1559         targetRect.moveBy(ceiledIntPoint(pinchViewport.visibleRect().location()));
1560         targetRect.setSize(pinchViewportSize.shrunkTo(targetRect.size()));
1561     }
1562 
1563     LayoutRect bounds = element->boundingBox();
1564     int centeringOffsetX = (targetRect.width() - bounds.width()) / 2;
1565     int centeringOffsetY = (targetRect.height() - bounds.height()) / 2;
1566 
1567     IntPoint targetOffset(
1568         bounds.x() - centeringOffsetX - targetRect.x(),
1569         bounds.y() - centeringOffsetY - targetRect.y());
1570 
1571     setScrollPosition(targetOffset);
1572 
1573     if (pinchVirtualViewportEnabled) {
1574         IntPoint remainder = IntPoint(targetOffset - scrollPosition());
1575         m_frame->page()->frameHost().pinchViewport().move(remainder);
1576     }
1577 }
1578 
setScrollPosition(const IntPoint & scrollPoint)1579 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
1580 {
1581     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1582     m_maintainScrollPositionAnchor = nullptr;
1583 
1584     IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1585 
1586     if (newScrollPosition == scrollPosition())
1587         return;
1588 
1589     ScrollView::setScrollPosition(newScrollPosition);
1590 }
1591 
setScrollPositionNonProgrammatically(const IntPoint & scrollPoint)1592 void FrameView::setScrollPositionNonProgrammatically(const IntPoint& scrollPoint)
1593 {
1594     IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1595 
1596     if (newScrollPosition == scrollPosition())
1597         return;
1598 
1599     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, false);
1600     notifyScrollPositionChanged(newScrollPosition);
1601 }
1602 
layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const1603 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const
1604 {
1605     return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize;
1606 }
1607 
setLayoutSize(const IntSize & size)1608 void FrameView::setLayoutSize(const IntSize& size)
1609 {
1610     ASSERT(!layoutSizeFixedToFrameSize());
1611 
1612     setLayoutSizeInternal(size);
1613 }
1614 
scrollPositionChanged()1615 void FrameView::scrollPositionChanged()
1616 {
1617     setWasScrolledByUser(true);
1618 
1619     Document* document = m_frame->document();
1620     document->enqueueScrollEventForNode(document);
1621 
1622     m_frame->eventHandler().dispatchFakeMouseMoveEventSoon();
1623 
1624     if (RenderView* renderView = document->renderView()) {
1625         if (renderView->usesCompositing())
1626             renderView->compositor()->frameViewDidScroll();
1627     }
1628 
1629     if (m_didScrollTimer.isActive())
1630         m_didScrollTimer.stop();
1631     m_didScrollTimer.startOneShot(resourcePriorityUpdateDelayAfterScroll, FROM_HERE);
1632 
1633     if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1634         cache->handleScrollPositionChanged(this);
1635 
1636     frame().loader().saveScrollState();
1637 }
1638 
didScrollTimerFired(Timer<FrameView> *)1639 void FrameView::didScrollTimerFired(Timer<FrameView>*)
1640 {
1641     if (m_frame->document() && m_frame->document()->renderView()) {
1642         ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
1643     }
1644 }
1645 
updateLayersAndCompositingAfterScrollIfNeeded()1646 void FrameView::updateLayersAndCompositingAfterScrollIfNeeded()
1647 {
1648     // Nothing to do after scrolling if there are no fixed position elements.
1649     if (!hasViewportConstrainedObjects())
1650         return;
1651 
1652     RefPtr<FrameView> protect(this);
1653 
1654     // If there fixed position elements, scrolling may cause compositing layers to change.
1655     // Update widget and layer positions after scrolling, but only if we're not inside of
1656     // layout.
1657     if (!m_nestedLayoutCount) {
1658         updateWidgetPositions();
1659         if (RenderView* renderView = this->renderView()) {
1660             renderView->layer()->updateLayerPositionsAfterDocumentScroll();
1661             renderView->layer()->setNeedsCompositingInputsUpdate();
1662             renderView->compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
1663         }
1664     }
1665 }
1666 
updateFixedElementPaintInvalidationRectsAfterScroll()1667 void FrameView::updateFixedElementPaintInvalidationRectsAfterScroll()
1668 {
1669     if (!hasViewportConstrainedObjects())
1670         return;
1671 
1672     // Update the paint invalidation rects for fixed elements after scrolling and invalidation to reflect
1673     // the new scroll position.
1674     ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1675     for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1676         RenderObject* renderer = *it;
1677         // m_viewportConstrainedObjects should not contain non-viewport constrained objects.
1678         ASSERT(renderer->style()->hasViewportConstrainedPosition());
1679 
1680         // Fixed items should always have layers.
1681         ASSERT(renderer->hasLayer());
1682 
1683         RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1684 
1685         // Don't need to do this for composited fixed items.
1686         if (layer->compositingState() == PaintsIntoOwnBacking)
1687             continue;
1688 
1689         // Also don't need to do this for invisible items.
1690         if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1691             || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent)
1692             continue;
1693 
1694         layer->repainter().computeRepaintRectsIncludingNonCompositingDescendants();
1695     }
1696 }
1697 
isRubberBandInProgress() const1698 bool FrameView::isRubberBandInProgress() const
1699 {
1700     if (scrollbarsSuppressed())
1701         return false;
1702 
1703     // If the main thread updates the scroll position for this FrameView, we should return
1704     // ScrollAnimator::isRubberBandInProgress().
1705     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1706         return scrollAnimator->isRubberBandInProgress();
1707 
1708     return false;
1709 }
1710 
hostWindow() const1711 HostWindow* FrameView::hostWindow() const
1712 {
1713     Page* page = frame().page();
1714     if (!page)
1715         return 0;
1716     return &page->chrome();
1717 }
1718 
contentRectangleForPaintInvalidation(const IntRect & r)1719 void FrameView::contentRectangleForPaintInvalidation(const IntRect& r)
1720 {
1721     ASSERT(paintInvalidationIsAllowed());
1722     ASSERT(!m_frame->owner());
1723 
1724     if (m_isTrackingPaintInvalidations) {
1725         IntRect paintInvalidationRect = r;
1726         paintInvalidationRect.move(-scrollOffset());
1727         m_trackedPaintInvalidationRects.append(paintInvalidationRect);
1728         // FIXME: http://crbug.com/368518. Eventually, invalidateContentRectangleForPaint
1729         // is going away entirely once all layout tests are FCM. In the short
1730         // term, no code should be tracking non-composited FrameView paint invalidations.
1731         RELEASE_ASSERT_NOT_REACHED();
1732     }
1733 
1734     ScrollView::contentRectangleForPaintInvalidation(r);
1735 }
1736 
contentsResized()1737 void FrameView::contentsResized()
1738 {
1739     if (m_frame->isMainFrame() && m_frame->document()) {
1740         if (FastTextAutosizer* textAutosizer = m_frame->document()->fastTextAutosizer())
1741             textAutosizer->updatePageInfoInAllFrames();
1742     }
1743 
1744     ScrollView::contentsResized();
1745     setNeedsLayout();
1746 }
1747 
scrollbarExistenceDidChange()1748 void FrameView::scrollbarExistenceDidChange()
1749 {
1750     // We check to make sure the view is attached to a frame() as this method can
1751     // be triggered before the view is attached by LocalFrame::createView(...) setting
1752     // various values such as setScrollBarModes(...) for example.  An ASSERT is
1753     // triggered when a view is layout before being attached to a frame().
1754     if (!frame().view())
1755         return;
1756 
1757     // Note that simply having overlay scrollbars is not sufficient to be
1758     // certain that scrollbars' presence does not impact layout. This should
1759     // also check if custom scrollbars (as reported by shouldUseCustomScrollbars)
1760     // are in use as well.
1761     // http://crbug.com/269692
1762     bool useOverlayScrollbars = ScrollbarTheme::theme()->usesOverlayScrollbars();
1763 
1764     if (!useOverlayScrollbars && needsLayout())
1765         layout();
1766 
1767     if (renderView() && renderView()->usesCompositing()) {
1768         renderView()->compositor()->frameViewScrollbarsExistenceDidChange();
1769 
1770         if (!useOverlayScrollbars)
1771             renderView()->compositor()->frameViewDidChangeSize();
1772     }
1773 }
1774 
handleLoadCompleted()1775 void FrameView::handleLoadCompleted()
1776 {
1777     // Once loading has completed, allow autoSize one last opportunity to
1778     // reduce the size of the frame.
1779     autoSizeIfEnabled();
1780 }
1781 
scheduleRelayout()1782 void FrameView::scheduleRelayout()
1783 {
1784     ASSERT(m_frame->view() == this);
1785 
1786     if (isSubtreeLayout()) {
1787         m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1788         m_layoutSubtreeRoot = 0;
1789     }
1790     if (!m_layoutSchedulingEnabled)
1791         return;
1792     if (!needsLayout())
1793         return;
1794     if (!m_frame->document()->shouldScheduleLayout())
1795         return;
1796     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get());
1797     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
1798     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1799     InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1800 
1801     if (m_hasPendingLayout)
1802         return;
1803     m_hasPendingLayout = true;
1804 
1805     page()->animator().scheduleVisualUpdate();
1806     lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1807 }
1808 
isObjectAncestorContainerOf(RenderObject * ancestor,RenderObject * descendant)1809 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
1810 {
1811     for (RenderObject* r = descendant; r; r = r->container()) {
1812         if (r == ancestor)
1813             return true;
1814     }
1815     return false;
1816 }
1817 
scheduleRelayoutOfSubtree(RenderObject * relayoutRoot)1818 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
1819 {
1820     ASSERT(m_frame->view() == this);
1821 
1822     // FIXME: Should this call shouldScheduleLayout instead?
1823     if (!m_frame->document()->isActive())
1824         return;
1825 
1826     RenderView* renderView = this->renderView();
1827     if (renderView && renderView->needsLayout()) {
1828         if (relayoutRoot)
1829             relayoutRoot->markContainingBlocksForLayout(false);
1830         return;
1831     }
1832 
1833     if (layoutPending() || !m_layoutSchedulingEnabled) {
1834         if (m_layoutSubtreeRoot != relayoutRoot) {
1835             if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) {
1836                 // Keep the current root
1837                 relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot);
1838                 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1839             } else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) {
1840                 // Re-root at relayoutRoot
1841                 m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot);
1842                 m_layoutSubtreeRoot = relayoutRoot;
1843                 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1844             } else {
1845                 // Just do a full relayout
1846                 if (isSubtreeLayout())
1847                     m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1848                 m_layoutSubtreeRoot = 0;
1849                 relayoutRoot->markContainingBlocksForLayout(false);
1850             }
1851         }
1852     } else if (m_layoutSchedulingEnabled) {
1853         m_layoutSubtreeRoot = relayoutRoot;
1854         ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1855         m_hasPendingLayout = true;
1856 
1857         page()->animator().scheduleVisualUpdate();
1858         lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1859     }
1860     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get());
1861     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
1862     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1863     InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1864 }
1865 
layoutPending() const1866 bool FrameView::layoutPending() const
1867 {
1868     // FIXME: This should check Document::lifecycle instead.
1869     return m_hasPendingLayout;
1870 }
1871 
isInPerformLayout() const1872 bool FrameView::isInPerformLayout() const
1873 {
1874     ASSERT(m_inPerformLayout == (lifecycle().state() == DocumentLifecycle::InPerformLayout));
1875     return m_inPerformLayout;
1876 }
1877 
needsLayout() const1878 bool FrameView::needsLayout() const
1879 {
1880     // This can return true in cases where the document does not have a body yet.
1881     // Document::shouldScheduleLayout takes care of preventing us from scheduling
1882     // layout in that case.
1883 
1884     RenderView* renderView = this->renderView();
1885     return layoutPending()
1886         || (renderView && renderView->needsLayout())
1887         || isSubtreeLayout();
1888 }
1889 
setNeedsLayout()1890 void FrameView::setNeedsLayout()
1891 {
1892     if (RenderView* renderView = this->renderView())
1893         renderView->setNeedsLayout();
1894 }
1895 
isTransparent() const1896 bool FrameView::isTransparent() const
1897 {
1898     return m_isTransparent;
1899 }
1900 
setTransparent(bool isTransparent)1901 void FrameView::setTransparent(bool isTransparent)
1902 {
1903     m_isTransparent = isTransparent;
1904     DisableCompositingQueryAsserts disabler;
1905     if (renderView() && renderView()->layer()->hasCompositedLayerMapping())
1906         renderView()->layer()->compositedLayerMapping()->updateContentsOpaque();
1907 }
1908 
hasOpaqueBackground() const1909 bool FrameView::hasOpaqueBackground() const
1910 {
1911     return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
1912 }
1913 
baseBackgroundColor() const1914 Color FrameView::baseBackgroundColor() const
1915 {
1916     return m_baseBackgroundColor;
1917 }
1918 
setBaseBackgroundColor(const Color & backgroundColor)1919 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
1920 {
1921     m_baseBackgroundColor = backgroundColor;
1922 
1923     if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) {
1924         CompositedLayerMappingPtr compositedLayerMapping = renderView()->layer()->compositedLayerMapping();
1925         compositedLayerMapping->updateContentsOpaque();
1926         if (compositedLayerMapping->mainGraphicsLayer())
1927             compositedLayerMapping->mainGraphicsLayer()->setNeedsDisplay();
1928     }
1929     recalculateScrollbarOverlayStyle();
1930 }
1931 
updateBackgroundRecursively(const Color & backgroundColor,bool transparent)1932 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
1933 {
1934     for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1935         if (!frame->isLocalFrame())
1936             continue;
1937         if (FrameView* view = toLocalFrame(frame)->view()) {
1938             view->setTransparent(transparent);
1939             view->setBaseBackgroundColor(backgroundColor);
1940         }
1941     }
1942 }
1943 
scrollToAnchor()1944 void FrameView::scrollToAnchor()
1945 {
1946     RefPtrWillBeRawPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
1947     if (!anchorNode)
1948         return;
1949 
1950     if (!anchorNode->renderer())
1951         return;
1952 
1953     LayoutRect rect;
1954     if (anchorNode != m_frame->document())
1955         rect = anchorNode->boundingBox();
1956 
1957     // Scroll nested layers and frames to reveal the anchor.
1958     // Align to the top and to the closest side (this matches other browsers).
1959     anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1960 
1961     if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1962         cache->handleScrolledToAnchor(anchorNode.get());
1963 
1964     // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
1965     m_maintainScrollPositionAnchor = anchorNode;
1966 }
1967 
updateWidgets()1968 bool FrameView::updateWidgets()
1969 {
1970     // This is always called from updateWidgetsTimerFired.
1971     // m_updateWidgetsTimer should only be scheduled if we have widgets to update.
1972     // Thus I believe we can stop checking isEmpty here, and just ASSERT isEmpty:
1973     ASSERT(!m_widgetUpdateSet.isEmpty());
1974     if (m_nestedLayoutCount > 1 || m_widgetUpdateSet.isEmpty())
1975         return true;
1976 
1977     // Need to swap because script will run inside the below loop and invalidate the iterator.
1978     EmbeddedObjectSet objects;
1979     objects.swap(m_widgetUpdateSet);
1980 
1981     for (EmbeddedObjectSet::iterator it = objects.begin(); it != objects.end(); ++it) {
1982         RenderEmbeddedObject& object = **it;
1983         HTMLPlugInElement* element = toHTMLPlugInElement(object.node());
1984 
1985         // The object may have already been destroyed (thus node cleared),
1986         // but FrameView holds a manual ref, so it won't have been deleted.
1987         if (!element)
1988             continue;
1989 
1990         // No need to update if it's already crashed or known to be missing.
1991         if (object.showsUnavailablePluginIndicator())
1992             continue;
1993 
1994         if (element->needsWidgetUpdate())
1995             element->updateWidget();
1996         object.updateWidgetPosition();
1997 
1998         // Prevent plugins from causing infinite updates of themselves.
1999         // FIXME: Do we really need to prevent this?
2000         m_widgetUpdateSet.remove(&object);
2001     }
2002 
2003     return m_widgetUpdateSet.isEmpty();
2004 }
2005 
updateWidgetsTimerFired(Timer<FrameView> *)2006 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*)
2007 {
2008     ASSERT(!isInPerformLayout());
2009     RefPtr<FrameView> protect(this);
2010     m_updateWidgetsTimer.stop();
2011     for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) {
2012         if (updateWidgets())
2013             return;
2014     }
2015 }
2016 
flushAnyPendingPostLayoutTasks()2017 void FrameView::flushAnyPendingPostLayoutTasks()
2018 {
2019     ASSERT(!isInPerformLayout());
2020     if (m_postLayoutTasksTimer.isActive())
2021         performPostLayoutTasks();
2022     if (m_updateWidgetsTimer.isActive())
2023         updateWidgetsTimerFired(0);
2024 }
2025 
scheduleUpdateWidgetsIfNecessary()2026 void FrameView::scheduleUpdateWidgetsIfNecessary()
2027 {
2028     ASSERT(!isInPerformLayout());
2029     if (m_updateWidgetsTimer.isActive() || m_widgetUpdateSet.isEmpty())
2030         return;
2031     m_updateWidgetsTimer.startOneShot(0, FROM_HERE);
2032 }
2033 
performPostLayoutTasks()2034 void FrameView::performPostLayoutTasks()
2035 {
2036     // FIXME: We can reach here, even when the page is not active!
2037     // http/tests/inspector/elements/html-link-import.html and many other
2038     // tests hit that case.
2039     // We should ASSERT(isActive()); or at least return early if we can!
2040     ASSERT(!isInPerformLayout()); // Always before or after performLayout(), part of the highest-level layout() call.
2041     TRACE_EVENT0("webkit", "FrameView::performPostLayoutTasks");
2042     RefPtr<FrameView> protect(this);
2043 
2044     m_postLayoutTasksTimer.stop();
2045 
2046     m_frame->selection().setCaretRectNeedsUpdate();
2047 
2048     {
2049         // Hits in compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html
2050         DisableCompositingQueryAsserts disabler;
2051         m_frame->selection().updateAppearance();
2052     }
2053 
2054     ASSERT(m_frame->document());
2055     if (m_nestedLayoutCount <= 1) {
2056         if (m_firstLayoutCallbackPending)
2057             m_firstLayoutCallbackPending = false;
2058 
2059         // Ensure that we always send this eventually.
2060         if (!m_frame->document()->parsing() && m_frame->loader().stateMachine()->committedFirstRealDocumentLoad())
2061             m_isVisuallyNonEmpty = true;
2062 
2063         // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
2064         if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
2065             m_firstVisuallyNonEmptyLayoutCallbackPending = false;
2066             // FIXME: This callback is probably not needed, but is currently used
2067             // by android for setting the background color.
2068             m_frame->loader().client()->dispatchDidFirstVisuallyNonEmptyLayout();
2069         }
2070     }
2071 
2072     FontFaceSet::didLayout(*m_frame->document());
2073 
2074     updateWidgetPositions();
2075 
2076     // Plugins could have torn down the page inside updateWidgetPositions().
2077     if (!renderView())
2078         return;
2079 
2080     scheduleUpdateWidgetsIfNecessary();
2081 
2082     if (Page* page = m_frame->page()) {
2083         if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2084             scrollingCoordinator->notifyLayoutUpdated();
2085     }
2086 
2087     scrollToAnchor();
2088 
2089     sendResizeEventIfNeeded();
2090 }
2091 
sendResizeEventIfNeeded()2092 void FrameView::sendResizeEventIfNeeded()
2093 {
2094     ASSERT(m_frame);
2095 
2096     RenderView* renderView = this->renderView();
2097     if (!renderView || renderView->document().printing())
2098         return;
2099 
2100     IntSize currentSize = layoutSize(IncludeScrollbars);
2101     float currentZoomFactor = renderView->style()->zoom();
2102 
2103     bool shouldSendResizeEvent = currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor;
2104 
2105     m_lastViewportSize = currentSize;
2106     m_lastZoomFactor = currentZoomFactor;
2107 
2108     if (!shouldSendResizeEvent)
2109         return;
2110 
2111     m_frame->document()->enqueueResizeEvent();
2112 
2113     if (m_frame->isMainFrame())
2114         InspectorInstrumentation::didResizeMainFrame(m_frame->page());
2115 }
2116 
postLayoutTimerFired(Timer<FrameView> *)2117 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
2118 {
2119     performPostLayoutTasks();
2120 }
2121 
updateCounters()2122 void FrameView::updateCounters()
2123 {
2124     RenderView* view = renderView();
2125     if (!view->hasRenderCounters())
2126         return;
2127 
2128     for (RenderObject* renderer = view; renderer; renderer = renderer->nextInPreOrder()) {
2129         if (!renderer->isCounter())
2130             continue;
2131 
2132         toRenderCounter(renderer)->updateCounter();
2133     }
2134 }
2135 
autoSizeIfEnabled()2136 void FrameView::autoSizeIfEnabled()
2137 {
2138     if (!m_shouldAutoSize)
2139         return;
2140 
2141     if (m_inAutoSize)
2142         return;
2143 
2144     TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
2145 
2146     Document* document = frame().document();
2147     if (!document || !document->isActive())
2148         return;
2149 
2150     Element* documentElement = document->documentElement();
2151     if (!documentElement)
2152         return;
2153 
2154     // If this is the first time we run autosize, start from small height and
2155     // allow it to grow.
2156     if (!m_didRunAutosize)
2157         resize(frameRect().width(), m_minAutoSize.height());
2158 
2159     IntSize size = frameRect().size();
2160 
2161     // Do the resizing twice. The first time is basically a rough calculation using the preferred width
2162     // which may result in a height change during the second iteration.
2163     for (int i = 0; i < 2; i++) {
2164         // Update various sizes including contentsSize, scrollHeight, etc.
2165         document->updateLayoutIgnorePendingStylesheets();
2166 
2167         RenderView* renderView = document->renderView();
2168         if (!renderView)
2169             return;
2170 
2171         int width = renderView->minPreferredLogicalWidth();
2172 
2173         RenderBox* documentRenderBox = documentElement->renderBox();
2174         if (!documentRenderBox)
2175             return;
2176 
2177         int height = documentRenderBox->scrollHeight();
2178         IntSize newSize(width, height);
2179 
2180         // Check to see if a scrollbar is needed for a given dimension and
2181         // if so, increase the other dimension to account for the scrollbar.
2182         // Since the dimensions are only for the view rectangle, once a
2183         // dimension exceeds the maximum, there is no need to increase it further.
2184         if (newSize.width() > m_maxAutoSize.width()) {
2185             RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
2186             if (!localHorizontalScrollbar)
2187                 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
2188             if (!localHorizontalScrollbar->isOverlayScrollbar())
2189                 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
2190 
2191             // Don't bother checking for a vertical scrollbar because the width is at
2192             // already greater the maximum.
2193         } else if (newSize.height() > m_maxAutoSize.height()) {
2194             RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
2195             if (!localVerticalScrollbar)
2196                 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
2197             if (!localVerticalScrollbar->isOverlayScrollbar())
2198                 newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
2199 
2200             // Don't bother checking for a horizontal scrollbar because the height is
2201             // already greater the maximum.
2202         }
2203 
2204         // Ensure the size is at least the min bounds.
2205         newSize = newSize.expandedTo(m_minAutoSize);
2206 
2207         // Bound the dimensions by the max bounds and determine what scrollbars to show.
2208         ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
2209         if (newSize.width() > m_maxAutoSize.width()) {
2210             newSize.setWidth(m_maxAutoSize.width());
2211             horizonalScrollbarMode = ScrollbarAlwaysOn;
2212         }
2213         ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
2214         if (newSize.height() > m_maxAutoSize.height()) {
2215             newSize.setHeight(m_maxAutoSize.height());
2216             verticalScrollbarMode = ScrollbarAlwaysOn;
2217         }
2218 
2219         if (newSize == size)
2220             continue;
2221 
2222         // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
2223         // unless autoresize has just been turned on or the maximum size is smaller than the current size.
2224         if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
2225             && !m_frame->document()->loadEventFinished() && (newSize.height() < size.height() || newSize.width() < size.width()))
2226             break;
2227 
2228         resize(newSize.width(), newSize.height());
2229         // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
2230         // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
2231         setVerticalScrollbarLock(false);
2232         setHorizontalScrollbarLock(false);
2233         setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
2234     }
2235     m_didRunAutosize = true;
2236 }
2237 
updateOverflowStatus(bool horizontalOverflow,bool verticalOverflow)2238 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2239 {
2240     if (!m_viewportRenderer)
2241         return;
2242 
2243     if (m_overflowStatusDirty) {
2244         m_horizontalOverflow = horizontalOverflow;
2245         m_verticalOverflow = verticalOverflow;
2246         m_overflowStatusDirty = false;
2247         return;
2248     }
2249 
2250     bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2251     bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2252 
2253     if (horizontalOverflowChanged || verticalOverflowChanged) {
2254         m_horizontalOverflow = horizontalOverflow;
2255         m_verticalOverflow = verticalOverflow;
2256 
2257         RefPtrWillBeRawPtr<OverflowEvent> event = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow);
2258         event->setTarget(m_viewportRenderer->node());
2259         m_frame->document()->enqueueAnimationFrameEvent(event.release());
2260     }
2261 
2262 }
2263 
windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const2264 IntRect FrameView::windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const
2265 {
2266     ASSERT(m_frame->view() == this);
2267 
2268     if (paintsEntireContents())
2269         return IntRect(IntPoint(), contentsSize());
2270 
2271     // Set our clip rect to be our contents.
2272     IntRect clipRect = contentsToWindow(visibleContentRect(scrollbarInclusion));
2273     if (!m_frame->deprecatedLocalOwner())
2274         return clipRect;
2275 
2276     // Take our owner element and get its clip rect.
2277     // FIXME: Do we need to do this for remote frames?
2278     HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
2279     FrameView* parentView = ownerElement->document().view();
2280     if (parentView)
2281         clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement));
2282     return clipRect;
2283 }
2284 
windowClipRectForFrameOwner(const HTMLFrameOwnerElement * ownerElement) const2285 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement) const
2286 {
2287     // The renderer can sometimes be null when style="display:none" interacts
2288     // with external content and plugins.
2289     if (!ownerElement->renderer())
2290         return windowClipRect();
2291 
2292     // If we have no layer, just return our window clip rect.
2293     const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
2294     if (!enclosingLayer)
2295         return windowClipRect();
2296 
2297     // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date.
2298     // https://code.google.com/p/chromium/issues/detail?id=343769
2299     DisableCompositingQueryAsserts disabler;
2300 
2301     // Apply the clip from the layer.
2302     IntRect clipRect = contentsToWindow(pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect()));
2303     return intersection(clipRect, windowClipRect());
2304 }
2305 
isActive() const2306 bool FrameView::isActive() const
2307 {
2308     Page* page = frame().page();
2309     return page && page->focusController().isActive();
2310 }
2311 
scrollTo(const IntSize & newOffset)2312 void FrameView::scrollTo(const IntSize& newOffset)
2313 {
2314     LayoutSize offset = scrollOffset();
2315     ScrollView::scrollTo(newOffset);
2316     if (offset != scrollOffset()) {
2317         updateLayersAndCompositingAfterScrollIfNeeded();
2318         scrollPositionChanged();
2319     }
2320     frame().loader().client()->didChangeScrollOffset();
2321 }
2322 
invalidateScrollbarRect(Scrollbar * scrollbar,const IntRect & rect)2323 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2324 {
2325     // Add in our offset within the FrameView.
2326     IntRect dirtyRect = rect;
2327     dirtyRect.moveBy(scrollbar->location());
2328 
2329     if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && isInPerformLayout()) {
2330         if (scrollbar == verticalScrollbar()) {
2331             m_verticalBarDamage = dirtyRect;
2332             m_hasVerticalBarDamage = true;
2333         } else {
2334             m_horizontalBarDamage = dirtyRect;
2335             m_hasHorizontalBarDamage = true;
2336         }
2337     } else {
2338         invalidateRect(dirtyRect);
2339     }
2340 }
2341 
getTickmarks(Vector<IntRect> & tickmarks) const2342 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
2343 {
2344     if (!m_tickmarks.isEmpty())
2345         tickmarks = m_tickmarks;
2346     else
2347         tickmarks = frame().document()->markers().renderedRectsForMarkers(DocumentMarker::TextMatch);
2348 }
2349 
windowResizerRect() const2350 IntRect FrameView::windowResizerRect() const
2351 {
2352     Page* page = frame().page();
2353     if (!page)
2354         return IntRect();
2355     return page->chrome().windowResizerRect();
2356 }
2357 
setVisibleContentScaleFactor(float visibleContentScaleFactor)2358 void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor)
2359 {
2360     if (m_visibleContentScaleFactor == visibleContentScaleFactor)
2361         return;
2362 
2363     m_visibleContentScaleFactor = visibleContentScaleFactor;
2364     updateScrollbars(scrollOffset());
2365 }
2366 
setInputEventsTransformForEmulation(const IntSize & offset,float contentScaleFactor)2367 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor)
2368 {
2369     m_inputEventsOffsetForEmulation = offset;
2370     m_inputEventsScaleFactorForEmulation = contentScaleFactor;
2371 }
2372 
inputEventsOffsetForEmulation() const2373 IntSize FrameView::inputEventsOffsetForEmulation() const
2374 {
2375     return m_inputEventsOffsetForEmulation;
2376 }
2377 
inputEventsScaleFactor() const2378 float FrameView::inputEventsScaleFactor() const
2379 {
2380     float pageScale = m_frame->settings()->pinchVirtualViewportEnabled()
2381         ? m_frame->page()->frameHost().pinchViewport().scale()
2382         : visibleContentScaleFactor();
2383     return pageScale * m_inputEventsScaleFactorForEmulation;
2384 }
2385 
scrollbarsCanBeActive() const2386 bool FrameView::scrollbarsCanBeActive() const
2387 {
2388     if (m_frame->view() != this)
2389         return false;
2390 
2391     return !!m_frame->document();
2392 }
2393 
scrollableAreaBoundingBox() const2394 IntRect FrameView::scrollableAreaBoundingBox() const
2395 {
2396     RenderPart* ownerRenderer = frame().ownerRenderer();
2397     if (!ownerRenderer)
2398         return frameRect();
2399 
2400     return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
2401 }
2402 
isScrollable()2403 bool FrameView::isScrollable()
2404 {
2405     // Check for:
2406     // 1) If there an actual overflow.
2407     // 2) display:none or visibility:hidden set to self or inherited.
2408     // 3) overflow{-x,-y}: hidden;
2409     // 4) scrolling: no;
2410 
2411     // Covers #1
2412     IntSize contentsSize = this->contentsSize();
2413     IntSize visibleContentSize = visibleContentRect().size();
2414     if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width()))
2415         return false;
2416 
2417     // Covers #2.
2418     // FIXME: Do we need to fix this for OOPI?
2419     HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
2420     if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
2421         return false;
2422 
2423     // Cover #3 and #4.
2424     ScrollbarMode horizontalMode;
2425     ScrollbarMode verticalMode;
2426     calculateScrollbarModesForLayoutAndSetViewportRenderer(horizontalMode, verticalMode, RulesFromWebContentOnly);
2427     if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
2428         return false;
2429 
2430     return true;
2431 }
2432 
updateScrollableAreaSet()2433 void FrameView::updateScrollableAreaSet()
2434 {
2435     // That ensures that only inner frames are cached.
2436     FrameView* parentFrameView = this->parentFrameView();
2437     if (!parentFrameView)
2438         return;
2439 
2440     if (!isScrollable()) {
2441         parentFrameView->removeScrollableArea(this);
2442         return;
2443     }
2444 
2445     parentFrameView->addScrollableArea(this);
2446 }
2447 
shouldSuspendScrollAnimations() const2448 bool FrameView::shouldSuspendScrollAnimations() const
2449 {
2450     return m_frame->loader().state() != FrameStateComplete;
2451 }
2452 
scrollbarStyleChanged()2453 void FrameView::scrollbarStyleChanged()
2454 {
2455     // FIXME: Why does this only apply to the main frame?
2456     if (!m_frame->isMainFrame())
2457         return;
2458     ScrollView::scrollbarStyleChanged();
2459 }
2460 
notifyPageThatContentAreaWillPaint() const2461 void FrameView::notifyPageThatContentAreaWillPaint() const
2462 {
2463     Page* page = m_frame->page();
2464     if (!page)
2465         return;
2466 
2467     contentAreaWillPaint();
2468 
2469     if (!m_scrollableAreas)
2470         return;
2471 
2472     for (HashSet<ScrollableArea*>::const_iterator it = m_scrollableAreas->begin(), end = m_scrollableAreas->end(); it != end; ++it) {
2473         ScrollableArea* scrollableArea = *it;
2474 
2475         if (!scrollableArea->scrollbarsCanBeActive())
2476             continue;
2477 
2478         scrollableArea->contentAreaWillPaint();
2479     }
2480 }
2481 
scrollAnimatorEnabled() const2482 bool FrameView::scrollAnimatorEnabled() const
2483 {
2484     return m_frame->settings() && m_frame->settings()->scrollAnimatorEnabled();
2485 }
2486 
updateAnnotatedRegions()2487 void FrameView::updateAnnotatedRegions()
2488 {
2489     Document* document = m_frame->document();
2490     if (!document->hasAnnotatedRegions())
2491         return;
2492     Vector<AnnotatedRegionValue> newRegions;
2493     document->renderBox()->collectAnnotatedRegions(newRegions);
2494     if (newRegions == document->annotatedRegions())
2495         return;
2496     document->setAnnotatedRegions(newRegions);
2497     if (Page* page = m_frame->page())
2498         page->chrome().client().annotatedRegionsChanged();
2499 }
2500 
updateScrollCorner()2501 void FrameView::updateScrollCorner()
2502 {
2503     RefPtr<RenderStyle> cornerStyle;
2504     IntRect cornerRect = scrollCornerRect();
2505     Document* doc = m_frame->document();
2506 
2507     if (doc && !cornerRect.isEmpty()) {
2508         // Try the <body> element first as a scroll corner source.
2509         if (Element* body = doc->body()) {
2510             if (RenderObject* renderer = body->renderer())
2511                 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2512         }
2513 
2514         if (!cornerStyle) {
2515             // If the <body> didn't have a custom style, then the root element might.
2516             if (Element* docElement = doc->documentElement()) {
2517                 if (RenderObject* renderer = docElement->renderer())
2518                     cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2519             }
2520         }
2521 
2522         if (!cornerStyle) {
2523             // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
2524             if (RenderPart* renderer = m_frame->ownerRenderer())
2525                 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2526         }
2527     }
2528 
2529     if (cornerStyle) {
2530         if (!m_scrollCorner)
2531             m_scrollCorner = RenderScrollbarPart::createAnonymous(doc);
2532         m_scrollCorner->setStyle(cornerStyle.release());
2533         invalidateScrollCorner(cornerRect);
2534     } else if (m_scrollCorner) {
2535         m_scrollCorner->destroy();
2536         m_scrollCorner = 0;
2537     }
2538 
2539     ScrollView::updateScrollCorner();
2540 }
2541 
paintScrollCorner(GraphicsContext * context,const IntRect & cornerRect)2542 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
2543 {
2544     if (context->updatingControlTints()) {
2545         updateScrollCorner();
2546         return;
2547     }
2548 
2549     if (m_scrollCorner) {
2550         bool needsBackgorund = m_frame->isMainFrame();
2551         if (needsBackgorund)
2552             context->fillRect(cornerRect, baseBackgroundColor());
2553         m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
2554         return;
2555     }
2556 
2557     ScrollView::paintScrollCorner(context, cornerRect);
2558 }
2559 
paintScrollbar(GraphicsContext * context,Scrollbar * bar,const IntRect & rect)2560 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
2561 {
2562     bool needsBackgorund = bar->isCustomScrollbar() && m_frame->isMainFrame();
2563     if (needsBackgorund) {
2564         IntRect toFill = bar->frameRect();
2565         toFill.intersect(rect);
2566         context->fillRect(toFill, baseBackgroundColor());
2567     }
2568 
2569     ScrollView::paintScrollbar(context, bar, rect);
2570 }
2571 
documentBackgroundColor() const2572 Color FrameView::documentBackgroundColor() const
2573 {
2574     // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
2575     // the document and the body against the base background color of the frame view.
2576     // Background images are unfortunately impractical to include.
2577 
2578     Color result = baseBackgroundColor();
2579     if (!frame().document())
2580         return result;
2581 
2582     Element* htmlElement = frame().document()->documentElement();
2583     Element* bodyElement = frame().document()->body();
2584 
2585     // We take the aggregate of the base background color
2586     // the <html> background color, and the <body>
2587     // background color to find the document color. The
2588     // addition of the base background color is not
2589     // technically part of the document background, but it
2590     // otherwise poses problems when the aggregate is not
2591     // fully opaque.
2592     if (htmlElement && htmlElement->renderer())
2593         result = result.blend(htmlElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2594     if (bodyElement && bodyElement->renderer())
2595         result = result.blend(bodyElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2596 
2597     return result;
2598 }
2599 
hasCustomScrollbars() const2600 bool FrameView::hasCustomScrollbars() const
2601 {
2602     const HashSet<RefPtr<Widget> >* viewChildren = children();
2603     HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
2604     for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
2605         Widget* widget = current->get();
2606         if (widget->isFrameView()) {
2607             if (toFrameView(widget)->hasCustomScrollbars())
2608                 return true;
2609         } else if (widget->isScrollbar()) {
2610             Scrollbar* scrollbar = static_cast<Scrollbar*>(widget);
2611             if (scrollbar->isCustomScrollbar())
2612                 return true;
2613         }
2614     }
2615 
2616     return false;
2617 }
2618 
parentFrameView() const2619 FrameView* FrameView::parentFrameView() const
2620 {
2621     if (!parent())
2622         return 0;
2623 
2624     Frame* parentFrame = m_frame->tree().parent();
2625     if (parentFrame && parentFrame->isLocalFrame())
2626         return toLocalFrame(parentFrame)->view();
2627 
2628     return 0;
2629 }
2630 
updateControlTints()2631 void FrameView::updateControlTints()
2632 {
2633     // This is called when control tints are changed from aqua/graphite to clear and vice versa.
2634     // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
2635     // This is only done if the theme supports control tinting. It's up to the theme and platform
2636     // to define when controls get the tint and to call this function when that changes.
2637 
2638     // Optimize the common case where we bring a window to the front while it's still empty.
2639     if (m_frame->document()->url().isEmpty())
2640         return;
2641 
2642     // FIXME: We shouldn't rely on the paint code to implement :window-inactive on custom scrollbars.
2643     if (!RenderTheme::theme().supportsControlTints() && !hasCustomScrollbars())
2644         return;
2645 
2646     // Updating layout can run script, which can tear down the FrameView.
2647     RefPtr<FrameView> protector(this);
2648     updateLayoutAndStyleForPainting();
2649 
2650     // FIXME: The use of paint seems like overkill: crbug.com/236892
2651     GraphicsContext context(0); // NULL canvas to get a non-painting context.
2652     context.setUpdatingControlTints(true);
2653     paint(&context, frameRect());
2654 }
2655 
wasScrolledByUser() const2656 bool FrameView::wasScrolledByUser() const
2657 {
2658     return m_wasScrolledByUser;
2659 }
2660 
setWasScrolledByUser(bool wasScrolledByUser)2661 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
2662 {
2663     if (m_inProgrammaticScroll)
2664         return;
2665     m_maintainScrollPositionAnchor = nullptr;
2666     m_wasScrolledByUser = wasScrolledByUser;
2667 }
2668 
paintContents(GraphicsContext * p,const IntRect & rect)2669 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
2670 {
2671     Document* document = m_frame->document();
2672 
2673 #ifndef NDEBUG
2674     bool fillWithRed;
2675     if (document->printing())
2676         fillWithRed = false; // Printing, don't fill with red (can't remember why).
2677     else if (m_frame->owner())
2678         fillWithRed = false; // Subframe, don't fill with red.
2679     else if (isTransparent())
2680         fillWithRed = false; // Transparent, don't fill with red.
2681     else if (m_paintBehavior & PaintBehaviorSelectionOnly)
2682         fillWithRed = false; // Selections are transparent, don't fill with red.
2683     else if (m_nodeToDraw)
2684         fillWithRed = false; // Element images are transparent, don't fill with red.
2685     else
2686         fillWithRed = true;
2687 
2688     if (fillWithRed)
2689         p->fillRect(rect, Color(0xFF, 0, 0));
2690 #endif
2691 
2692     RenderView* renderView = this->renderView();
2693     if (!renderView) {
2694         WTF_LOG_ERROR("called FrameView::paint with nil renderer");
2695         return;
2696     }
2697 
2698     ASSERT(!needsLayout());
2699     if (needsLayout())
2700         return;
2701 
2702     TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Paint", "data", InspectorPaintEvent::data(renderView, rect, 0));
2703     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
2704     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
2705     InspectorInstrumentation::willPaint(renderView, 0);
2706 
2707     bool isTopLevelPainter = !s_inPaintContents;
2708     s_inPaintContents = true;
2709 
2710     FontCachePurgePreventer fontCachePurgePreventer;
2711 
2712     PaintBehavior oldPaintBehavior = m_paintBehavior;
2713 
2714     if (FrameView* parentView = parentFrameView()) {
2715         if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
2716             m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
2717     }
2718 
2719     if (m_paintBehavior == PaintBehaviorNormal)
2720         document->markers().invalidateRenderedRectsForMarkersInRect(rect);
2721 
2722     if (document->printing())
2723         m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
2724 
2725     ASSERT(!m_isPainting);
2726     m_isPainting = true;
2727 
2728     // m_nodeToDraw is used to draw only one element (and its descendants)
2729     RenderObject* renderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
2730     RenderLayer* rootLayer = renderView->layer();
2731 
2732 #ifndef NDEBUG
2733     renderView->assertSubtreeIsLaidOut();
2734     RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*rootLayer->renderer());
2735 #endif
2736 
2737     rootLayer->paint(p, rect, m_paintBehavior, renderer);
2738 
2739     if (rootLayer->containsDirtyOverlayScrollbars())
2740         rootLayer->paintOverlayScrollbars(p, rect, m_paintBehavior, renderer);
2741 
2742     m_isPainting = false;
2743 
2744     m_paintBehavior = oldPaintBehavior;
2745     m_lastPaintTime = currentTime();
2746 
2747     // Regions may have changed as a result of the visibility/z-index of element changing.
2748     if (document->annotatedRegionsDirty())
2749         updateAnnotatedRegions();
2750 
2751     if (isTopLevelPainter) {
2752         // Everythin that happens after paintContents completions is considered
2753         // to be part of the next frame.
2754         s_currentFrameTimeStamp = currentTime();
2755         s_inPaintContents = false;
2756     }
2757 
2758     InspectorInstrumentation::didPaint(renderView, 0, p, rect);
2759 }
2760 
setPaintBehavior(PaintBehavior behavior)2761 void FrameView::setPaintBehavior(PaintBehavior behavior)
2762 {
2763     m_paintBehavior = behavior;
2764 }
2765 
paintBehavior() const2766 PaintBehavior FrameView::paintBehavior() const
2767 {
2768     return m_paintBehavior;
2769 }
2770 
isPainting() const2771 bool FrameView::isPainting() const
2772 {
2773     return m_isPainting;
2774 }
2775 
setNodeToDraw(Node * node)2776 void FrameView::setNodeToDraw(Node* node)
2777 {
2778     m_nodeToDraw = node;
2779 }
2780 
paintOverhangAreas(GraphicsContext * context,const IntRect & horizontalOverhangArea,const IntRect & verticalOverhangArea,const IntRect & dirtyRect)2781 void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
2782 {
2783     if (context->paintingDisabled())
2784         return;
2785 
2786     if (m_frame->document()->printing())
2787         return;
2788 
2789     if (m_frame->isMainFrame()) {
2790         if (m_frame->page()->chrome().client().paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect))
2791             return;
2792     }
2793 
2794     ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
2795 }
2796 
updateLayoutAndStyleForPainting()2797 void FrameView::updateLayoutAndStyleForPainting()
2798 {
2799     // Updating layout can run script, which can tear down the FrameView.
2800     RefPtr<FrameView> protector(this);
2801 
2802     updateLayoutAndStyleIfNeededRecursive();
2803 
2804     if (RenderView* view = renderView()) {
2805         InspectorInstrumentation::willUpdateLayerTree(view->frame());
2806 
2807         view->compositor()->updateIfNeededRecursive();
2808 
2809         if (view->compositor()->inCompositingMode() && m_frame->isMainFrame())
2810             m_frame->page()->scrollingCoordinator()->updateAfterCompositingChangeIfNeeded();
2811 
2812         InspectorInstrumentation::didUpdateLayerTree(view->frame());
2813     }
2814 
2815     scrollContentsIfNeededRecursive();
2816 }
2817 
updateLayoutAndStyleIfNeededRecursive()2818 void FrameView::updateLayoutAndStyleIfNeededRecursive()
2819 {
2820     // We have to crawl our entire tree looking for any FrameViews that need
2821     // layout and make sure they are up to date.
2822     // Mac actually tests for intersection with the dirty region and tries not to
2823     // update layout for frames that are outside the dirty region.  Not only does this seem
2824     // pointless (since those frames will have set a zero timer to layout anyway), but
2825     // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
2826     // region but then become included later by the second frame adding rects to the dirty region
2827     // when it lays out.
2828 
2829     m_frame->document()->updateRenderTreeIfNeeded();
2830 
2831     if (needsLayout())
2832         layout();
2833 
2834     // FIXME: Calling layout() shouldn't trigger scripe execution or have any
2835     // observable effects on the frame tree but we're not quite there yet.
2836     Vector<RefPtr<FrameView> > frameViews;
2837     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2838         if (!child->isLocalFrame())
2839             continue;
2840         if (FrameView* view = toLocalFrame(child)->view())
2841             frameViews.append(view);
2842     }
2843 
2844     const Vector<RefPtr<FrameView> >::iterator end = frameViews.end();
2845     for (Vector<RefPtr<FrameView> >::iterator it = frameViews.begin(); it != end; ++it)
2846         (*it)->updateLayoutAndStyleIfNeededRecursive();
2847 
2848     // When an <iframe> gets composited, it triggers an extra style recalc in its containing FrameView.
2849     // To avoid pushing an invalid tree for display, we have to check for this case and do another
2850     // style recalc. The extra style recalc needs to happen after our child <iframes> were updated.
2851     // FIXME: We shouldn't be triggering an extra style recalc in the first place.
2852     if (m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate()) {
2853         m_frame->document()->updateRenderTreeIfNeeded();
2854 
2855         if (needsLayout())
2856             layout();
2857     }
2858 
2859     // These asserts ensure that parent frames are clean, when child frames finished updating layout and style.
2860     ASSERT(!needsLayout());
2861     ASSERT(!m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate());
2862 #ifndef NDEBUG
2863     m_frame->document()->renderView()->assertRendererLaidOut();
2864 #endif
2865 
2866 }
2867 
enableAutoSizeMode(bool enable,const IntSize & minSize,const IntSize & maxSize)2868 void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize)
2869 {
2870     ASSERT(!enable || !minSize.isEmpty());
2871     ASSERT(minSize.width() <= maxSize.width());
2872     ASSERT(minSize.height() <= maxSize.height());
2873 
2874     if (m_shouldAutoSize == enable && m_minAutoSize == minSize && m_maxAutoSize == maxSize)
2875         return;
2876 
2877 
2878     m_shouldAutoSize = enable;
2879     m_minAutoSize = minSize;
2880     m_maxAutoSize = maxSize;
2881     m_didRunAutosize = false;
2882 
2883     setLayoutSizeFixedToFrameSize(enable);
2884     setNeedsLayout();
2885     scheduleRelayout();
2886     if (m_shouldAutoSize)
2887         return;
2888 
2889     // Since autosize mode forces the scrollbar mode, change them to being auto.
2890     setVerticalScrollbarLock(false);
2891     setHorizontalScrollbarLock(false);
2892     setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
2893 }
2894 
forceLayout(bool allowSubtree)2895 void FrameView::forceLayout(bool allowSubtree)
2896 {
2897     layout(allowSubtree);
2898 }
2899 
forceLayoutForPagination(const FloatSize & pageSize,const FloatSize & originalPageSize,float maximumShrinkFactor)2900 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor)
2901 {
2902     // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
2903     // the state of things before and after the layout
2904     if (RenderView* renderView = this->renderView()) {
2905         float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
2906         float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
2907 
2908         LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2909         LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2910         renderView->setLogicalWidth(flooredPageLogicalWidth);
2911         renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2912         renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
2913         forceLayout();
2914 
2915         // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
2916         // page width when shrunk, we will lay out at maximum shrink and clip extra content.
2917         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
2918         // implementation should not do this!
2919         bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode();
2920         const LayoutRect& documentRect = renderView->documentRect();
2921         LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
2922         if (docLogicalWidth > pageLogicalWidth) {
2923             FloatSize expectedPageSize(std::min<float>(documentRect.width().toFloat(), pageSize.width() * maximumShrinkFactor), std::min<float>(documentRect.height().toFloat(), pageSize.height() * maximumShrinkFactor));
2924             FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), expectedPageSize);
2925             pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
2926             pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
2927 
2928             flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2929             flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2930             renderView->setLogicalWidth(flooredPageLogicalWidth);
2931             renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2932             renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
2933             forceLayout();
2934 
2935             const LayoutRect& updatedDocumentRect = renderView->documentRect();
2936             LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
2937             LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
2938             LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
2939             LayoutUnit clippedLogicalLeft = 0;
2940             if (!renderView->style()->isLeftToRightDirection())
2941                 clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
2942             LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
2943 
2944             if (!horizontalWritingMode)
2945                 overflow = overflow.transposedRect();
2946             renderView->clearLayoutOverflow();
2947             renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
2948         }
2949     }
2950 
2951     adjustViewSize();
2952 }
2953 
convertFromRenderer(const RenderObject & renderer,const IntRect & rendererRect) const2954 IntRect FrameView::convertFromRenderer(const RenderObject& renderer, const IntRect& rendererRect) const
2955 {
2956     IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer.localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
2957 
2958     // Convert from page ("absolute") to FrameView coordinates.
2959     rect.moveBy(-scrollPosition());
2960 
2961     return rect;
2962 }
2963 
convertToRenderer(const RenderObject & renderer,const IntRect & viewRect) const2964 IntRect FrameView::convertToRenderer(const RenderObject& renderer, const IntRect& viewRect) const
2965 {
2966     IntRect rect = viewRect;
2967 
2968     // Convert from FrameView coords into page ("absolute") coordinates.
2969     rect.moveBy(scrollPosition());
2970 
2971     // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
2972     // move the rect for now.
2973     rect.setLocation(roundedIntPoint(renderer.absoluteToLocal(rect.location(), UseTransforms)));
2974     return rect;
2975 }
2976 
convertFromRenderer(const RenderObject & renderer,const IntPoint & rendererPoint) const2977 IntPoint FrameView::convertFromRenderer(const RenderObject& renderer, const IntPoint& rendererPoint) const
2978 {
2979     IntPoint point = roundedIntPoint(renderer.localToAbsolute(rendererPoint, UseTransforms));
2980 
2981     // Convert from page ("absolute") to FrameView coordinates.
2982     point.moveBy(-scrollPosition());
2983     return point;
2984 }
2985 
convertToRenderer(const RenderObject & renderer,const IntPoint & viewPoint) const2986 IntPoint FrameView::convertToRenderer(const RenderObject& renderer, const IntPoint& viewPoint) const
2987 {
2988     IntPoint point = viewPoint;
2989 
2990     // Convert from FrameView coords into page ("absolute") coordinates.
2991     point += IntSize(scrollX(), scrollY());
2992 
2993     return roundedIntPoint(renderer.absoluteToLocal(point, UseTransforms));
2994 }
2995 
convertToContainingView(const IntRect & localRect) const2996 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
2997 {
2998     if (const ScrollView* parentScrollView = toScrollView(parent())) {
2999         if (parentScrollView->isFrameView()) {
3000             const FrameView* parentView = toFrameView(parentScrollView);
3001             // Get our renderer in the parent view
3002             RenderPart* renderer = m_frame->ownerRenderer();
3003             if (!renderer)
3004                 return localRect;
3005 
3006             IntRect rect(localRect);
3007             // Add borders and padding??
3008             rect.move(renderer->borderLeft() + renderer->paddingLeft(),
3009                 renderer->borderTop() + renderer->paddingTop());
3010             return parentView->convertFromRenderer(*renderer, rect);
3011         }
3012 
3013         return Widget::convertToContainingView(localRect);
3014     }
3015 
3016     return localRect;
3017 }
3018 
convertFromContainingView(const IntRect & parentRect) const3019 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
3020 {
3021     if (const ScrollView* parentScrollView = toScrollView(parent())) {
3022         if (parentScrollView->isFrameView()) {
3023             const FrameView* parentView = toFrameView(parentScrollView);
3024 
3025             // Get our renderer in the parent view
3026             RenderPart* renderer = m_frame->ownerRenderer();
3027             if (!renderer)
3028                 return parentRect;
3029 
3030             IntRect rect = parentView->convertToRenderer(*renderer, parentRect);
3031             // Subtract borders and padding
3032             rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
3033                       -renderer->borderTop() - renderer->paddingTop());
3034             return rect;
3035         }
3036 
3037         return Widget::convertFromContainingView(parentRect);
3038     }
3039 
3040     return parentRect;
3041 }
3042 
convertToContainingView(const IntPoint & localPoint) const3043 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
3044 {
3045     if (const ScrollView* parentScrollView = toScrollView(parent())) {
3046         if (parentScrollView->isFrameView()) {
3047             const FrameView* parentView = toFrameView(parentScrollView);
3048 
3049             // Get our renderer in the parent view
3050             RenderPart* renderer = m_frame->ownerRenderer();
3051             if (!renderer)
3052                 return localPoint;
3053 
3054             IntPoint point(localPoint);
3055 
3056             // Add borders and padding
3057             point.move(renderer->borderLeft() + renderer->paddingLeft(),
3058                        renderer->borderTop() + renderer->paddingTop());
3059             return parentView->convertFromRenderer(*renderer, point);
3060         }
3061 
3062         return Widget::convertToContainingView(localPoint);
3063     }
3064 
3065     return localPoint;
3066 }
3067 
convertFromContainingView(const IntPoint & parentPoint) const3068 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
3069 {
3070     if (const ScrollView* parentScrollView = toScrollView(parent())) {
3071         if (parentScrollView->isFrameView()) {
3072             const FrameView* parentView = toFrameView(parentScrollView);
3073 
3074             // Get our renderer in the parent view
3075             RenderPart* renderer = m_frame->ownerRenderer();
3076             if (!renderer)
3077                 return parentPoint;
3078 
3079             IntPoint point = parentView->convertToRenderer(*renderer, parentPoint);
3080             // Subtract borders and padding
3081             point.move(-renderer->borderLeft() - renderer->paddingLeft(),
3082                        -renderer->borderTop() - renderer->paddingTop());
3083             return point;
3084         }
3085 
3086         return Widget::convertFromContainingView(parentPoint);
3087     }
3088 
3089     return parentPoint;
3090 }
3091 
setTracksPaintInvalidations(bool trackPaintInvalidations)3092 void FrameView::setTracksPaintInvalidations(bool trackPaintInvalidations)
3093 {
3094     if (trackPaintInvalidations == m_isTrackingPaintInvalidations)
3095         return;
3096 
3097     for (Frame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) {
3098         if (!frame->isLocalFrame())
3099             continue;
3100         if (RenderView* renderView = toLocalFrame(frame)->contentRenderer())
3101             renderView->compositor()->setTracksRepaints(trackPaintInvalidations);
3102     }
3103 
3104     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"),
3105         "FrameView::setTracksPaintInvalidations", "enabled", trackPaintInvalidations);
3106 
3107     resetTrackedPaintInvalidations();
3108     m_isTrackingPaintInvalidations = trackPaintInvalidations;
3109 }
3110 
resetTrackedPaintInvalidations()3111 void FrameView::resetTrackedPaintInvalidations()
3112 {
3113     m_trackedPaintInvalidationRects.clear();
3114     if (RenderView* renderView = this->renderView())
3115         renderView->compositor()->resetTrackedRepaintRects();
3116 }
3117 
trackedPaintInvalidationRectsAsText() const3118 String FrameView::trackedPaintInvalidationRectsAsText() const
3119 {
3120     TextStream ts;
3121     if (!m_trackedPaintInvalidationRects.isEmpty()) {
3122         ts << "(repaint rects\n";
3123         for (size_t i = 0; i < m_trackedPaintInvalidationRects.size(); ++i)
3124             ts << "  (rect " << m_trackedPaintInvalidationRects[i].x() << " " << m_trackedPaintInvalidationRects[i].y() << " " << m_trackedPaintInvalidationRects[i].width() << " " << m_trackedPaintInvalidationRects[i].height() << ")\n";
3125         ts << ")\n";
3126     }
3127     return ts.release();
3128 }
3129 
addResizerArea(RenderBox & resizerBox)3130 void FrameView::addResizerArea(RenderBox& resizerBox)
3131 {
3132     if (!m_resizerAreas)
3133         m_resizerAreas = adoptPtr(new ResizerAreaSet);
3134     m_resizerAreas->add(&resizerBox);
3135 }
3136 
removeResizerArea(RenderBox & resizerBox)3137 void FrameView::removeResizerArea(RenderBox& resizerBox)
3138 {
3139     if (!m_resizerAreas)
3140         return;
3141 
3142     ResizerAreaSet::iterator it = m_resizerAreas->find(&resizerBox);
3143     if (it != m_resizerAreas->end())
3144         m_resizerAreas->remove(it);
3145 }
3146 
addScrollableArea(ScrollableArea * scrollableArea)3147 void FrameView::addScrollableArea(ScrollableArea* scrollableArea)
3148 {
3149     ASSERT(scrollableArea);
3150     if (!m_scrollableAreas)
3151         m_scrollableAreas = adoptPtr(new ScrollableAreaSet);
3152     m_scrollableAreas->add(scrollableArea);
3153 }
3154 
removeScrollableArea(ScrollableArea * scrollableArea)3155 void FrameView::removeScrollableArea(ScrollableArea* scrollableArea)
3156 {
3157     if (!m_scrollableAreas)
3158         return;
3159     m_scrollableAreas->remove(scrollableArea);
3160 }
3161 
removeChild(Widget * widget)3162 void FrameView::removeChild(Widget* widget)
3163 {
3164     if (widget->isFrameView())
3165         removeScrollableArea(toFrameView(widget));
3166 
3167     ScrollView::removeChild(widget);
3168 }
3169 
wheelEvent(const PlatformWheelEvent & wheelEvent)3170 bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent)
3171 {
3172     bool allowScrolling = userInputScrollable(HorizontalScrollbar) || userInputScrollable(VerticalScrollbar);
3173 
3174     // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views
3175     // should handle wheel events.
3176 #if !USE(RUBBER_BANDING)
3177     if (!isScrollable())
3178         allowScrolling = false;
3179 #endif
3180 
3181     if (allowScrolling && ScrollableArea::handleWheelEvent(wheelEvent))
3182         return true;
3183 
3184     // If the frame didn't handle the event, give the pinch-zoom viewport a chance to
3185     // process the scroll event.
3186     if (m_frame->settings()->pinchVirtualViewportEnabled() && m_frame->isMainFrame())
3187         return page()->frameHost().pinchViewport().handleWheelEvent(wheelEvent);
3188 
3189     return false;
3190 }
3191 
isVerticalDocument() const3192 bool FrameView::isVerticalDocument() const
3193 {
3194     RenderView* renderView = this->renderView();
3195     if (!renderView)
3196         return true;
3197 
3198     return renderView->style()->isHorizontalWritingMode();
3199 }
3200 
isFlippedDocument() const3201 bool FrameView::isFlippedDocument() const
3202 {
3203     RenderView* renderView = this->renderView();
3204     if (!renderView)
3205         return false;
3206 
3207     return renderView->style()->isFlippedBlocksWritingMode();
3208 }
3209 
axObjectCache() const3210 AXObjectCache* FrameView::axObjectCache() const
3211 {
3212     if (frame().document())
3213         return frame().document()->existingAXObjectCache();
3214     return 0;
3215 }
3216 
setCursor(const Cursor & cursor)3217 void FrameView::setCursor(const Cursor& cursor)
3218 {
3219     Page* page = frame().page();
3220     if (!page || !page->settings().deviceSupportsMouse())
3221         return;
3222     page->chrome().setCursor(cursor);
3223 }
3224 
frameRectsChanged()3225 void FrameView::frameRectsChanged()
3226 {
3227     if (layoutSizeFixedToFrameSize())
3228         setLayoutSizeInternal(frameRect().size());
3229 
3230     ScrollView::frameRectsChanged();
3231 }
3232 
setLayoutSizeInternal(const IntSize & size)3233 void FrameView::setLayoutSizeInternal(const IntSize& size)
3234 {
3235     if (m_layoutSize == size)
3236         return;
3237 
3238     m_layoutSize = size;
3239     contentsResized();
3240 }
3241 
didAddScrollbar(Scrollbar * scrollbar,ScrollbarOrientation orientation)3242 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3243 {
3244     ScrollableArea::didAddScrollbar(scrollbar, orientation);
3245     if (AXObjectCache* cache = axObjectCache())
3246         cache->handleScrollbarUpdate(this);
3247 }
3248 
willRemoveScrollbar(Scrollbar * scrollbar,ScrollbarOrientation orientation)3249 void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3250 {
3251     ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
3252     if (AXObjectCache* cache = axObjectCache()) {
3253         cache->remove(scrollbar);
3254         cache->handleScrollbarUpdate(this);
3255     }
3256 }
3257 
3258 } // namespace WebCore
3259