Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / frame / FrameView.cpp
1 /*
2  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3  *                     1999 Lars Knoll <knoll@kde.org>
4  *                     1999 Antti Koivisto <koivisto@kde.org>
5  *                     2000 Dirk Mueller <mueller@kde.org>
6  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7  *           (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9  * 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/MediaTypeNames.h"
32 #include "core/accessibility/AXObjectCache.h"
33 #include "core/css/FontFaceSet.h"
34 #include "core/css/resolver/StyleResolver.h"
35 #include "core/dom/DocumentMarkerController.h"
36 #include "core/dom/Fullscreen.h"
37 #include "core/editing/FrameSelection.h"
38 #include "core/editing/RenderedPosition.h"
39 #include "core/events/OverflowEvent.h"
40 #include "core/fetch/ResourceFetcher.h"
41 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
42 #include "core/frame/FrameHost.h"
43 #include "core/frame/LocalFrame.h"
44 #include "core/frame/Settings.h"
45 #include "core/html/HTMLFrameElement.h"
46 #include "core/html/HTMLPlugInElement.h"
47 #include "core/html/parser/TextResourceDecoder.h"
48 #include "core/inspector/InspectorInstrumentation.h"
49 #include "core/inspector/InspectorTraceEvents.h"
50 #include "core/loader/FrameLoader.h"
51 #include "core/loader/FrameLoaderClient.h"
52 #include "core/page/Chrome.h"
53 #include "core/page/ChromeClient.h"
54 #include "core/page/EventHandler.h"
55 #include "core/page/FocusController.h"
56 #include "core/page/FrameTree.h"
57 #include "core/page/Page.h"
58 #include "core/page/scrolling/ScrollingCoordinator.h"
59 #include "core/paint/FramePainter.h"
60 #include "core/rendering/RenderCounter.h"
61 #include "core/rendering/RenderEmbeddedObject.h"
62 #include "core/rendering/RenderLayer.h"
63 #include "core/rendering/RenderListBox.h"
64 #include "core/rendering/RenderPart.h"
65 #include "core/rendering/RenderScrollbar.h"
66 #include "core/rendering/RenderScrollbarPart.h"
67 #include "core/rendering/RenderTheme.h"
68 #include "core/rendering/RenderView.h"
69 #include "core/rendering/TextAutosizer.h"
70 #include "core/rendering/compositing/CompositedLayerMapping.h"
71 #include "core/rendering/compositing/CompositedSelectionBound.h"
72 #include "core/rendering/compositing/RenderLayerCompositor.h"
73 #include "core/rendering/style/RenderStyle.h"
74 #include "core/rendering/svg/RenderSVGRoot.h"
75 #include "core/svg/SVGDocumentExtensions.h"
76 #include "core/svg/SVGSVGElement.h"
77 #include "platform/HostWindow.h"
78 #include "platform/RuntimeEnabledFeatures.h"
79 #include "platform/ScriptForbiddenScope.h"
80 #include "platform/TraceEvent.h"
81 #include "platform/fonts/FontCache.h"
82 #include "platform/geometry/FloatRect.h"
83 #include "platform/graphics/GraphicsContext.h"
84 #include "platform/graphics/GraphicsContextStateSaver.h"
85 #include "platform/graphics/GraphicsLayer.h"
86 #include "platform/graphics/GraphicsLayerDebugInfo.h"
87 #include "platform/scroll/ScrollAnimator.h"
88 #include "platform/scroll/ScrollbarTheme.h"
89 #include "platform/text/TextStream.h"
90 #include "wtf/CurrentTime.h"
91 #include "wtf/StdLibExtras.h"
92 #include "wtf/TemporaryChange.h"
93
94 namespace blink {
95
96 using namespace HTMLNames;
97
98 double FrameView::s_currentFrameTimeStamp = 0.0;
99
100 // The maximum number of updateWidgets iterations that should be done before returning.
101 static const unsigned maxUpdateWidgetsIterations = 2;
102 static const double resourcePriorityUpdateDelayAfterScroll = 0.250;
103
104 FrameView::FrameView(LocalFrame* frame)
105     : m_frame(frame)
106     , m_canHaveScrollbars(true)
107     , m_slowRepaintObjectCount(0)
108     , m_hasPendingLayout(false)
109     , m_layoutSubtreeRoot(0)
110     , m_inSynchronousPostLayout(false)
111     , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
112     , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
113     , m_isTransparent(false)
114     , m_baseBackgroundColor(Color::white)
115     , m_mediaType(MediaTypeNames::screen)
116     , m_overflowStatusDirty(true)
117     , m_viewportRenderer(0)
118     , m_wasScrolledByUser(false)
119     , m_inProgrammaticScroll(false)
120     , m_safeToPropagateScrollToParent(true)
121     , m_isTrackingPaintInvalidations(false)
122     , m_scrollCorner(nullptr)
123     , m_visibleContentScaleFactor(1)
124     , m_inputEventsScaleFactorForEmulation(1)
125     , m_layoutSizeFixedToFrameSize(true)
126     , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
127     , m_topControlsViewportAdjustment(0)
128     , m_needsUpdateWidgetPositions(false)
129 #if ENABLE(OILPAN) && ENABLE(ASSERT)
130     , m_hasBeenDisposed(false)
131 #endif
132     , m_horizontalScrollbarMode(ScrollbarAuto)
133     , m_verticalScrollbarMode(ScrollbarAuto)
134     , m_horizontalScrollbarLock(false)
135     , m_verticalScrollbarLock(false)
136     , m_scrollbarsAvoidingResizer(0)
137     , m_scrollbarsSuppressed(false)
138     , m_inUpdateScrollbars(false)
139     , m_shouldDrawPanScrollIcon(false)
140     , m_clipsRepaints(true)
141 {
142     ASSERT(m_frame);
143     init();
144
145     if (!m_frame->isMainFrame())
146         return;
147
148     ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed);
149     ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed);
150 }
151
152 PassRefPtrWillBeRawPtr<FrameView> FrameView::create(LocalFrame* frame)
153 {
154     RefPtrWillBeRawPtr<FrameView> view = adoptRefWillBeNoop(new FrameView(frame));
155     view->show();
156     return view.release();
157 }
158
159 PassRefPtrWillBeRawPtr<FrameView> FrameView::create(LocalFrame* frame, const IntSize& initialSize)
160 {
161     RefPtrWillBeRawPtr<FrameView> view = adoptRefWillBeNoop(new FrameView(frame));
162     view->Widget::setFrameRect(IntRect(view->location(), initialSize));
163     view->setLayoutSizeInternal(initialSize);
164
165     view->show();
166     return view.release();
167 }
168
169 FrameView::~FrameView()
170 {
171 #if ENABLE(OILPAN)
172     ASSERT(m_hasBeenDisposed);
173 #else
174     // Verify that the LocalFrame has a different FrameView or
175     // that it is being detached and destructed.
176     ASSERT(frame().view() != this || !renderView());
177     dispose();
178 #endif
179 }
180
181 void FrameView::dispose()
182 {
183     if (m_postLayoutTasksTimer.isActive())
184         m_postLayoutTasksTimer.stop();
185
186     if (m_didScrollTimer.isActive())
187         m_didScrollTimer.stop();
188
189     removeFromAXObjectCache();
190
191     // Custom scrollbars should already be destroyed at this point
192     ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
193     ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
194
195     setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
196     setHasVerticalScrollbar(false);
197
198     ASSERT(!m_scrollCorner);
199
200     // FIXME: Do we need to do something here for OOPI?
201     HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
202     if (ownerElement && ownerElement->ownedWidget() == this)
203         ownerElement->setWidget(nullptr);
204
205     disposeAutoSizeInfo();
206 #if ENABLE(OILPAN) && ENABLE(ASSERT)
207     m_hasBeenDisposed = true;
208 #endif
209 }
210
211 void FrameView::trace(Visitor* visitor)
212 {
213 #if ENABLE(OILPAN)
214     visitor->trace(m_partUpdateSet);
215     visitor->trace(m_parts);
216     visitor->trace(m_frame);
217     visitor->trace(m_nodeToDraw);
218     visitor->trace(m_maintainScrollPositionAnchor);
219     visitor->trace(m_scrollCorner);
220     visitor->trace(m_autoSizeInfo);
221     visitor->trace(m_horizontalScrollbar);
222     visitor->trace(m_verticalScrollbar);
223     visitor->trace(m_children);
224 #endif
225     Widget::trace(visitor);
226 }
227
228 void FrameView::reset()
229 {
230     m_hasPendingLayout = false;
231     m_layoutSubtreeRoot = 0;
232     m_doFullPaintInvalidation = false;
233     m_layoutSchedulingEnabled = true;
234     m_inPerformLayout = false;
235     m_canInvalidatePaintDuringPerformLayout = false;
236     m_inSynchronousPostLayout = false;
237     m_layoutCount = 0;
238     m_nestedLayoutCount = 0;
239     m_postLayoutTasksTimer.stop();
240     m_updateWidgetsTimer.stop();
241     m_firstLayout = true;
242     m_firstLayoutCallbackPending = false;
243     m_wasScrolledByUser = false;
244     m_safeToPropagateScrollToParent = true;
245     m_lastViewportSize = IntSize();
246     m_lastZoomFactor = 1.0f;
247     m_isTrackingPaintInvalidations = false;
248     m_trackedPaintInvalidationRects.clear();
249     m_lastPaintTime = 0;
250     m_paintBehavior = PaintBehaviorNormal;
251     m_isPainting = false;
252     m_visuallyNonEmptyCharacterCount = 0;
253     m_visuallyNonEmptyPixelCount = 0;
254     m_isVisuallyNonEmpty = false;
255     m_firstVisuallyNonEmptyLayoutCallbackPending = true;
256     m_maintainScrollPositionAnchor = nullptr;
257     m_viewportConstrainedObjects.clear();
258 }
259
260 void FrameView::removeFromAXObjectCache()
261 {
262     if (AXObjectCache* cache = axObjectCache()) {
263         cache->remove(this);
264         cache->childrenChanged(m_frame->pagePopupOwner());
265     }
266 }
267
268 void FrameView::init()
269 {
270     reset();
271
272     m_size = LayoutSize();
273
274     // Propagate the marginwidth/height and scrolling modes to the view.
275     // FIXME: Do we need to do this for OOPI?
276     Element* ownerElement = m_frame->deprecatedLocalOwner();
277     if (ownerElement && (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))) {
278         HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
279         if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
280             setCanHaveScrollbars(false);
281     }
282 }
283
284 void FrameView::prepareForDetach()
285 {
286     RELEASE_ASSERT(!isInPerformLayout());
287
288     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
289         scrollAnimator->cancelAnimations();
290     cancelProgrammaticScrollAnimation();
291
292     detachCustomScrollbars();
293     // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
294     // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
295     removeFromAXObjectCache();
296
297     if (m_frame->page()) {
298         if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
299             scrollingCoordinator->willDestroyScrollableArea(this);
300     }
301
302 #if ENABLE(OILPAN)
303     // FIXME: once/if dust settles, do this always (non-Oilpan)?
304     //
305     // FIXME: Oilpan: is this safe to dispose() if there are FrameView protections on the stack?
306     dispose();
307 #endif
308 }
309
310 void FrameView::detachCustomScrollbars()
311 {
312     Scrollbar* horizontalBar = horizontalScrollbar();
313     if (horizontalBar && horizontalBar->isCustomScrollbar())
314         setHasHorizontalScrollbar(false);
315
316     Scrollbar* verticalBar = verticalScrollbar();
317     if (verticalBar && verticalBar->isCustomScrollbar())
318         setHasVerticalScrollbar(false);
319
320     if (m_scrollCorner) {
321         m_scrollCorner->destroy();
322         m_scrollCorner = nullptr;
323     }
324 }
325
326 void FrameView::recalculateCustomScrollbarStyle()
327 {
328     bool didStyleChange = false;
329     if (m_horizontalScrollbar && m_horizontalScrollbar->isCustomScrollbar()) {
330         m_horizontalScrollbar->styleChanged();
331         didStyleChange = true;
332     }
333     if (m_verticalScrollbar && m_verticalScrollbar->isCustomScrollbar()) {
334         m_verticalScrollbar->styleChanged();
335         didStyleChange = true;
336     }
337     if (didStyleChange) {
338         updateScrollbarGeometry();
339         updateScrollCorner();
340         positionScrollbarLayers();
341     }
342 }
343
344 void FrameView::recalculateScrollbarOverlayStyle()
345 {
346     ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
347     ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
348
349     Color backgroundColor = documentBackgroundColor();
350     // Reduce the background color from RGB to a lightness value
351     // and determine which scrollbar style to use based on a lightness
352     // heuristic.
353     double hue, saturation, lightness;
354     backgroundColor.getHSL(hue, saturation, lightness);
355     if (lightness <= .5)
356         overlayStyle = ScrollbarOverlayStyleLight;
357
358     if (oldOverlayStyle != overlayStyle)
359         setScrollbarOverlayStyle(overlayStyle);
360 }
361
362 void FrameView::clear()
363 {
364     reset();
365     setScrollbarsSuppressed(true);
366 }
367
368 bool FrameView::didFirstLayout() const
369 {
370     return !m_firstLayout;
371 }
372
373 void FrameView::invalidateRect(const IntRect& rect)
374 {
375     // For querying RenderLayer::compositingState() when invalidating scrollbars.
376     // FIXME: do all scrollbar invalidations after layout of all frames is complete. It's currently not recursively true.
377     DisableCompositingQueryAsserts disabler;
378     if (!parent()) {
379         if (HostWindow* window = hostWindow())
380             window->invalidateContentsAndRootView(rect);
381         return;
382     }
383
384     RenderPart* renderer = m_frame->ownerRenderer();
385     if (!renderer)
386         return;
387
388     IntRect paintInvalidationRect = rect;
389     paintInvalidationRect.move(renderer->borderLeft() + renderer->paddingLeft(),
390                      renderer->borderTop() + renderer->paddingTop());
391     renderer->invalidatePaintRectangle(paintInvalidationRect);
392 }
393
394 void FrameView::setFrameRect(const IntRect& newRect)
395 {
396     IntRect oldRect = frameRect();
397     if (newRect == oldRect)
398         return;
399
400     // Autosized font sizes depend on the width of the viewing area.
401     bool autosizerNeedsUpdating = false;
402     if (newRect.width() != oldRect.width() && m_frame->isMainFrame() && m_frame->settings()->textAutosizingEnabled())
403         autosizerNeedsUpdating = true;
404
405     Widget::setFrameRect(newRect);
406
407     updateScrollbars(scrollOffsetDouble());
408     frameRectsChanged();
409
410     updateScrollableAreaSet();
411
412     if (autosizerNeedsUpdating) {
413         // This needs to be after the call to Widget::setFrameRect, because it reads the new width.
414         if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer())
415             textAutosizer->updatePageInfoInAllFrames();
416     }
417
418     if (RenderView* renderView = this->renderView()) {
419         if (renderView->usesCompositing())
420             renderView->compositor()->frameViewDidChangeSize();
421     }
422
423     viewportConstrainedVisibleContentSizeChanged(newRect.width() != oldRect.width(), newRect.height() != oldRect.height());
424
425     if (oldRect.size() != newRect.size()
426         && m_frame->isMainFrame()
427         && m_frame->settings()->pinchVirtualViewportEnabled())
428         page()->frameHost().pinchViewport().mainFrameDidChangeSize();
429 }
430
431 Page* FrameView::page() const
432 {
433     return frame().page();
434 }
435
436 RenderView* FrameView::renderView() const
437 {
438     return frame().contentRenderer();
439 }
440
441 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
442 {
443     m_canHaveScrollbars = canHaveScrollbars;
444
445     ScrollbarMode newHorizontalMode;
446     ScrollbarMode newVerticalMode;
447
448     scrollbarModes(newHorizontalMode, newVerticalMode);
449
450     if (canHaveScrollbars && newVerticalMode == ScrollbarAlwaysOff)
451         newVerticalMode = ScrollbarAuto;
452     else if (!canHaveScrollbars)
453         newVerticalMode = ScrollbarAlwaysOff;
454
455     if (canHaveScrollbars && newHorizontalMode == ScrollbarAlwaysOff)
456         newHorizontalMode = ScrollbarAuto;
457     else if (!canHaveScrollbars)
458         newHorizontalMode = ScrollbarAlwaysOff;
459
460     setScrollbarModes(newHorizontalMode, newVerticalMode);
461 }
462
463 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, LocalFrame*& customScrollbarFrame)
464 {
465     customScrollbarElement = 0;
466     customScrollbarFrame = 0;
467
468     if (Settings* settings = m_frame->settings()) {
469         if (!settings->allowCustomScrollbarInMainFrame() && m_frame->isMainFrame())
470             return false;
471     }
472
473     // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
474     Document* doc = m_frame->document();
475
476     // Try the <body> element first as a scrollbar source.
477     Element* body = doc ? doc->body() : 0;
478     if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
479         customScrollbarElement = body;
480         return true;
481     }
482
483     // If the <body> didn't have a custom style, then the root element might.
484     Element* docElement = doc ? doc->documentElement() : 0;
485     if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
486         customScrollbarElement = docElement;
487         return true;
488     }
489
490     // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
491     RenderPart* frameRenderer = m_frame->ownerRenderer();
492     if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) {
493         customScrollbarFrame = m_frame.get();
494         return true;
495     }
496
497     return false;
498 }
499
500 PassRefPtrWillBeRawPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
501 {
502     Element* customScrollbarElement = 0;
503     LocalFrame* customScrollbarFrame = 0;
504     if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame))
505         return RenderScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame);
506
507     // Nobody set a custom style, so we just use a native scrollbar.
508     return Scrollbar::create(this, orientation, RegularScrollbar);
509 }
510
511 void FrameView::setContentsSize(const IntSize& size)
512 {
513     if (size == contentsSize())
514         return;
515
516     m_contentsSize = size;
517     updateScrollbars(scrollOffsetDouble());
518     updateOverhangAreas();
519     ScrollableArea::contentsResized();
520
521     Page* page = frame().page();
522     if (!page)
523         return;
524
525     updateScrollableAreaSet();
526
527     page->chrome().contentsSizeChanged(m_frame.get(), size);
528 }
529
530 IntPoint FrameView::clampOffsetAtScale(const IntPoint& offset, float scale) const
531 {
532     IntPoint maxScrollExtent(contentsSize().width() - scrollOrigin().x(), contentsSize().height() - scrollOrigin().y());
533     FloatSize scaledSize = unscaledVisibleContentSize();
534     if (scale)
535         scaledSize.scale(1 / scale);
536
537     IntPoint clampedOffset = offset;
538     clampedOffset = clampedOffset.shrunkTo(maxScrollExtent - expandedIntSize(scaledSize));
539     clampedOffset = clampedOffset.expandedTo(-scrollOrigin());
540
541     return clampedOffset;
542 }
543
544 void FrameView::adjustViewSize()
545 {
546     RenderView* renderView = this->renderView();
547     if (!renderView)
548         return;
549
550     ASSERT(m_frame->view() == this);
551
552     const IntRect rect = renderView->documentRect();
553     const IntSize& size = rect.size();
554     setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize());
555
556     setContentsSize(size);
557 }
558
559 void FrameView::applyOverflowToViewportAndSetRenderer(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
560 {
561     // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
562     // overflow:hidden and overflow:scroll on <body> as applying to the document's
563     // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
564     // use the root element.
565
566     EOverflow overflowX = o->style()->overflowX();
567     EOverflow overflowY = o->style()->overflowY();
568
569     if (o->isSVGRoot()) {
570         // Don't allow overflow to affect <img> and css backgrounds
571         if (toRenderSVGRoot(o)->isEmbeddedThroughSVGImage())
572             return;
573
574         // FIXME: evaluate if we can allow overflow for these cases too.
575         // Overflow is always hidden when stand-alone SVG documents are embedded.
576         if (toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) {
577             overflowX = OHIDDEN;
578             overflowY = OHIDDEN;
579         }
580     }
581
582     bool ignoreOverflowHidden = false;
583     if (m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame())
584         ignoreOverflowHidden = true;
585
586     switch (overflowX) {
587         case OHIDDEN:
588             if (!ignoreOverflowHidden)
589                 hMode = ScrollbarAlwaysOff;
590             break;
591         case OSCROLL:
592             hMode = ScrollbarAlwaysOn;
593             break;
594         case OAUTO:
595             hMode = ScrollbarAuto;
596             break;
597         default:
598             // Don't set it at all.
599             ;
600     }
601
602      switch (overflowY) {
603         case OHIDDEN:
604             if (!ignoreOverflowHidden)
605                 vMode = ScrollbarAlwaysOff;
606             break;
607         case OSCROLL:
608             vMode = ScrollbarAlwaysOn;
609             break;
610         case OAUTO:
611             vMode = ScrollbarAuto;
612             break;
613         default:
614             // Don't set it at all.
615             ;
616     }
617
618     m_viewportRenderer = o;
619 }
620
621 void FrameView::calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
622 {
623     m_viewportRenderer = 0;
624
625     // FIXME: How do we handle this for OOPI?
626     const HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
627     if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
628         hMode = ScrollbarAlwaysOff;
629         vMode = ScrollbarAlwaysOff;
630         return;
631     }
632
633     if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
634         hMode = ScrollbarAuto;
635         vMode = ScrollbarAuto;
636     } else {
637         hMode = ScrollbarAlwaysOff;
638         vMode = ScrollbarAlwaysOff;
639     }
640
641     if (!isSubtreeLayout()) {
642         Document* document = m_frame->document();
643         Node* body = document->body();
644         if (isHTMLFrameSetElement(body) && body->renderer()) {
645             vMode = ScrollbarAlwaysOff;
646             hMode = ScrollbarAlwaysOff;
647         } else if (Element* viewportElement = document->viewportDefiningElement()) {
648             if (RenderObject* viewportRenderer = viewportElement->renderer()) {
649                 if (viewportRenderer->style())
650                     applyOverflowToViewportAndSetRenderer(viewportRenderer, hMode, vMode);
651             }
652         }
653     }
654 }
655
656 void FrameView::updateAcceleratedCompositingSettings()
657 {
658     if (RenderView* renderView = this->renderView())
659         renderView->compositor()->updateAcceleratedCompositingSettings();
660 }
661
662 void FrameView::recalcOverflowAfterStyleChange()
663 {
664     RenderView* renderView = this->renderView();
665     RELEASE_ASSERT(renderView);
666     if (!renderView->needsOverflowRecalcAfterStyleChange())
667         return;
668
669     renderView->recalcOverflowAfterStyleChange();
670
671     IntRect documentRect = renderView->documentRect();
672     if (scrollOrigin() == -documentRect.location() && contentsSize() == documentRect.size())
673         return;
674
675     if (needsLayout())
676         return;
677
678     InUpdateScrollbarsScope inUpdateScrollbarsScope(this);
679
680     bool shouldHaveHorizontalScrollbar = false;
681     bool shouldHaveVerticalScrollbar = false;
682     computeScrollbarExistence(shouldHaveHorizontalScrollbar, shouldHaveVerticalScrollbar, documentRect.size());
683
684     bool hasHorizontalScrollbar = horizontalScrollbar();
685     bool hasVerticalScrollbar = verticalScrollbar();
686     if (hasHorizontalScrollbar != shouldHaveHorizontalScrollbar
687         || hasVerticalScrollbar != shouldHaveVerticalScrollbar) {
688         setNeedsLayout();
689         return;
690     }
691
692     adjustViewSize();
693     updateScrollbarGeometry();
694 }
695
696 bool FrameView::usesCompositedScrolling() const
697 {
698     RenderView* renderView = this->renderView();
699     if (!renderView)
700         return false;
701     if (m_frame->settings() && m_frame->settings()->preferCompositingToLCDTextEnabled())
702         return renderView->compositor()->inCompositingMode();
703     return false;
704 }
705
706 GraphicsLayer* FrameView::layerForScrolling() const
707 {
708     RenderView* renderView = this->renderView();
709     if (!renderView)
710         return 0;
711     return renderView->compositor()->scrollLayer();
712 }
713
714 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
715 {
716     RenderView* renderView = this->renderView();
717     if (!renderView)
718         return 0;
719     return renderView->compositor()->layerForHorizontalScrollbar();
720 }
721
722 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
723 {
724     RenderView* renderView = this->renderView();
725     if (!renderView)
726         return 0;
727     return renderView->compositor()->layerForVerticalScrollbar();
728 }
729
730 GraphicsLayer* FrameView::layerForScrollCorner() const
731 {
732     RenderView* renderView = this->renderView();
733     if (!renderView)
734         return 0;
735     return renderView->compositor()->layerForScrollCorner();
736 }
737
738 bool FrameView::isEnclosedInCompositingLayer() const
739 {
740     // FIXME: It's a bug that compositing state isn't always up to date when this is called. crbug.com/366314
741     DisableCompositingQueryAsserts disabler;
742
743     RenderObject* frameOwnerRenderer = m_frame->ownerRenderer();
744     return frameOwnerRenderer && frameOwnerRenderer->enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries();
745 }
746
747 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
748 {
749     return onlyDuringLayout && layoutPending() ? 0 : m_layoutSubtreeRoot;
750 }
751
752 inline void FrameView::forceLayoutParentViewIfNeeded()
753 {
754     RenderPart* ownerRenderer = m_frame->ownerRenderer();
755     if (!ownerRenderer || !ownerRenderer->frame())
756         return;
757
758     RenderBox* contentBox = embeddedContentBox();
759     if (!contentBox)
760         return;
761
762     RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
763     if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
764         return;
765
766     // If the embedded SVG document appears the first time, the ownerRenderer has already finished
767     // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
768     // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
769     // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
770     // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
771     // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
772     // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
773     RefPtrWillBeRawPtr<FrameView> frameView = ownerRenderer->frame()->view();
774
775     // Mark the owner renderer as needing layout.
776     ownerRenderer->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
777
778     // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
779     ASSERT(frameView);
780     frameView->layout();
781 }
782
783 void FrameView::performPreLayoutTasks()
784 {
785     TRACE_EVENT0("blink", "FrameView::performPreLayoutTasks");
786     lifecycle().advanceTo(DocumentLifecycle::InPreLayout);
787
788     // Don't schedule more layouts, we're in one.
789     TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
790
791     if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) {
792         // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now.
793         m_inSynchronousPostLayout = true;
794         performPostLayoutTasks();
795         m_inSynchronousPostLayout = false;
796     }
797
798     Document* document = m_frame->document();
799     if (wasViewportResized())
800         document->notifyResizeForViewportUnits();
801
802     // Viewport-dependent media queries may cause us to need completely different style information.
803     if (!document->styleResolver() || document->styleResolver()->mediaQueryAffectedByViewportChange()) {
804         document->styleResolverChanged();
805         document->mediaQueryAffectingValueChanged();
806
807         // FIXME: This instrumentation event is not strictly accurate since cached media query results
808         //        do not persist across StyleResolver rebuilds.
809         InspectorInstrumentation::mediaQueryResultChanged(document);
810     } else {
811         document->evaluateMediaQueryList();
812     }
813
814     document->updateRenderTreeIfNeeded();
815     lifecycle().advanceTo(DocumentLifecycle::StyleClean);
816 }
817
818 void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout)
819 {
820     TRACE_EVENT0("blink", "FrameView::performLayout");
821
822     ScriptForbiddenScope forbidScript;
823
824     ASSERT(!isInPerformLayout());
825     lifecycle().advanceTo(DocumentLifecycle::InPerformLayout);
826
827     TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true);
828
829     // performLayout is the actual guts of layout().
830     // FIXME: The 300 other lines in layout() probably belong in other helper functions
831     // so that a single human could understand what layout() is actually doing.
832
833     LayoutState layoutState(*rootForThisLayout);
834
835     forceLayoutParentViewIfNeeded();
836
837     // FIXME (crbug.com/256657): Do not do two layouts for text autosizing.
838     rootForThisLayout->layout();
839     gatherDebugLayoutRects(rootForThisLayout);
840
841     ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
842
843     lifecycle().advanceTo(DocumentLifecycle::AfterPerformLayout);
844 }
845
846 void FrameView::scheduleOrPerformPostLayoutTasks()
847 {
848     if (m_postLayoutTasksTimer.isActive())
849         return;
850
851     if (!m_inSynchronousPostLayout) {
852         m_inSynchronousPostLayout = true;
853         // Calls resumeScheduledEvents()
854         performPostLayoutTasks();
855         m_inSynchronousPostLayout = false;
856     }
857
858     if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout)) {
859         // If we need layout or are already in a synchronous call to postLayoutTasks(),
860         // defer widget updates and event dispatch until after we return. postLayoutTasks()
861         // can make us need to update again, and we can get stuck in a nasty cycle unless
862         // we call it through the timer here.
863         m_postLayoutTasksTimer.startOneShot(0, FROM_HERE);
864         if (needsLayout())
865             layout();
866     }
867 }
868
869 void FrameView::layout(bool allowSubtree)
870 {
871     // We should never layout a Document which is not in a LocalFrame.
872     ASSERT(m_frame);
873     ASSERT(m_frame->view() == this);
874     ASSERT(m_frame->page());
875
876     ScriptForbiddenScope forbidScript;
877
878     if (isInPerformLayout() || !m_frame->document()->isActive())
879         return;
880
881     TRACE_EVENT0("blink", "FrameView::layout");
882     TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "Layout");
883
884     // Protect the view from being deleted during layout (in recalcStyle)
885     RefPtrWillBeRawPtr<FrameView> protector(this);
886
887     // Every scroll that happens during layout is programmatic.
888     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
889
890     if (m_autoSizeInfo)
891         m_autoSizeInfo->autoSizeIfNeeded();
892
893     m_hasPendingLayout = false;
894     DocumentLifecycle::Scope lifecycleScope(lifecycle(), DocumentLifecycle::LayoutClean);
895
896     RELEASE_ASSERT(!isPainting());
897
898     TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "beginData", InspectorLayoutEvent::beginData(this));
899     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
900     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
901     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get());
902
903     if (!allowSubtree && isSubtreeLayout()) {
904         m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
905         m_layoutSubtreeRoot = 0;
906     }
907
908     performPreLayoutTasks();
909
910 #if !ENABLE(OILPAN)
911     // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
912     // so there's no point to continuing to layout
913     if (protector->hasOneRef())
914         return;
915 #endif
916
917     Document* document = m_frame->document();
918     bool inSubtreeLayout = isSubtreeLayout();
919     RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderView();
920     if (!rootForThisLayout) {
921         // FIXME: Do we need to set m_size here?
922         ASSERT_NOT_REACHED();
923         return;
924     }
925
926     FontCachePurgePreventer fontCachePurgePreventer;
927     RenderLayer* layer;
928     {
929         TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
930
931         m_nestedLayoutCount++;
932         if (!inSubtreeLayout) {
933             Document* document = m_frame->document();
934             Node* body = document->body();
935             if (body && body->renderer()) {
936                 if (isHTMLFrameSetElement(*body)) {
937                     body->renderer()->setChildNeedsLayout();
938                 } else if (isHTMLBodyElement(*body)) {
939                     if (!m_firstLayout && m_size.height() != layoutSize().height() && body->renderer()->enclosingBox()->stretchesToViewport())
940                         body->renderer()->setChildNeedsLayout();
941                 }
942             }
943         }
944         updateCounters();
945
946         ScrollbarMode hMode;
947         ScrollbarMode vMode;
948         calculateScrollbarModesForLayoutAndSetViewportRenderer(hMode, vMode);
949
950         if (!inSubtreeLayout) {
951             // Now set our scrollbar state for the layout.
952             ScrollbarMode currentHMode = horizontalScrollbarMode();
953             ScrollbarMode currentVMode = verticalScrollbarMode();
954
955             if (m_firstLayout) {
956                 setScrollbarsSuppressed(true);
957
958                 m_doFullPaintInvalidation = true;
959                 m_firstLayout = false;
960                 m_firstLayoutCallbackPending = true;
961                 m_lastViewportSize = layoutSize(IncludeScrollbars);
962                 m_lastZoomFactor = rootForThisLayout->style()->zoom();
963
964                 // Set the initial vMode to AlwaysOn if we're auto.
965                 if (vMode == ScrollbarAuto)
966                     setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
967                 // Set the initial hMode to AlwaysOff if we're auto.
968                 if (hMode == ScrollbarAuto)
969                     setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
970
971                 setScrollbarModes(hMode, vMode);
972                 setScrollbarsSuppressed(false, true);
973             } else if (hMode != currentHMode || vMode != currentVMode) {
974                 setScrollbarModes(hMode, vMode);
975             }
976
977             LayoutSize oldSize = m_size;
978
979             m_size = LayoutSize(layoutSize().width(), layoutSize().height());
980
981             if (oldSize != m_size && !m_firstLayout) {
982                 RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0;
983                 RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0;
984                 if (bodyRenderer && bodyRenderer->stretchesToViewport())
985                     bodyRenderer->setChildNeedsLayout();
986                 else if (rootRenderer && rootRenderer->stretchesToViewport())
987                     rootRenderer->setChildNeedsLayout();
988             }
989
990             // We need to set m_doFullPaintInvalidation before triggering layout as RenderObject::checkForPaintInvalidation
991             // checks the boolean to disable local paint invalidations.
992             m_doFullPaintInvalidation |= renderView()->shouldDoFullPaintInvalidationForNextLayout();
993         }
994
995         layer = rootForThisLayout->enclosingLayer();
996
997         performLayout(rootForThisLayout, inSubtreeLayout);
998
999         m_layoutSubtreeRoot = 0;
1000         // We need to ensure that we mark up all renderers up to the RenderView
1001         // for paint invalidation. This simplifies our code as we just always
1002         // do a full tree walk.
1003         if (RenderObject* container = rootForThisLayout->container())
1004             container->setMayNeedPaintInvalidation(true);
1005     } // Reset m_layoutSchedulingEnabled to its previous value.
1006
1007     if (!inSubtreeLayout && !toRenderView(rootForThisLayout)->document().printing())
1008         adjustViewSize();
1009
1010     layer->updateLayerPositionsAfterLayout();
1011
1012     renderView()->compositor()->didLayout();
1013
1014     m_layoutCount++;
1015
1016     if (AXObjectCache* cache = rootForThisLayout->document().axObjectCache()) {
1017         const KURL& url = rootForThisLayout->document().url();
1018         if (url.isValid() && !url.isAboutBlankURL())
1019             cache->handleLayoutComplete(rootForThisLayout);
1020     }
1021     updateAnnotatedRegions();
1022
1023     ASSERT(!rootForThisLayout->needsLayout());
1024
1025     if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1026         updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight());
1027
1028     scheduleOrPerformPostLayoutTasks();
1029
1030     TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "endData", InspectorLayoutEvent::endData(rootForThisLayout));
1031     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1032     InspectorInstrumentation::didLayout(cookie, rootForThisLayout);
1033
1034     m_nestedLayoutCount--;
1035     if (m_nestedLayoutCount)
1036         return;
1037
1038 #if ENABLE(ASSERT)
1039     // Post-layout assert that nobody was re-marked as needing layout during layout.
1040     document->renderView()->assertSubtreeIsLaidOut();
1041 #endif
1042
1043     // FIXME: It should be not possible to remove the FrameView from the frame/page during layout
1044     // however m_inPerformLayout is not set for most of this function, so none of our RELEASE_ASSERTS
1045     // in LocalFrame/Page will fire. One of the post-layout tasks is disconnecting the LocalFrame from
1046     // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html
1047     // necessitating this check here.
1048     // ASSERT(frame()->page());
1049     if (frame().page())
1050         frame().page()->chrome().client().layoutUpdated(m_frame.get());
1051 }
1052
1053 // The plan is to move to compositor-queried paint invalidation, in which case this
1054 // method would setNeedsRedraw on the GraphicsLayers with invalidations and
1055 // let the compositor pick which to actually draw.
1056 // See http://crbug.com/306706
1057 void FrameView::invalidateTreeIfNeeded()
1058 {
1059     ASSERT(renderView());
1060     RenderView& rootForPaintInvalidation = *renderView();
1061     ASSERT(!rootForPaintInvalidation.needsLayout());
1062
1063     TRACE_EVENT1("blink", "FrameView::invalidateTree", "root", rootForPaintInvalidation.debugName().ascii());
1064
1065     PaintInvalidationState rootPaintInvalidationState(rootForPaintInvalidation);
1066
1067     if (m_doFullPaintInvalidation)
1068         renderView()->compositor()->fullyInvalidatePaint();
1069
1070     rootForPaintInvalidation.invalidateTreeIfNeeded(rootPaintInvalidationState);
1071
1072     // Invalidate the paint of the frameviews scrollbars if needed
1073     if (hasVerticalBarDamage())
1074         invalidateRect(verticalBarDamage());
1075     if (hasHorizontalBarDamage())
1076         invalidateRect(horizontalBarDamage());
1077     resetScrollbarDamage();
1078
1079
1080 #ifndef NDEBUG
1081     renderView()->assertSubtreeClearedPaintInvalidationState();
1082 #endif
1083
1084     if (m_frame->selection().isCaretBoundsDirty())
1085         m_frame->selection().invalidateCaretRect();
1086 }
1087
1088 DocumentLifecycle& FrameView::lifecycle() const
1089 {
1090     return m_frame->document()->lifecycle();
1091 }
1092
1093 void FrameView::gatherDebugLayoutRects(RenderObject* layoutRoot)
1094 {
1095     bool isTracing;
1096     TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
1097     if (!isTracing)
1098         return;
1099     if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping())
1100         return;
1101     // For access to compositedLayerMapping().
1102     DisableCompositingQueryAsserts disabler;
1103     GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer();
1104     if (!graphicsLayer)
1105         return;
1106
1107     GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo();
1108
1109     debugInfo.currentLayoutRects().clear();
1110     for (RenderObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) {
1111         if (renderer->layoutDidGetCalledSinceLastFrame()) {
1112             FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->previousPaintInvalidationRect()));
1113             LayoutRect rect = quad.enclosingBoundingBox();
1114             debugInfo.currentLayoutRects().append(rect);
1115         }
1116     }
1117 }
1118
1119 RenderBox* FrameView::embeddedContentBox() const
1120 {
1121     RenderView* renderView = this->renderView();
1122     if (!renderView)
1123         return 0;
1124
1125     RenderObject* firstChild = renderView->firstChild();
1126     if (!firstChild || !firstChild->isBox())
1127         return 0;
1128
1129     // Curently only embedded SVG documents participate in the size-negotiation logic.
1130     if (firstChild->isSVGRoot())
1131         return toRenderBox(firstChild);
1132
1133     return 0;
1134 }
1135
1136
1137 void FrameView::addPart(RenderPart* object)
1138 {
1139     m_parts.add(object);
1140 }
1141
1142 void FrameView::removePart(RenderPart* object)
1143 {
1144     m_parts.remove(object);
1145 }
1146
1147 void FrameView::updateWidgetPositions()
1148 {
1149     WillBeHeapVector<RefPtrWillBeMember<RenderPart> > parts;
1150     copyToVector(m_parts, parts);
1151
1152     // Script or plugins could detach the frame so abort processing if that happens.
1153
1154     for (size_t i = 0; i < parts.size() && renderView(); ++i)
1155         parts[i]->updateWidgetPosition();
1156
1157     for (size_t i = 0; i < parts.size() && renderView(); ++i)
1158         parts[i]->widgetPositionsUpdated();
1159 }
1160
1161 void FrameView::addPartToUpdate(RenderEmbeddedObject& object)
1162 {
1163     ASSERT(isInPerformLayout());
1164     // Tell the DOM element that it needs a widget update.
1165     Node* node = object.node();
1166     ASSERT(node);
1167     if (isHTMLObjectElement(*node) || isHTMLEmbedElement(*node))
1168         toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true);
1169
1170     m_partUpdateSet.add(&object);
1171 }
1172
1173 void FrameView::setMediaType(const AtomicString& mediaType)
1174 {
1175     ASSERT(m_frame->document());
1176     m_frame->document()->mediaQueryAffectingValueChanged();
1177     m_mediaType = mediaType;
1178 }
1179
1180 AtomicString FrameView::mediaType() const
1181 {
1182     // See if we have an override type.
1183     String overrideType;
1184     InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType);
1185     if (!overrideType.isNull())
1186         return AtomicString(overrideType);
1187     return m_mediaType;
1188 }
1189
1190 void FrameView::adjustMediaTypeForPrinting(bool printing)
1191 {
1192     if (printing) {
1193         if (m_mediaTypeWhenNotPrinting.isNull())
1194             m_mediaTypeWhenNotPrinting = mediaType();
1195             setMediaType(MediaTypeNames::print);
1196     } else {
1197         if (!m_mediaTypeWhenNotPrinting.isNull())
1198             setMediaType(m_mediaTypeWhenNotPrinting);
1199         m_mediaTypeWhenNotPrinting = nullAtom;
1200     }
1201 }
1202
1203 bool FrameView::contentsInCompositedLayer() const
1204 {
1205     RenderView* renderView = this->renderView();
1206     if (renderView && renderView->compositingState() == PaintsIntoOwnBacking) {
1207         GraphicsLayer* layer = renderView->layer()->compositedLayerMapping()->mainGraphicsLayer();
1208         if (layer && layer->drawsContent())
1209             return true;
1210     }
1211
1212     return false;
1213 }
1214
1215 void FrameView::addSlowRepaintObject()
1216 {
1217     if (!m_slowRepaintObjectCount++) {
1218         if (Page* page = m_frame->page()) {
1219             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1220                 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1221         }
1222     }
1223 }
1224
1225 void FrameView::removeSlowRepaintObject()
1226 {
1227     ASSERT(m_slowRepaintObjectCount > 0);
1228     m_slowRepaintObjectCount--;
1229     if (!m_slowRepaintObjectCount) {
1230         if (Page* page = m_frame->page()) {
1231             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1232                 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1233         }
1234     }
1235 }
1236
1237 void FrameView::addViewportConstrainedObject(RenderObject* object)
1238 {
1239     if (!m_viewportConstrainedObjects)
1240         m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet);
1241
1242     if (!m_viewportConstrainedObjects->contains(object)) {
1243         m_viewportConstrainedObjects->add(object);
1244
1245         if (Page* page = m_frame->page()) {
1246             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1247                 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1248         }
1249     }
1250 }
1251
1252 void FrameView::removeViewportConstrainedObject(RenderObject* object)
1253 {
1254     if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) {
1255         m_viewportConstrainedObjects->remove(object);
1256
1257         if (Page* page = m_frame->page()) {
1258             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1259                 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1260         }
1261     }
1262 }
1263
1264 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1265 {
1266     LayoutRect viewportRect = visibleContentRect();
1267     // Ignore overhang. No-op when not using rubber banding.
1268     viewportRect.setLocation(clampScrollPosition(scrollPosition()));
1269     return viewportRect;
1270 }
1271
1272 void FrameView::viewportConstrainedVisibleContentSizeChanged(bool widthChanged, bool heightChanged)
1273 {
1274     if (!hasViewportConstrainedObjects())
1275         return;
1276
1277     // If viewport is not enabled, frameRect change will cause layout size change and then layout.
1278     // Otherwise, viewport constrained objects need their layout flags set separately to ensure
1279     // they are positioned correctly. In the virtual-viewport pinch mode frame rect changes wont
1280     // necessarily cause a layout size change so only take this early-out if we're in old-style
1281     // pinch.
1282     if (m_frame->settings()
1283         && !m_frame->settings()->viewportEnabled()
1284         && !m_frame->settings()->pinchVirtualViewportEnabled())
1285         return;
1286
1287     for (const auto& viewportConstrainedObject : *m_viewportConstrainedObjects) {
1288         RenderObject* renderer = viewportConstrainedObject;
1289         RenderStyle* style = renderer->style();
1290         if (widthChanged) {
1291             if (style->width().isFixed() && (style->left().isAuto() || style->right().isAuto()))
1292                 renderer->setNeedsPositionedMovementLayout();
1293             else
1294                 renderer->setNeedsLayoutAndFullPaintInvalidation();
1295         }
1296         if (heightChanged) {
1297             if (style->height().isFixed() && (style->top().isAuto() || style->bottom().isAuto()))
1298                 renderer->setNeedsPositionedMovementLayout();
1299             else
1300                 renderer->setNeedsLayoutAndFullPaintInvalidation();
1301         }
1302     }
1303 }
1304
1305 IntSize FrameView::scrollOffsetForFixedPosition() const
1306 {
1307     return toIntSize(clampScrollPosition(scrollPosition()));
1308 }
1309
1310 IntPoint FrameView::lastKnownMousePosition() const
1311 {
1312     return m_frame->eventHandler().lastKnownMousePosition();
1313 }
1314
1315 bool FrameView::shouldSetCursor() const
1316 {
1317     Page* page = frame().page();
1318     return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive() && page->settings().deviceSupportsMouse();
1319 }
1320
1321 void FrameView::scrollContentsIfNeededRecursive()
1322 {
1323     scrollContentsIfNeeded();
1324
1325     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
1326         if (!child->isLocalFrame())
1327             continue;
1328         if (FrameView* view = toLocalFrame(child)->view())
1329             view->scrollContentsIfNeededRecursive();
1330     }
1331 }
1332
1333 // FIXME: If we had a flag to force invalidations in a whole subtree, we could get rid of this function (crbug.com/410097).
1334 static void setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(const RenderLayer* layer)
1335 {
1336     layer->renderer()->setShouldDoFullPaintInvalidation();
1337
1338     for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) {
1339         // Don't include paint invalidation rects for composited child layers; they will paint themselves and have a different origin.
1340         if (child->isPaintInvalidationContainer())
1341             continue;
1342
1343         setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(child);
1344     }
1345 }
1346
1347 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta)
1348 {
1349     if (!contentsInCompositedLayer() || hasSlowRepaintObjects())
1350         return false;
1351
1352     if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1353         InspectorInstrumentation::didScroll(page());
1354         return true;
1355     }
1356
1357     for (const auto& viewportConstrainedObject : *m_viewportConstrainedObjects) {
1358         RenderObject* renderer = viewportConstrainedObject;
1359         ASSERT(renderer->style()->hasViewportConstrainedPosition());
1360         ASSERT(renderer->hasLayer());
1361         RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1362
1363         if (layer->isPaintInvalidationContainer())
1364             continue;
1365
1366         if (layer->subtreeIsInvisible())
1367             continue;
1368
1369         // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1370         // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1371         if (layer->hasAncestorWithFilterOutsets())
1372             return false;
1373
1374         setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(layer);
1375     }
1376
1377     InspectorInstrumentation::didScroll(page());
1378     return true;
1379 }
1380
1381 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1382 {
1383     if (contentsInCompositedLayer()) {
1384         IntRect updateRect = visibleContentRect();
1385         ASSERT(renderView());
1386         renderView()->invalidatePaintRectangle(updateRect);
1387     }
1388     if (RenderPart* frameRenderer = m_frame->ownerRenderer()) {
1389         if (isEnclosedInCompositingLayer()) {
1390             LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1391                             frameRenderer->borderTop() + frameRenderer->paddingTop(),
1392                             visibleWidth(), visibleHeight());
1393             frameRenderer->invalidatePaintRectangle(rect);
1394             return;
1395         }
1396     }
1397
1398     hostWindow()->invalidateContentsForSlowScroll(updateRect);
1399 }
1400
1401 void FrameView::restoreScrollbar()
1402 {
1403     setScrollbarsSuppressed(false);
1404 }
1405
1406 bool FrameView::scrollToFragment(const KURL& url)
1407 {
1408     // If our URL has no ref, then we have no place we need to jump to.
1409     // OTOH If CSS target was set previously, we want to set it to 0, recalc
1410     // and possibly paint invalidation because :target pseudo class may have been
1411     // set (see bug 11321).
1412     if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget())
1413         return false;
1414
1415     String fragmentIdentifier = url.fragmentIdentifier();
1416     if (scrollToAnchor(fragmentIdentifier))
1417         return true;
1418
1419     // Try again after decoding the ref, based on the document's encoding.
1420     if (m_frame->document()->encoding().isValid())
1421         return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding()));
1422
1423     return false;
1424 }
1425
1426 bool FrameView::scrollToAnchor(const String& name)
1427 {
1428     ASSERT(m_frame->document());
1429
1430     if (!m_frame->document()->isRenderingReady()) {
1431         m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1432         return false;
1433     }
1434
1435     m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1436
1437     Element* anchorNode = m_frame->document()->findAnchor(name);
1438
1439     // Setting to null will clear the current target.
1440     m_frame->document()->setCSSTarget(anchorNode);
1441
1442     if (m_frame->document()->isSVGDocument()) {
1443         if (SVGSVGElement* svg = SVGDocumentExtensions::rootElement(*m_frame->document())) {
1444             svg->setupInitialView(name, anchorNode);
1445             if (!anchorNode)
1446                 return true;
1447         }
1448     }
1449
1450     // Implement the rule that "" and "top" both mean top of page as in other browsers.
1451     if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1452         return false;
1453
1454     maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
1455
1456     // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1457     // If anchorNode is not focusable, setFocusedElement() will still clear focus, which matches the behavior of other browsers.
1458     if (anchorNode)
1459         m_frame->document()->setFocusedElement(anchorNode);
1460
1461     return true;
1462 }
1463
1464 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1465 {
1466     m_maintainScrollPositionAnchor = anchorNode;
1467     if (!m_maintainScrollPositionAnchor)
1468         return;
1469
1470     // We need to update the layout before scrolling, otherwise we could
1471     // really mess things up if an anchor scroll comes at a bad moment.
1472     m_frame->document()->updateRenderTreeIfNeeded();
1473     // Only do a layout if changes have occurred that make it necessary.
1474     RenderView* renderView = this->renderView();
1475     if (renderView && renderView->needsLayout())
1476         layout();
1477     else
1478         scrollToAnchor();
1479 }
1480
1481 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1482 {
1483     // FIXME(http://crbug.com/371896) - This method shouldn't be manually doing
1484     // coordinate transformations to the PinchViewport.
1485     IntRect targetRect(rect);
1486
1487     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1488
1489     bool pinchVirtualViewportEnabled = m_frame->settings()->pinchVirtualViewportEnabled();
1490
1491     if (pinchVirtualViewportEnabled) {
1492         PinchViewport& pinchViewport = m_frame->page()->frameHost().pinchViewport();
1493
1494         IntSize pinchViewportSize = expandedIntSize(pinchViewport.visibleRect().size());
1495         targetRect.moveBy(ceiledIntPoint(pinchViewport.visibleRect().location()));
1496         targetRect.setSize(pinchViewportSize.shrunkTo(targetRect.size()));
1497     }
1498
1499     LayoutRect bounds = element->boundingBox();
1500     int centeringOffsetX = (targetRect.width() - bounds.width()) / 2;
1501     int centeringOffsetY = (targetRect.height() - bounds.height()) / 2;
1502
1503     IntPoint targetOffset(
1504         bounds.x() - centeringOffsetX - targetRect.x(),
1505         bounds.y() - centeringOffsetY - targetRect.y());
1506
1507     setScrollPosition(DoublePoint(targetOffset));
1508
1509     if (pinchVirtualViewportEnabled) {
1510         IntPoint remainder = IntPoint(targetOffset - scrollPosition());
1511         m_frame->page()->frameHost().pinchViewport().move(remainder);
1512     }
1513 }
1514
1515 void FrameView::setScrollPosition(const DoublePoint& scrollPoint, ScrollBehavior scrollBehavior)
1516 {
1517     cancelProgrammaticScrollAnimation();
1518     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1519     m_maintainScrollPositionAnchor = nullptr;
1520
1521     DoublePoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1522     if (newScrollPosition == scrollPositionDouble())
1523         return;
1524
1525     if (scrollBehavior == ScrollBehaviorAuto) {
1526         RenderObject* renderer = m_frame->document()->documentElement() ? m_frame->document()->documentElement()->renderer() : 0;
1527         if (renderer)
1528             scrollBehavior = renderer->style()->scrollBehavior();
1529         else
1530             scrollBehavior = ScrollBehaviorInstant;
1531     }
1532
1533     if (scrollBehavior == ScrollBehaviorInstant) {
1534         DoubleSize newOffset(newScrollPosition.x(), newScrollPosition.y());
1535         updateScrollbars(newOffset);
1536     } else {
1537         programmaticallyScrollSmoothlyToOffset(toFloatPoint(newScrollPosition));
1538     }
1539 }
1540
1541 void FrameView::setScrollPositionNonProgrammatically(const IntPoint& scrollPoint)
1542 {
1543     IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1544
1545     if (newScrollPosition == scrollPosition())
1546         return;
1547
1548     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, false);
1549     notifyScrollPositionChanged(newScrollPosition);
1550 }
1551
1552 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const
1553 {
1554     return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize;
1555 }
1556
1557 void FrameView::setLayoutSize(const IntSize& size)
1558 {
1559     ASSERT(!layoutSizeFixedToFrameSize());
1560
1561     setLayoutSizeInternal(size);
1562 }
1563
1564 void FrameView::scrollPositionChanged()
1565 {
1566     setWasScrolledByUser(true);
1567
1568     Document* document = m_frame->document();
1569     document->enqueueScrollEventForNode(document);
1570
1571     m_frame->eventHandler().dispatchFakeMouseMoveEventSoon();
1572
1573     if (RenderView* renderView = document->renderView()) {
1574         if (renderView->usesCompositing())
1575             renderView->compositor()->frameViewDidScroll();
1576     }
1577
1578     if (m_didScrollTimer.isActive())
1579         m_didScrollTimer.stop();
1580     m_didScrollTimer.startOneShot(resourcePriorityUpdateDelayAfterScroll, FROM_HERE);
1581
1582     if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1583         cache->handleScrollPositionChanged(this);
1584
1585     frame().loader().saveScrollState();
1586 }
1587
1588 void FrameView::didScrollTimerFired(Timer<FrameView>*)
1589 {
1590     if (m_frame->document() && m_frame->document()->renderView()) {
1591         ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
1592     }
1593 }
1594
1595 void FrameView::updateLayersAndCompositingAfterScrollIfNeeded()
1596 {
1597     // Nothing to do after scrolling if there are no fixed position elements.
1598     if (!hasViewportConstrainedObjects())
1599         return;
1600
1601     RefPtrWillBeRawPtr<FrameView> protect(this);
1602
1603     // If there fixed position elements, scrolling may cause compositing layers to change.
1604     // Update widget and layer positions after scrolling, but only if we're not inside of
1605     // layout.
1606     if (!m_nestedLayoutCount) {
1607         updateWidgetPositions();
1608         if (RenderView* renderView = this->renderView())
1609             renderView->layer()->setNeedsCompositingInputsUpdate();
1610     }
1611 }
1612
1613 bool FrameView::computeCompositedSelectionBounds(LocalFrame& frame, CompositedSelectionBound& start, CompositedSelectionBound& end)
1614 {
1615     const VisibleSelection &selection = frame.selection().selection();
1616     if (!selection.isCaretOrRange())
1617         return false;
1618
1619     VisiblePosition visibleStart(selection.visibleStart());
1620     VisiblePosition visibleEnd(selection.visibleEnd());
1621
1622     RenderedPosition renderedStart(visibleStart);
1623     RenderedPosition renderedEnd(visibleEnd);
1624
1625     renderedStart.positionInGraphicsLayerBacking(start);
1626     if (!start.layer)
1627         return false;
1628
1629     renderedEnd.positionInGraphicsLayerBacking(end);
1630     if (!end.layer)
1631         return false;
1632
1633     if (selection.isCaret()) {
1634         start.type = end.type = CompositedSelectionBound::Caret;
1635         return true;
1636     }
1637
1638     TextDirection startDir = visibleStart.deepEquivalent().primaryDirection();
1639     TextDirection endDir = visibleEnd.deepEquivalent().primaryDirection();
1640     start.type = startDir == RTL ? CompositedSelectionBound::SelectionRight : CompositedSelectionBound::SelectionLeft;
1641     end.type = endDir == RTL ? CompositedSelectionBound::SelectionLeft : CompositedSelectionBound::SelectionRight;
1642     return true;
1643 }
1644
1645 void FrameView::updateCompositedSelectionBoundsIfNeeded()
1646 {
1647     if (!RuntimeEnabledFeatures::compositedSelectionUpdateEnabled())
1648         return;
1649
1650     Page* page = frame().page();
1651     ASSERT(page);
1652
1653     CompositedSelectionBound start, end;
1654     LocalFrame* frame = toLocalFrame(page->focusController().focusedOrMainFrame());
1655     if (!frame || !computeCompositedSelectionBounds(*frame, start, end)) {
1656         page->chrome().client().clearCompositedSelectionBounds();
1657         return;
1658     }
1659
1660     page->chrome().client().updateCompositedSelectionBounds(start, end);
1661 }
1662
1663 bool FrameView::isRubberBandInProgress() const
1664 {
1665     if (scrollbarsSuppressed())
1666         return false;
1667
1668     // If the main thread updates the scroll position for this FrameView, we should return
1669     // ScrollAnimator::isRubberBandInProgress().
1670     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1671         return scrollAnimator->isRubberBandInProgress();
1672
1673     return false;
1674 }
1675
1676 HostWindow* FrameView::hostWindow() const
1677 {
1678     Page* page = frame().page();
1679     if (!page)
1680         return 0;
1681     return &page->chrome();
1682 }
1683
1684 void FrameView::contentRectangleForPaintInvalidation(const IntRect& rect)
1685 {
1686     ASSERT(paintInvalidationIsAllowed());
1687     ASSERT(!m_frame->ownerRenderer());
1688
1689     if (m_isTrackingPaintInvalidations) {
1690         IntRect paintInvalidationRect = rect;
1691         paintInvalidationRect.move(-scrollOffset());
1692         m_trackedPaintInvalidationRects.append(paintInvalidationRect);
1693         // FIXME: http://crbug.com/368518. Eventually, invalidateContentRectangleForPaint
1694         // is going away entirely once all layout tests are FCM. In the short
1695         // term, no code should be tracking non-composited FrameView paint invalidations.
1696         RELEASE_ASSERT_NOT_REACHED();
1697     }
1698
1699     IntRect paintRect = rect;
1700     if (clipsPaintInvalidations())
1701         paintRect.intersect(visibleContentRect());
1702     if (paintRect.isEmpty())
1703         return;
1704
1705     if (HostWindow* window = hostWindow())
1706         window->invalidateContentsAndRootView(contentsToWindow(paintRect));
1707 }
1708
1709 void FrameView::contentsResized()
1710 {
1711     if (m_frame->isMainFrame() && m_frame->document()) {
1712         if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer())
1713             textAutosizer->updatePageInfoInAllFrames();
1714     }
1715
1716     ScrollableArea::contentsResized();
1717     setNeedsLayout();
1718 }
1719
1720 void FrameView::scrollbarExistenceDidChange()
1721 {
1722     // We check to make sure the view is attached to a frame() as this method can
1723     // be triggered before the view is attached by LocalFrame::createView(...) setting
1724     // various values such as setScrollBarModes(...) for example.  An ASSERT is
1725     // triggered when a view is layout before being attached to a frame().
1726     if (!frame().view())
1727         return;
1728
1729     // Note that simply having overlay scrollbars is not sufficient to be
1730     // certain that scrollbars' presence does not impact layout. This should
1731     // also check if custom scrollbars (as reported by shouldUseCustomScrollbars)
1732     // are in use as well.
1733     // http://crbug.com/269692
1734     bool useOverlayScrollbars = ScrollbarTheme::theme()->usesOverlayScrollbars();
1735
1736     // FIXME: this call to layout() could be called within FrameView::layout(), but before performLayout(),
1737     // causing double-layout. See also crbug.com/429242.
1738     if (!useOverlayScrollbars && needsLayout())
1739         layout();
1740
1741     if (renderView() && renderView()->usesCompositing()) {
1742         renderView()->compositor()->frameViewScrollbarsExistenceDidChange();
1743
1744         if (!useOverlayScrollbars)
1745             renderView()->compositor()->frameViewDidChangeSize();
1746     }
1747 }
1748
1749 void FrameView::handleLoadCompleted()
1750 {
1751     // Once loading has completed, allow autoSize one last opportunity to
1752     // reduce the size of the frame.
1753     if (m_autoSizeInfo)
1754         m_autoSizeInfo->autoSizeIfNeeded();
1755 }
1756
1757 void FrameView::scheduleRelayout()
1758 {
1759     ASSERT(m_frame->view() == this);
1760
1761     if (isSubtreeLayout()) {
1762         m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1763         m_layoutSubtreeRoot = 0;
1764     }
1765     if (!m_layoutSchedulingEnabled)
1766         return;
1767     if (!needsLayout())
1768         return;
1769     if (!m_frame->document()->shouldScheduleLayout())
1770         return;
1771     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get());
1772     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
1773     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1774     InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1775
1776     if (m_hasPendingLayout)
1777         return;
1778     m_hasPendingLayout = true;
1779
1780     page()->animator().scheduleVisualUpdate();
1781     lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1782 }
1783
1784 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
1785 {
1786     for (RenderObject* r = descendant; r; r = r->container()) {
1787         if (r == ancestor)
1788             return true;
1789     }
1790     return false;
1791 }
1792
1793 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
1794 {
1795     ASSERT(m_frame->view() == this);
1796
1797     // FIXME: Should this call shouldScheduleLayout instead?
1798     if (!m_frame->document()->isActive())
1799         return;
1800
1801     RenderView* renderView = this->renderView();
1802     if (renderView && renderView->needsLayout()) {
1803         if (relayoutRoot)
1804             relayoutRoot->markContainingBlocksForLayout(false);
1805         return;
1806     }
1807
1808     if (layoutPending() || !m_layoutSchedulingEnabled) {
1809         if (m_layoutSubtreeRoot != relayoutRoot) {
1810             if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) {
1811                 // Keep the current root
1812                 relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot);
1813                 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1814             } else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) {
1815                 // Re-root at relayoutRoot
1816                 m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot);
1817                 m_layoutSubtreeRoot = relayoutRoot;
1818                 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1819             } else {
1820                 // Just do a full relayout
1821                 if (isSubtreeLayout())
1822                     m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1823                 m_layoutSubtreeRoot = 0;
1824                 relayoutRoot->markContainingBlocksForLayout(false);
1825             }
1826         }
1827     } else if (m_layoutSchedulingEnabled) {
1828         m_layoutSubtreeRoot = relayoutRoot;
1829         ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1830         m_hasPendingLayout = true;
1831
1832         page()->animator().scheduleVisualUpdate();
1833         lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1834     }
1835     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get());
1836     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
1837     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1838     InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1839 }
1840
1841 bool FrameView::layoutPending() const
1842 {
1843     // FIXME: This should check Document::lifecycle instead.
1844     return m_hasPendingLayout;
1845 }
1846
1847 bool FrameView::isInPerformLayout() const
1848 {
1849     ASSERT(m_inPerformLayout == (lifecycle().state() == DocumentLifecycle::InPerformLayout));
1850     return m_inPerformLayout;
1851 }
1852
1853 bool FrameView::needsLayout() const
1854 {
1855     // This can return true in cases where the document does not have a body yet.
1856     // Document::shouldScheduleLayout takes care of preventing us from scheduling
1857     // layout in that case.
1858
1859     RenderView* renderView = this->renderView();
1860     return layoutPending()
1861         || (renderView && renderView->needsLayout())
1862         || isSubtreeLayout();
1863 }
1864
1865 void FrameView::setNeedsLayout()
1866 {
1867     if (RenderView* renderView = this->renderView())
1868         renderView->setNeedsLayout();
1869 }
1870
1871 bool FrameView::isTransparent() const
1872 {
1873     return m_isTransparent;
1874 }
1875
1876 void FrameView::setTransparent(bool isTransparent)
1877 {
1878     m_isTransparent = isTransparent;
1879     DisableCompositingQueryAsserts disabler;
1880     if (renderView() && renderView()->layer()->hasCompositedLayerMapping())
1881         renderView()->layer()->compositedLayerMapping()->updateContentsOpaque();
1882 }
1883
1884 bool FrameView::hasOpaqueBackground() const
1885 {
1886     return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
1887 }
1888
1889 Color FrameView::baseBackgroundColor() const
1890 {
1891     return m_baseBackgroundColor;
1892 }
1893
1894 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
1895 {
1896     m_baseBackgroundColor = backgroundColor;
1897
1898     if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) {
1899         CompositedLayerMapping* compositedLayerMapping = renderView()->layer()->compositedLayerMapping();
1900         compositedLayerMapping->updateContentsOpaque();
1901         if (compositedLayerMapping->mainGraphicsLayer())
1902             compositedLayerMapping->mainGraphicsLayer()->setNeedsDisplay();
1903     }
1904     recalculateScrollbarOverlayStyle();
1905 }
1906
1907 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
1908 {
1909     for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1910         if (!frame->isLocalFrame())
1911             continue;
1912         if (FrameView* view = toLocalFrame(frame)->view()) {
1913             view->setTransparent(transparent);
1914             view->setBaseBackgroundColor(backgroundColor);
1915         }
1916     }
1917 }
1918
1919 void FrameView::scrollToAnchor()
1920 {
1921     RefPtrWillBeRawPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
1922     if (!anchorNode)
1923         return;
1924
1925     if (!anchorNode->renderer())
1926         return;
1927
1928     LayoutRect rect;
1929     if (anchorNode != m_frame->document())
1930         rect = anchorNode->boundingBox();
1931
1932     RefPtrWillBeRawPtr<LocalFrame> boundaryFrame = m_frame->document()->findUnsafeParentScrollPropagationBoundary();
1933
1934     if (boundaryFrame)
1935         boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
1936
1937     // Scroll nested layers and frames to reveal the anchor.
1938     // Align to the top and to the closest side (this matches other browsers).
1939     anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1940
1941     if (boundaryFrame)
1942         boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
1943
1944     if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1945         cache->handleScrolledToAnchor(anchorNode.get());
1946
1947     // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
1948     m_maintainScrollPositionAnchor = anchorNode;
1949 }
1950
1951 bool FrameView::updateWidgets()
1952 {
1953     // This is always called from updateWidgetsTimerFired.
1954     // m_updateWidgetsTimer should only be scheduled if we have widgets to update.
1955     // Thus I believe we can stop checking isEmpty here, and just ASSERT isEmpty:
1956     // FIXME: This assert has been temporarily removed due to https://crbug.com/430344
1957     if (m_nestedLayoutCount > 1 || m_partUpdateSet.isEmpty())
1958         return true;
1959
1960     // Need to swap because script will run inside the below loop and invalidate the iterator.
1961     EmbeddedObjectSet objects;
1962     objects.swap(m_partUpdateSet);
1963
1964     for (const auto& embeddedObject : objects) {
1965         RenderEmbeddedObject& object = *embeddedObject;
1966         HTMLPlugInElement* element = toHTMLPlugInElement(object.node());
1967
1968         // The object may have already been destroyed (thus node cleared),
1969         // but FrameView holds a manual ref, so it won't have been deleted.
1970         if (!element)
1971             continue;
1972
1973         // No need to update if it's already crashed or known to be missing.
1974         if (object.showsUnavailablePluginIndicator())
1975             continue;
1976
1977         if (element->needsWidgetUpdate())
1978             element->updateWidget();
1979         object.updateWidgetPosition();
1980
1981         // Prevent plugins from causing infinite updates of themselves.
1982         // FIXME: Do we really need to prevent this?
1983         m_partUpdateSet.remove(&object);
1984     }
1985
1986     return m_partUpdateSet.isEmpty();
1987 }
1988
1989 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*)
1990 {
1991     ASSERT(!isInPerformLayout());
1992     RefPtrWillBeRawPtr<FrameView> protect(this);
1993     m_updateWidgetsTimer.stop();
1994     for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) {
1995         if (updateWidgets())
1996             return;
1997     }
1998 }
1999
2000 void FrameView::flushAnyPendingPostLayoutTasks()
2001 {
2002     ASSERT(!isInPerformLayout());
2003     if (m_postLayoutTasksTimer.isActive())
2004         performPostLayoutTasks();
2005     if (m_updateWidgetsTimer.isActive())
2006         updateWidgetsTimerFired(0);
2007 }
2008
2009 void FrameView::scheduleUpdateWidgetsIfNecessary()
2010 {
2011     ASSERT(!isInPerformLayout());
2012     if (m_updateWidgetsTimer.isActive() || m_partUpdateSet.isEmpty())
2013         return;
2014     m_updateWidgetsTimer.startOneShot(0, FROM_HERE);
2015 }
2016
2017 void FrameView::performPostLayoutTasks()
2018 {
2019     // FIXME: We can reach here, even when the page is not active!
2020     // http/tests/inspector/elements/html-link-import.html and many other
2021     // tests hit that case.
2022     // We should ASSERT(isActive()); or at least return early if we can!
2023     ASSERT(!isInPerformLayout()); // Always before or after performLayout(), part of the highest-level layout() call.
2024     TRACE_EVENT0("blink", "FrameView::performPostLayoutTasks");
2025     RefPtrWillBeRawPtr<FrameView> protect(this);
2026
2027     m_postLayoutTasksTimer.stop();
2028
2029     m_frame->selection().setCaretRectNeedsUpdate();
2030
2031     {
2032         // Hits in compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html
2033         DisableCompositingQueryAsserts disabler;
2034         m_frame->selection().updateAppearance();
2035     }
2036
2037     ASSERT(m_frame->document());
2038     if (m_nestedLayoutCount <= 1) {
2039         if (m_firstLayoutCallbackPending)
2040             m_firstLayoutCallbackPending = false;
2041
2042         // Ensure that we always send this eventually.
2043         if (!m_frame->document()->parsing() && m_frame->loader().stateMachine()->committedFirstRealDocumentLoad())
2044             m_isVisuallyNonEmpty = true;
2045
2046         // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
2047         if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
2048             m_firstVisuallyNonEmptyLayoutCallbackPending = false;
2049             // FIXME: This callback is probably not needed, but is currently used
2050             // by android for setting the background color.
2051             m_frame->loader().client()->dispatchDidFirstVisuallyNonEmptyLayout();
2052         }
2053     }
2054
2055     FontFaceSet::didLayout(*m_frame->document());
2056
2057     updateWidgetPositions();
2058
2059     // Plugins could have torn down the page inside updateWidgetPositions().
2060     if (!renderView())
2061         return;
2062
2063     scheduleUpdateWidgetsIfNecessary();
2064
2065     if (Page* page = m_frame->page()) {
2066         if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2067             scrollingCoordinator->notifyLayoutUpdated();
2068     }
2069
2070     scrollToAnchor();
2071
2072     sendResizeEventIfNeeded();
2073 }
2074
2075 bool FrameView::wasViewportResized()
2076 {
2077     ASSERT(m_frame);
2078     RenderView* renderView = this->renderView();
2079     if (!renderView)
2080         return false;
2081     ASSERT(renderView->style());
2082     return (layoutSize(IncludeScrollbars) != m_lastViewportSize || renderView->style()->zoom() != m_lastZoomFactor);
2083 }
2084
2085 void FrameView::sendResizeEventIfNeeded()
2086 {
2087     ASSERT(m_frame);
2088
2089     RenderView* renderView = this->renderView();
2090     if (!renderView || renderView->document().printing())
2091         return;
2092
2093     if (!wasViewportResized())
2094         return;
2095
2096     m_lastViewportSize = layoutSize(IncludeScrollbars);
2097     m_lastZoomFactor = renderView->style()->zoom();
2098
2099     m_frame->document()->enqueueResizeEvent();
2100
2101     if (m_frame->isMainFrame())
2102         InspectorInstrumentation::didResizeMainFrame(m_frame->page());
2103 }
2104
2105 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
2106 {
2107     performPostLayoutTasks();
2108 }
2109
2110 void FrameView::updateCounters()
2111 {
2112     RenderView* view = renderView();
2113     if (!view->hasRenderCounters())
2114         return;
2115
2116     for (RenderObject* renderer = view; renderer; renderer = renderer->nextInPreOrder()) {
2117         if (!renderer->isCounter())
2118             continue;
2119
2120         toRenderCounter(renderer)->updateCounter();
2121     }
2122 }
2123
2124 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2125 {
2126     if (!m_viewportRenderer)
2127         return;
2128
2129     if (m_overflowStatusDirty) {
2130         m_horizontalOverflow = horizontalOverflow;
2131         m_verticalOverflow = verticalOverflow;
2132         m_overflowStatusDirty = false;
2133         return;
2134     }
2135
2136     bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2137     bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2138
2139     if (horizontalOverflowChanged || verticalOverflowChanged) {
2140         m_horizontalOverflow = horizontalOverflow;
2141         m_verticalOverflow = verticalOverflow;
2142
2143         RefPtrWillBeRawPtr<OverflowEvent> event = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow);
2144         event->setTarget(m_viewportRenderer->node());
2145         m_frame->document()->enqueueAnimationFrameEvent(event.release());
2146     }
2147
2148 }
2149
2150 IntRect FrameView::windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const
2151 {
2152     ASSERT(m_frame->view() == this);
2153
2154     // Set our clip rect to be our contents.
2155     IntRect clipRect = contentsToWindow(visibleContentRect(scrollbarInclusion));
2156     if (!m_frame->deprecatedLocalOwner())
2157         return clipRect;
2158
2159     // Take our owner element and get its clip rect.
2160     // FIXME: Do we need to do this for remote frames?
2161     HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
2162     FrameView* parentView = ownerElement->document().view();
2163     if (parentView)
2164         clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement));
2165     return clipRect;
2166 }
2167
2168 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement) const
2169 {
2170     // The renderer can sometimes be null when style="display:none" interacts
2171     // with external content and plugins.
2172     if (!ownerElement->renderer())
2173         return windowClipRect();
2174
2175     // If we have no layer, just return our window clip rect.
2176     const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
2177     if (!enclosingLayer)
2178         return windowClipRect();
2179
2180     // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date.
2181     // https://code.google.com/p/chromium/issues/detail?id=343769
2182     DisableCompositingQueryAsserts disabler;
2183
2184     // Apply the clip from the layer.
2185     IntRect clipRect = contentsToWindow(pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect()));
2186     return intersection(clipRect, windowClipRect());
2187 }
2188
2189 bool FrameView::isActive() const
2190 {
2191     Page* page = frame().page();
2192     return page && page->focusController().isActive();
2193 }
2194
2195 void FrameView::scrollTo(const DoublePoint& newPosition)
2196 {
2197     DoublePoint oldPosition = m_scrollPosition;
2198     DoubleSize scrollDelta = newPosition - oldPosition;
2199     if (scrollDelta.isZero())
2200         return;
2201
2202     if (m_frame->settings() && m_frame->settings()->rootLayerScrolls()) {
2203         // Don't scroll the FrameView!
2204         ASSERT_NOT_REACHED();
2205     }
2206
2207     m_scrollPosition = newPosition;
2208
2209     if (!scrollbarsSuppressed())
2210         m_pendingScrollDelta += scrollDelta;
2211
2212     updateLayersAndCompositingAfterScrollIfNeeded();
2213     scrollPositionChanged();
2214     frame().loader().client()->didChangeScrollOffset();
2215 }
2216
2217 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2218 {
2219     // Add in our offset within the FrameView.
2220     IntRect dirtyRect = rect;
2221     dirtyRect.moveBy(scrollbar->location());
2222
2223     if (isInPerformLayout())
2224         addScrollbarDamage(scrollbar, rect);
2225     else
2226         invalidateRect(dirtyRect);
2227 }
2228
2229 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
2230 {
2231     if (!m_tickmarks.isEmpty())
2232         tickmarks = m_tickmarks;
2233     else
2234         tickmarks = frame().document()->markers().renderedRectsForMarkers(DocumentMarker::TextMatch);
2235 }
2236
2237 IntRect FrameView::windowResizerRect() const
2238 {
2239     Page* page = frame().page();
2240     if (!page)
2241         return IntRect();
2242     return page->chrome().windowResizerRect();
2243 }
2244
2245 void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor)
2246 {
2247     if (m_visibleContentScaleFactor == visibleContentScaleFactor)
2248         return;
2249
2250     m_visibleContentScaleFactor = visibleContentScaleFactor;
2251     updateScrollbars(scrollOffsetDouble());
2252 }
2253
2254 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor)
2255 {
2256     m_inputEventsOffsetForEmulation = offset;
2257     m_inputEventsScaleFactorForEmulation = contentScaleFactor;
2258 }
2259
2260 IntSize FrameView::inputEventsOffsetForEmulation() const
2261 {
2262     return m_inputEventsOffsetForEmulation;
2263 }
2264
2265 float FrameView::inputEventsScaleFactor() const
2266 {
2267     float pageScale = m_frame->settings()->pinchVirtualViewportEnabled()
2268         ? m_frame->page()->frameHost().pinchViewport().scale()
2269         : visibleContentScaleFactor();
2270     return pageScale * m_inputEventsScaleFactorForEmulation;
2271 }
2272
2273 bool FrameView::scrollbarsCanBeActive() const
2274 {
2275     if (m_frame->view() != this)
2276         return false;
2277
2278     return !!m_frame->document();
2279 }
2280
2281 IntRect FrameView::scrollableAreaBoundingBox() const
2282 {
2283     RenderPart* ownerRenderer = frame().ownerRenderer();
2284     if (!ownerRenderer)
2285         return frameRect();
2286
2287     return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
2288 }
2289
2290
2291 bool FrameView::isScrollable()
2292 {
2293     return scrollingReasons() == Scrollable;
2294 }
2295
2296 FrameView::ScrollingReasons FrameView::scrollingReasons()
2297 {
2298     // Check for:
2299     // 1) If there an actual overflow.
2300     // 2) display:none or visibility:hidden set to self or inherited.
2301     // 3) overflow{-x,-y}: hidden;
2302     // 4) scrolling: no;
2303
2304     // Covers #1
2305     IntSize contentsSize = this->contentsSize();
2306     IntSize visibleContentSize = visibleContentRect().size();
2307     if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width()))
2308         return NotScrollableNoOverflow;
2309
2310     // Covers #2.
2311     // FIXME: Do we need to fix this for OOPI?
2312     HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
2313     if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
2314         return NotScrollableNotVisible;
2315
2316     // Cover #3 and #4.
2317     ScrollbarMode horizontalMode;
2318     ScrollbarMode verticalMode;
2319     calculateScrollbarModesForLayoutAndSetViewportRenderer(horizontalMode, verticalMode, RulesFromWebContentOnly);
2320     if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
2321         return NotScrollableExplicitlyDisabled;
2322
2323     return Scrollable;
2324 }
2325
2326 void FrameView::updateScrollableAreaSet()
2327 {
2328     // That ensures that only inner frames are cached.
2329     FrameView* parentFrameView = this->parentFrameView();
2330     if (!parentFrameView)
2331         return;
2332
2333     if (!isScrollable()) {
2334         parentFrameView->removeScrollableArea(this);
2335         return;
2336     }
2337
2338     parentFrameView->addScrollableArea(this);
2339 }
2340
2341 bool FrameView::shouldSuspendScrollAnimations() const
2342 {
2343     return m_frame->loader().state() != FrameStateComplete;
2344 }
2345
2346 void FrameView::scrollbarStyleChanged()
2347 {
2348     // FIXME: Why does this only apply to the main frame?
2349     if (!m_frame->isMainFrame())
2350         return;
2351     adjustScrollbarOpacity();
2352     contentsResized();
2353     updateScrollbars(scrollOffsetDouble());
2354     positionScrollbarLayers();
2355 }
2356
2357 void FrameView::notifyPageThatContentAreaWillPaint() const
2358 {
2359     Page* page = m_frame->page();
2360     if (!page)
2361         return;
2362
2363     contentAreaWillPaint();
2364
2365     if (!m_scrollableAreas)
2366         return;
2367
2368     for (const auto& scrollableArea : *m_scrollableAreas) {
2369         if (!scrollableArea->scrollbarsCanBeActive())
2370             continue;
2371
2372         scrollableArea->contentAreaWillPaint();
2373     }
2374 }
2375
2376 bool FrameView::scrollAnimatorEnabled() const
2377 {
2378     return m_frame->settings() && m_frame->settings()->scrollAnimatorEnabled();
2379 }
2380
2381 void FrameView::updateAnnotatedRegions()
2382 {
2383     Document* document = m_frame->document();
2384     if (!document->hasAnnotatedRegions())
2385         return;
2386     Vector<AnnotatedRegionValue> newRegions;
2387     document->renderBox()->collectAnnotatedRegions(newRegions);
2388     if (newRegions == document->annotatedRegions())
2389         return;
2390     document->setAnnotatedRegions(newRegions);
2391     if (Page* page = m_frame->page())
2392         page->chrome().client().annotatedRegionsChanged();
2393 }
2394
2395 void FrameView::updateScrollCorner()
2396 {
2397     RefPtr<RenderStyle> cornerStyle;
2398     IntRect cornerRect = scrollCornerRect();
2399     Document* doc = m_frame->document();
2400
2401     if (doc && !cornerRect.isEmpty()) {
2402         // Try the <body> element first as a scroll corner source.
2403         if (Element* body = doc->body()) {
2404             if (RenderObject* renderer = body->renderer())
2405                 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2406         }
2407
2408         if (!cornerStyle) {
2409             // If the <body> didn't have a custom style, then the root element might.
2410             if (Element* docElement = doc->documentElement()) {
2411                 if (RenderObject* renderer = docElement->renderer())
2412                     cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2413             }
2414         }
2415
2416         if (!cornerStyle) {
2417             // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
2418             if (RenderPart* renderer = m_frame->ownerRenderer())
2419                 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2420         }
2421     }
2422
2423     if (cornerStyle) {
2424         if (!m_scrollCorner)
2425             m_scrollCorner = RenderScrollbarPart::createAnonymous(doc);
2426         m_scrollCorner->setStyle(cornerStyle.release());
2427         invalidateScrollCorner(cornerRect);
2428     } else if (m_scrollCorner) {
2429         m_scrollCorner->destroy();
2430         m_scrollCorner = nullptr;
2431     }
2432 }
2433
2434 Color FrameView::documentBackgroundColor() const
2435 {
2436     // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
2437     // the document and the body against the base background color of the frame view.
2438     // Background images are unfortunately impractical to include.
2439
2440     Color result = baseBackgroundColor();
2441     if (!frame().document())
2442         return result;
2443
2444     Element* htmlElement = frame().document()->documentElement();
2445     Element* bodyElement = frame().document()->body();
2446
2447     // We take the aggregate of the base background color
2448     // the <html> background color, and the <body>
2449     // background color to find the document color. The
2450     // addition of the base background color is not
2451     // technically part of the document background, but it
2452     // otherwise poses problems when the aggregate is not
2453     // fully opaque.
2454     if (htmlElement && htmlElement->renderer())
2455         result = result.blend(htmlElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2456     if (bodyElement && bodyElement->renderer())
2457         result = result.blend(bodyElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2458
2459     return result;
2460 }
2461
2462 bool FrameView::hasCustomScrollbars() const
2463 {
2464     const ChildrenWidgetSet* viewChildren = children();
2465     for (const RefPtrWillBeMember<Widget>& child : *viewChildren) {
2466         Widget* widget = child.get();
2467         if (widget->isFrameView()) {
2468             if (toFrameView(widget)->hasCustomScrollbars())
2469                 return true;
2470         } else if (widget->isScrollbar()) {
2471             if (toScrollbar(widget)->isCustomScrollbar())
2472                 return true;
2473         }
2474     }
2475
2476     return false;
2477 }
2478
2479 FrameView* FrameView::parentFrameView() const
2480 {
2481     if (!parent())
2482         return 0;
2483
2484     Frame* parentFrame = m_frame->tree().parent();
2485     if (parentFrame && parentFrame->isLocalFrame())
2486         return toLocalFrame(parentFrame)->view();
2487
2488     return 0;
2489 }
2490
2491 bool FrameView::wasScrolledByUser() const
2492 {
2493     return m_wasScrolledByUser;
2494 }
2495
2496 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
2497 {
2498     if (m_inProgrammaticScroll)
2499         return;
2500     m_maintainScrollPositionAnchor = nullptr;
2501     m_wasScrolledByUser = wasScrolledByUser;
2502 }
2503
2504 void FrameView::setPaintBehavior(PaintBehavior behavior)
2505 {
2506     m_paintBehavior = behavior;
2507 }
2508
2509 PaintBehavior FrameView::paintBehavior() const
2510 {
2511     return m_paintBehavior;
2512 }
2513
2514 bool FrameView::isPainting() const
2515 {
2516     return m_isPainting;
2517 }
2518
2519 void FrameView::setNodeToDraw(Node* node)
2520 {
2521     m_nodeToDraw = node;
2522 }
2523
2524 void FrameView::updateWidgetPositionsIfNeeded()
2525 {
2526     if (!m_needsUpdateWidgetPositions)
2527         return;
2528
2529     m_needsUpdateWidgetPositions = false;
2530
2531     updateWidgetPositions();
2532 }
2533
2534 void FrameView::updateLayoutAndStyleForPainting()
2535 {
2536     // Updating layout can run script, which can tear down the FrameView.
2537     RefPtrWillBeRawPtr<FrameView> protector(this);
2538
2539     updateLayoutAndStyleIfNeededRecursive();
2540
2541     updateWidgetPositionsIfNeeded();
2542
2543     RenderView* view = renderView();
2544     if (view) {
2545         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateLayerTree", "frame", m_frame.get());
2546         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
2547         InspectorInstrumentation::willUpdateLayerTree(m_frame.get());
2548
2549         view->compositor()->updateIfNeededRecursive();
2550
2551         if (view->compositor()->inCompositingMode() && m_frame->isLocalRoot())
2552             m_frame->page()->scrollingCoordinator()->updateAfterCompositingChangeIfNeeded();
2553
2554         updateCompositedSelectionBoundsIfNeeded();
2555
2556         InspectorInstrumentation::didUpdateLayerTree(m_frame.get());
2557     }
2558
2559     scrollContentsIfNeededRecursive();
2560
2561     if (view)
2562         invalidateTreeIfNeededRecursive();
2563
2564     ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean);
2565 }
2566
2567 void FrameView::updateLayoutAndStyleIfNeededRecursive()
2568 {
2569     // We have to crawl our entire tree looking for any FrameViews that need
2570     // layout and make sure they are up to date.
2571     // Mac actually tests for intersection with the dirty region and tries not to
2572     // update layout for frames that are outside the dirty region.  Not only does this seem
2573     // pointless (since those frames will have set a zero timer to layout anyway), but
2574     // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
2575     // region but then become included later by the second frame adding rects to the dirty region
2576     // when it lays out.
2577
2578     m_frame->document()->updateRenderTreeIfNeeded();
2579
2580     if (needsLayout())
2581         layout();
2582
2583     // FIXME: Calling layout() shouldn't trigger scripe execution or have any
2584     // observable effects on the frame tree but we're not quite there yet.
2585     WillBeHeapVector<RefPtrWillBeMember<FrameView> > frameViews;
2586     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2587         if (!child->isLocalFrame())
2588             continue;
2589         if (FrameView* view = toLocalFrame(child)->view())
2590             frameViews.append(view);
2591     }
2592
2593     for (const auto& frameView : frameViews)
2594         frameView->updateLayoutAndStyleIfNeededRecursive();
2595
2596     // When an <iframe> gets composited, it triggers an extra style recalc in its containing FrameView.
2597     // To avoid pushing an invalid tree for display, we have to check for this case and do another
2598     // style recalc. The extra style recalc needs to happen after our child <iframes> were updated.
2599     // FIXME: We shouldn't be triggering an extra style recalc in the first place.
2600     if (m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate()) {
2601         m_frame->document()->updateRenderTreeIfNeeded();
2602
2603         if (needsLayout())
2604             layout();
2605     }
2606
2607     // These asserts ensure that parent frames are clean, when child frames finished updating layout and style.
2608     ASSERT(!needsLayout());
2609     ASSERT(!m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate());
2610 #if ENABLE(ASSERT)
2611     m_frame->document()->renderView()->assertRendererLaidOut();
2612 #endif
2613
2614 }
2615
2616 void FrameView::invalidateTreeIfNeededRecursive()
2617 {
2618     // FIXME: We should be more aggressive at cutting tree traversals.
2619     lifecycle().advanceTo(DocumentLifecycle::InPaintInvalidation);
2620     invalidateTreeIfNeeded();
2621     lifecycle().advanceTo(DocumentLifecycle::PaintInvalidationClean);
2622
2623     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2624         if (!child->isLocalFrame())
2625             continue;
2626
2627         toLocalFrame(child)->view()->invalidateTreeIfNeededRecursive();
2628     }
2629
2630     m_doFullPaintInvalidation = false;
2631 }
2632
2633 void FrameView::enableAutoSizeMode(const IntSize& minSize, const IntSize& maxSize)
2634 {
2635     if (!m_autoSizeInfo)
2636         m_autoSizeInfo = FrameViewAutoSizeInfo::create(this);
2637
2638     m_autoSizeInfo->configureAutoSizeMode(minSize, maxSize);
2639     setLayoutSizeFixedToFrameSize(true);
2640     setNeedsLayout();
2641     scheduleRelayout();
2642 }
2643
2644 void FrameView::disposeAutoSizeInfo()
2645 {
2646     if (!m_autoSizeInfo)
2647         return;
2648
2649     setLayoutSizeFixedToFrameSize(false);
2650     setNeedsLayout();
2651     scheduleRelayout();
2652
2653     // Since autosize mode forces the scrollbar mode, change them to being auto.
2654     setVerticalScrollbarLock(false);
2655     setHorizontalScrollbarLock(false);
2656     setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
2657     m_autoSizeInfo.clear();
2658 }
2659
2660 void FrameView::forceLayout(bool allowSubtree)
2661 {
2662     layout(allowSubtree);
2663 }
2664
2665 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor)
2666 {
2667     // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
2668     // the state of things before and after the layout
2669     if (RenderView* renderView = this->renderView()) {
2670         float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
2671         float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
2672
2673         LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2674         LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2675         renderView->setLogicalWidth(flooredPageLogicalWidth);
2676         renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2677         renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
2678         forceLayout();
2679
2680         // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
2681         // page width when shrunk, we will lay out at maximum shrink and clip extra content.
2682         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
2683         // implementation should not do this!
2684         bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode();
2685         const LayoutRect& documentRect = renderView->documentRect();
2686         LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
2687         if (docLogicalWidth > pageLogicalWidth) {
2688             FloatSize expectedPageSize(std::min<float>(documentRect.width().toFloat(), pageSize.width() * maximumShrinkFactor), std::min<float>(documentRect.height().toFloat(), pageSize.height() * maximumShrinkFactor));
2689             FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), expectedPageSize);
2690             pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
2691             pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
2692
2693             flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2694             flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2695             renderView->setLogicalWidth(flooredPageLogicalWidth);
2696             renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2697             renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
2698             forceLayout();
2699
2700             const LayoutRect& updatedDocumentRect = renderView->documentRect();
2701             LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
2702             LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
2703             LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
2704             LayoutUnit clippedLogicalLeft = 0;
2705             if (!renderView->style()->isLeftToRightDirection())
2706                 clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
2707             LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
2708
2709             if (!horizontalWritingMode)
2710                 overflow = overflow.transposedRect();
2711             renderView->clearLayoutOverflow();
2712             renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
2713         }
2714     }
2715
2716     adjustViewSize();
2717 }
2718
2719 IntRect FrameView::convertFromRenderer(const RenderObject& renderer, const IntRect& rendererRect) const
2720 {
2721     IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer.localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
2722
2723     // Convert from page ("absolute") to FrameView coordinates.
2724     rect.moveBy(-scrollPosition());
2725
2726     return rect;
2727 }
2728
2729 IntRect FrameView::convertToRenderer(const RenderObject& renderer, const IntRect& viewRect) const
2730 {
2731     IntRect rect = viewRect;
2732
2733     // Convert from FrameView coords into page ("absolute") coordinates.
2734     rect.moveBy(scrollPosition());
2735
2736     // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
2737     // move the rect for now.
2738     rect.setLocation(roundedIntPoint(renderer.absoluteToLocal(rect.location(), UseTransforms)));
2739     return rect;
2740 }
2741
2742 IntPoint FrameView::convertFromRenderer(const RenderObject& renderer, const IntPoint& rendererPoint) const
2743 {
2744     IntPoint point = roundedIntPoint(renderer.localToAbsolute(rendererPoint, UseTransforms));
2745
2746     // Convert from page ("absolute") to FrameView coordinates.
2747     point.moveBy(-scrollPosition());
2748     return point;
2749 }
2750
2751 IntPoint FrameView::convertToRenderer(const RenderObject& renderer, const IntPoint& viewPoint) const
2752 {
2753     IntPoint point = viewPoint;
2754
2755     // Convert from FrameView coords into page ("absolute") coordinates.
2756     point += IntSize(scrollX(), scrollY());
2757
2758     return roundedIntPoint(renderer.absoluteToLocal(point, UseTransforms));
2759 }
2760
2761 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
2762 {
2763     if (const FrameView* parentView = toFrameView(parent())) {
2764         // Get our renderer in the parent view
2765         RenderPart* renderer = m_frame->ownerRenderer();
2766         if (!renderer)
2767             return localRect;
2768
2769         IntRect rect(localRect);
2770         // Add borders and padding??
2771         rect.move(renderer->borderLeft() + renderer->paddingLeft(),
2772             renderer->borderTop() + renderer->paddingTop());
2773         return parentView->convertFromRenderer(*renderer, rect);
2774     }
2775
2776     return localRect;
2777 }
2778
2779 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
2780 {
2781     if (const FrameView* parentView = toFrameView(parent())) {
2782         // Get our renderer in the parent view
2783         RenderPart* renderer = m_frame->ownerRenderer();
2784         if (!renderer)
2785             return parentRect;
2786
2787         IntRect rect = parentView->convertToRenderer(*renderer, parentRect);
2788         // Subtract borders and padding
2789         rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
2790             -renderer->borderTop() - renderer->paddingTop());
2791         return rect;
2792     }
2793
2794     return parentRect;
2795 }
2796
2797 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
2798 {
2799     if (const FrameView* parentView = toFrameView(parent())) {
2800         // Get our renderer in the parent view
2801         RenderPart* renderer = m_frame->ownerRenderer();
2802         if (!renderer)
2803             return localPoint;
2804
2805         IntPoint point(localPoint);
2806
2807         // Add borders and padding
2808         point.move(renderer->borderLeft() + renderer->paddingLeft(),
2809             renderer->borderTop() + renderer->paddingTop());
2810         return parentView->convertFromRenderer(*renderer, point);
2811     }
2812
2813     return localPoint;
2814 }
2815
2816 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
2817 {
2818     if (const FrameView* parentView = toFrameView(parent())) {
2819         // Get our renderer in the parent view
2820         RenderPart* renderer = m_frame->ownerRenderer();
2821         if (!renderer)
2822             return parentPoint;
2823
2824         IntPoint point = parentView->convertToRenderer(*renderer, parentPoint);
2825         // Subtract borders and padding
2826         point.move(-renderer->borderLeft() - renderer->paddingLeft(),
2827             -renderer->borderTop() - renderer->paddingTop());
2828         return point;
2829     }
2830
2831     return parentPoint;
2832 }
2833
2834 void FrameView::setTracksPaintInvalidations(bool trackPaintInvalidations)
2835 {
2836     if (trackPaintInvalidations == m_isTrackingPaintInvalidations)
2837         return;
2838
2839     for (Frame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) {
2840         if (!frame->isLocalFrame())
2841             continue;
2842         if (RenderView* renderView = toLocalFrame(frame)->contentRenderer())
2843             renderView->compositor()->setTracksPaintInvalidations(trackPaintInvalidations);
2844     }
2845
2846     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"),
2847         "FrameView::setTracksPaintInvalidations", "enabled", trackPaintInvalidations);
2848
2849     resetTrackedPaintInvalidations();
2850     m_isTrackingPaintInvalidations = trackPaintInvalidations;
2851 }
2852
2853 void FrameView::resetTrackedPaintInvalidations()
2854 {
2855     m_trackedPaintInvalidationRects.clear();
2856     if (RenderView* renderView = this->renderView())
2857         renderView->compositor()->resetTrackedPaintInvalidationRects();
2858 }
2859
2860 String FrameView::trackedPaintInvalidationRectsAsText() const
2861 {
2862     TextStream ts;
2863     if (!m_trackedPaintInvalidationRects.isEmpty()) {
2864         ts << "(repaint rects\n";
2865         for (size_t i = 0; i < m_trackedPaintInvalidationRects.size(); ++i)
2866             ts << "  (rect " << m_trackedPaintInvalidationRects[i].x() << " " << m_trackedPaintInvalidationRects[i].y() << " " << m_trackedPaintInvalidationRects[i].width() << " " << m_trackedPaintInvalidationRects[i].height() << ")\n";
2867         ts << ")\n";
2868     }
2869     return ts.release();
2870 }
2871
2872 void FrameView::addResizerArea(RenderBox& resizerBox)
2873 {
2874     if (!m_resizerAreas)
2875         m_resizerAreas = adoptPtr(new ResizerAreaSet);
2876     m_resizerAreas->add(&resizerBox);
2877 }
2878
2879 void FrameView::removeResizerArea(RenderBox& resizerBox)
2880 {
2881     if (!m_resizerAreas)
2882         return;
2883
2884     ResizerAreaSet::iterator it = m_resizerAreas->find(&resizerBox);
2885     if (it != m_resizerAreas->end())
2886         m_resizerAreas->remove(it);
2887 }
2888
2889 void FrameView::addScrollableArea(ScrollableArea* scrollableArea)
2890 {
2891     ASSERT(scrollableArea);
2892     if (!m_scrollableAreas)
2893         m_scrollableAreas = adoptPtr(new ScrollableAreaSet);
2894     m_scrollableAreas->add(scrollableArea);
2895 }
2896
2897 void FrameView::removeScrollableArea(ScrollableArea* scrollableArea)
2898 {
2899     if (!m_scrollableAreas)
2900         return;
2901     m_scrollableAreas->remove(scrollableArea);
2902 }
2903
2904 void FrameView::setParent(Widget* parentView)
2905 {
2906     if (parentView == parent())
2907         return;
2908
2909     if (m_scrollbarsAvoidingResizer && parent())
2910         toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
2911
2912     Widget::setParent(parentView);
2913
2914     if (m_scrollbarsAvoidingResizer && parent())
2915         toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
2916
2917     updateScrollableAreaSet();
2918 }
2919
2920 void FrameView::removeChild(Widget* child)
2921 {
2922     ASSERT(child->parent() == this);
2923
2924     if (child->isFrameView())
2925         removeScrollableArea(toFrameView(child));
2926
2927     child->setParent(0);
2928     m_children.remove(child);
2929 }
2930
2931 bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent)
2932 {
2933     bool allowScrolling = userInputScrollable(HorizontalScrollbar) || userInputScrollable(VerticalScrollbar);
2934
2935     // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views
2936     // should handle wheel events.
2937 #if !USE(RUBBER_BANDING)
2938     if (!isScrollable())
2939         allowScrolling = false;
2940 #endif
2941
2942     if (m_frame->settings()->rootLayerScrolls())
2943         allowScrolling = false;
2944
2945     if (allowScrolling && ScrollableArea::handleWheelEvent(wheelEvent))
2946         return true;
2947
2948     // If the frame didn't handle the event, give the pinch-zoom viewport a chance to
2949     // process the scroll event.
2950     if (m_frame->settings()->pinchVirtualViewportEnabled() && m_frame->isMainFrame())
2951         return page()->frameHost().pinchViewport().handleWheelEvent(wheelEvent);
2952
2953     return false;
2954 }
2955
2956 bool FrameView::isVerticalDocument() const
2957 {
2958     RenderView* renderView = this->renderView();
2959     if (!renderView)
2960         return true;
2961
2962     return renderView->style()->isHorizontalWritingMode();
2963 }
2964
2965 bool FrameView::isFlippedDocument() const
2966 {
2967     RenderView* renderView = this->renderView();
2968     if (!renderView)
2969         return false;
2970
2971     return renderView->hasFlippedBlocksWritingMode();
2972 }
2973
2974 bool FrameView::scrollbarsDisabled() const
2975 {
2976     if (!m_frame->settings() || !m_frame->settings()->pinchVirtualViewportEnabled())
2977         return false;
2978
2979     // FIXME: This decision should be made based on whether or not to use
2980     // viewport scrollbars for the main frame. This is implicitly just Android,
2981     // but should be made explicit.
2982     // http://crbug.com/434533
2983 #if !OS(ANDROID)
2984     return false;
2985 #else
2986     return m_frame->isMainFrame();
2987 #endif
2988 }
2989
2990 AXObjectCache* FrameView::axObjectCache() const
2991 {
2992     if (frame().document())
2993         return frame().document()->existingAXObjectCache();
2994     return 0;
2995 }
2996
2997 void FrameView::setCursor(const Cursor& cursor)
2998 {
2999     Page* page = frame().page();
3000     if (!page || !page->settings().deviceSupportsMouse())
3001         return;
3002     page->chrome().setCursor(cursor);
3003 }
3004
3005 void FrameView::frameRectsChanged()
3006 {
3007     if (layoutSizeFixedToFrameSize())
3008         setLayoutSizeInternal(frameRect().size());
3009
3010     for (const auto& child : m_children)
3011         child->frameRectsChanged();
3012 }
3013
3014 void FrameView::setLayoutSizeInternal(const IntSize& size)
3015 {
3016     if (m_layoutSize == size)
3017         return;
3018
3019     m_layoutSize = size;
3020     contentsResized();
3021 }
3022
3023 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3024 {
3025     ScrollableArea::didAddScrollbar(scrollbar, orientation);
3026     if (AXObjectCache* cache = axObjectCache())
3027         cache->handleScrollbarUpdate(this);
3028 }
3029
3030 void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3031 {
3032     ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
3033     if (AXObjectCache* cache = axObjectCache()) {
3034         cache->remove(scrollbar);
3035         cache->handleScrollbarUpdate(this);
3036     }
3037 }
3038
3039 void FrameView::setTopControlsViewportAdjustment(float adjustment)
3040 {
3041     m_topControlsViewportAdjustment = adjustment;
3042 }
3043
3044 IntPoint FrameView::maximumScrollPosition() const
3045 {
3046     // Make the same calculation as in CC's LayerImpl::MaxScrollOffset()
3047     // FIXME: We probably shouldn't be storing the bounds in a float. crbug.com/422331.
3048     FloatSize visibleSize = unscaledVisibleContentSize(ExcludeScrollbars);
3049     visibleSize.expand(0, m_topControlsViewportAdjustment);
3050
3051     FloatSize contentBounds = contentsSize();
3052     contentBounds.scale(visibleContentScaleFactor());
3053     contentBounds = flooredIntSize(contentBounds);
3054
3055     FloatSize maximumOffset = contentBounds - visibleSize - toIntSize(scrollOrigin());
3056
3057     // Convert back to CSS pixels.
3058     maximumOffset.scale(1 / visibleContentScaleFactor());
3059
3060     IntPoint snappedMaximumOffset = flooredIntPoint(maximumOffset);
3061     snappedMaximumOffset.clampNegativeToZero();
3062     return snappedMaximumOffset;
3063 }
3064
3065 void FrameView::addChild(PassRefPtrWillBeRawPtr<Widget> prpChild)
3066 {
3067     Widget* child = prpChild.get();
3068     ASSERT(child != this && !child->parent());
3069     child->setParent(this);
3070     m_children.add(prpChild);
3071 }
3072
3073 void FrameView::setHasHorizontalScrollbar(bool hasBar)
3074 {
3075     if (hasBar && !m_horizontalScrollbar) {
3076         m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
3077         addChild(m_horizontalScrollbar.get());
3078         didAddScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
3079         m_horizontalScrollbar->styleChanged();
3080     } else if (!hasBar && m_horizontalScrollbar) {
3081         willRemoveScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
3082         // If the scrollbar has been marked as overlapping the window resizer,
3083         // then its removal should reduce the count.
3084         if (m_horizontalScrollbar->overlapsResizer())
3085             adjustScrollbarsAvoidingResizerCount(-1);
3086         removeChild(m_horizontalScrollbar.get());
3087         m_horizontalScrollbar = nullptr;
3088     }
3089 }
3090
3091 void FrameView::setHasVerticalScrollbar(bool hasBar)
3092 {
3093     if (hasBar && !m_verticalScrollbar) {
3094         m_verticalScrollbar = createScrollbar(VerticalScrollbar);
3095         addChild(m_verticalScrollbar.get());
3096         didAddScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
3097         m_verticalScrollbar->styleChanged();
3098     } else if (!hasBar && m_verticalScrollbar) {
3099         willRemoveScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
3100         // If the scrollbar has been marked as overlapping the window resizer,
3101         // then its removal should reduce the count.
3102         if (m_verticalScrollbar->overlapsResizer())
3103             adjustScrollbarsAvoidingResizerCount(-1);
3104         removeChild(m_verticalScrollbar.get());
3105         m_verticalScrollbar = nullptr;
3106     }
3107 }
3108
3109 void FrameView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
3110     bool horizontalLock, bool verticalLock)
3111 {
3112     bool needsUpdate = false;
3113
3114     if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
3115         m_horizontalScrollbarMode = horizontalMode;
3116         needsUpdate = true;
3117     }
3118
3119     if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
3120         m_verticalScrollbarMode = verticalMode;
3121         needsUpdate = true;
3122     }
3123
3124     if (horizontalLock)
3125         setHorizontalScrollbarLock();
3126
3127     if (verticalLock)
3128         setVerticalScrollbarLock();
3129
3130     if (!needsUpdate)
3131         return;
3132
3133     updateScrollbars(scrollOffsetDouble());
3134
3135     if (!layerForScrolling())
3136         return;
3137     blink::WebLayer* layer = layerForScrolling()->platformLayer();
3138     if (!layer)
3139         return;
3140     layer->setUserScrollable(userInputScrollable(HorizontalScrollbar), userInputScrollable(VerticalScrollbar));
3141 }
3142
3143 void FrameView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
3144 {
3145     horizontalMode = m_horizontalScrollbarMode;
3146     verticalMode = m_verticalScrollbarMode;
3147 }
3148
3149 void FrameView::setClipsRepaints(bool clipsRepaints)
3150 {
3151     m_clipsRepaints = clipsRepaints;
3152 }
3153
3154 IntSize FrameView::unscaledVisibleContentSize(IncludeScrollbarsInRect scrollbarInclusion) const
3155 {
3156     return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(frameRect().size()) : frameRect().size();
3157 }
3158
3159 IntSize FrameView::excludeScrollbars(const IntSize& size) const
3160 {
3161     int verticalScrollbarWidth = 0;
3162     int horizontalScrollbarHeight = 0;
3163
3164     if (Scrollbar* verticalBar = verticalScrollbar())
3165         verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? verticalBar->width() : 0;
3166     if (Scrollbar* horizontalBar = horizontalScrollbar())
3167         horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? horizontalBar->height() : 0;
3168
3169     return IntSize(std::max(0, size.width() - verticalScrollbarWidth),
3170         std::max(0, size.height() - horizontalScrollbarHeight));
3171
3172 }
3173
3174 IntRect FrameView::visibleContentRect(IncludeScrollbarsInRect scollbarInclusion) const
3175 {
3176     FloatSize visibleContentSize = unscaledVisibleContentSize(scollbarInclusion);
3177     visibleContentSize.scale(1 / visibleContentScaleFactor());
3178     return IntRect(flooredIntPoint(m_scrollPosition), expandedIntSize(visibleContentSize));
3179 }
3180
3181 IntSize FrameView::contentsSize() const
3182 {
3183     return m_contentsSize;
3184 }
3185
3186 IntPoint FrameView::minimumScrollPosition() const
3187 {
3188     return IntPoint(-scrollOrigin().x(), -scrollOrigin().y());
3189 }
3190
3191 IntPoint FrameView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
3192 {
3193     if (!constrainsScrollingToContentEdge())
3194         return scrollPoint;
3195
3196     IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
3197     newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
3198     return newScrollPosition;
3199 }
3200
3201 DoublePoint FrameView::adjustScrollPositionWithinRange(const DoublePoint& scrollPoint) const
3202 {
3203     if (!constrainsScrollingToContentEdge())
3204         return scrollPoint;
3205     DoublePoint newScrollPosition = scrollPoint.shrunkTo(
3206         maximumScrollPosition().x(), maximumScrollPosition().y());
3207     newScrollPosition = newScrollPosition.expandedTo(
3208         minimumScrollPosition().x(), minimumScrollPosition().y());
3209     return newScrollPosition;
3210 }
3211
3212 void FrameView::adjustScrollbarOpacity()
3213 {
3214     if (m_horizontalScrollbar && layerForHorizontalScrollbar()) {
3215         bool isOpaqueScrollbar = !m_horizontalScrollbar->isOverlayScrollbar();
3216         layerForHorizontalScrollbar()->setContentsOpaque(isOpaqueScrollbar);
3217     }
3218     if (m_verticalScrollbar && layerForVerticalScrollbar()) {
3219         bool isOpaqueScrollbar = !m_verticalScrollbar->isOverlayScrollbar();
3220         layerForVerticalScrollbar()->setContentsOpaque(isOpaqueScrollbar);
3221     }
3222 }
3223
3224 int FrameView::scrollSize(ScrollbarOrientation orientation) const
3225 {
3226     Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
3227
3228     // If no scrollbars are present, the content may still be scrollable.
3229     if (!scrollbar) {
3230         IntSize scrollSize = m_contentsSize - visibleContentRect().size();
3231         scrollSize.clampNegativeToZero();
3232         return orientation == HorizontalScrollbar ? scrollSize.width() : scrollSize.height();
3233     }
3234
3235     return scrollbar->totalSize() - scrollbar->visibleSize();
3236 }
3237
3238 void FrameView::setScrollOffset(const IntPoint& offset)
3239 {
3240     scrollTo(DoublePoint(adjustScrollPositionWithinRange(offset)));
3241 }
3242
3243 void FrameView::setScrollOffset(const DoublePoint& offset)
3244 {
3245     scrollTo(adjustScrollPositionWithinRange(offset));
3246 }
3247
3248 bool FrameView::scroll(ScrollDirection direction, ScrollGranularity granularity)
3249 {
3250     ScrollDirection physicalDirection =
3251         toPhysicalDirection(direction, isVerticalDocument(), isFlippedDocument());
3252
3253     return ScrollableArea::scroll(physicalDirection, granularity);
3254 }
3255
3256 IntSize FrameView::overhangAmount() const
3257 {
3258     IntSize stretch;
3259
3260     IntPoint currentScrollPosition = scrollPosition();
3261     IntPoint minScrollPosition = minimumScrollPosition();
3262     IntPoint maxScrollPosition = maximumScrollPosition();
3263
3264     if (currentScrollPosition.x() < minScrollPosition.x())
3265         stretch.setWidth(currentScrollPosition.x() - minScrollPosition.x());
3266     if (currentScrollPosition.x() > maxScrollPosition.x())
3267         stretch.setWidth(currentScrollPosition.x() - maxScrollPosition.x());
3268
3269     if (currentScrollPosition.y() < minScrollPosition.y())
3270         stretch.setHeight(currentScrollPosition.y() - minScrollPosition.y());
3271     if (currentScrollPosition.y() > maxScrollPosition.y())
3272         stretch.setHeight(currentScrollPosition.y() - maxScrollPosition.y());
3273
3274     return stretch;
3275 }
3276
3277 void FrameView::windowResizerRectChanged()
3278 {
3279     updateScrollbars(scrollOffsetDouble());
3280 }
3281
3282 static bool useOverlayScrollbars()
3283 {
3284     // FIXME: Need to detect the presence of CSS custom scrollbars, which are non-overlay regardless the ScrollbarTheme.
3285     return ScrollbarTheme::theme()->usesOverlayScrollbars();
3286 }
3287
3288 void FrameView::computeScrollbarExistence(bool& newHasHorizontalScrollbar, bool& newHasVerticalScrollbar, const IntSize& docSize, ComputeScrollbarExistenceOption option) const
3289 {
3290     bool hasHorizontalScrollbar = m_horizontalScrollbar;
3291     bool hasVerticalScrollbar = m_verticalScrollbar;
3292
3293     newHasHorizontalScrollbar = hasHorizontalScrollbar;
3294     newHasVerticalScrollbar = hasVerticalScrollbar;
3295
3296     if (m_frame->settings() && m_frame->settings()->rootLayerScrolls())
3297         return;
3298
3299     ScrollbarMode hScroll = m_horizontalScrollbarMode;
3300     ScrollbarMode vScroll = m_verticalScrollbarMode;
3301
3302     if (hScroll != ScrollbarAuto)
3303         newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
3304     if (vScroll != ScrollbarAuto)
3305         newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
3306
3307     if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto))
3308         return;
3309
3310     if (hScroll == ScrollbarAuto)
3311         newHasHorizontalScrollbar = docSize.width() > visibleWidth();
3312     if (vScroll == ScrollbarAuto)
3313         newHasVerticalScrollbar = docSize.height() > visibleHeight();
3314
3315     if (useOverlayScrollbars())
3316         return;
3317
3318     IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size();
3319
3320     bool attemptToRemoveScrollbars = (option == FirstPass
3321         && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height());
3322     if (attemptToRemoveScrollbars) {
3323         if (hScroll == ScrollbarAuto)
3324             newHasHorizontalScrollbar = false;
3325         if (vScroll == ScrollbarAuto)
3326             newHasVerticalScrollbar = false;
3327     }
3328
3329     // If we ever turn one scrollbar off, always turn the other one off too.
3330     // Never ever try to both gain/lose a scrollbar in the same pass.
3331     if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn)
3332         newHasVerticalScrollbar = false;
3333     if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn)
3334         newHasHorizontalScrollbar = false;
3335 }
3336
3337 void FrameView::updateScrollbarGeometry()
3338 {
3339     if (m_horizontalScrollbar) {
3340         int clientWidth = visibleWidth();
3341         IntRect oldRect(m_horizontalScrollbar->frameRect());
3342         IntRect hBarRect((shouldPlaceVerticalScrollbarOnLeft() && m_verticalScrollbar) ? m_verticalScrollbar->width() : 0,
3343             height() - m_horizontalScrollbar->height(),
3344             width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
3345             m_horizontalScrollbar->height());
3346         m_horizontalScrollbar->setFrameRect(adjustScrollbarRectForResizer(hBarRect, m_horizontalScrollbar.get()));
3347         if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
3348             m_horizontalScrollbar->invalidate();
3349
3350         if (m_scrollbarsSuppressed)
3351             m_horizontalScrollbar->setSuppressInvalidation(true);
3352         m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
3353         m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
3354         m_horizontalScrollbar->offsetDidChange();
3355         if (m_scrollbarsSuppressed)
3356             m_horizontalScrollbar->setSuppressInvalidation(false);
3357     }
3358
3359     if (m_verticalScrollbar) {
3360         int clientHeight = visibleHeight();
3361         IntRect oldRect(m_verticalScrollbar->frameRect());
3362         IntRect vBarRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()),
3363             0,
3364             m_verticalScrollbar->width(),
3365             height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
3366         m_verticalScrollbar->setFrameRect(adjustScrollbarRectForResizer(vBarRect, m_verticalScrollbar.get()));
3367         if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
3368             m_verticalScrollbar->invalidate();
3369
3370         if (m_scrollbarsSuppressed)
3371             m_verticalScrollbar->setSuppressInvalidation(true);
3372         m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
3373         m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
3374         m_verticalScrollbar->offsetDidChange();
3375         if (m_scrollbarsSuppressed)
3376             m_verticalScrollbar->setSuppressInvalidation(false);
3377     }
3378 }
3379
3380 IntRect FrameView::adjustScrollbarRectForResizer(const IntRect& rect, Scrollbar* scrollbar)
3381 {
3382     // Get our window resizer rect and see if we overlap. Adjust to avoid the overlap
3383     // if necessary.
3384     IntRect adjustedRect(rect);
3385     bool overlapsResizer = false;
3386     if (!rect.isEmpty() && !windowResizerRect().isEmpty()) {
3387         IntRect resizerRect = convertFromContainingWindow(windowResizerRect());
3388         if (rect.intersects(resizerRect)) {
3389             if (scrollbar->orientation() == HorizontalScrollbar) {
3390                 int overlap = rect.maxX() - resizerRect.x();
3391                 if (overlap > 0 && resizerRect.maxX() >= rect.maxX()) {
3392                     adjustedRect.setWidth(rect.width() - overlap);
3393                     overlapsResizer = true;
3394                 }
3395             } else {
3396                 int overlap = rect.maxY() - resizerRect.y();
3397                 if (overlap > 0 && resizerRect.maxY() >= rect.maxY()) {
3398                     adjustedRect.setHeight(rect.height() - overlap);
3399                     overlapsResizer = true;
3400                 }
3401             }
3402         }
3403     }
3404     if (overlapsResizer != scrollbar->overlapsResizer()) {
3405         scrollbar->setOverlapsResizer(overlapsResizer);
3406         adjustScrollbarsAvoidingResizerCount(overlapsResizer ? 1 : -1);
3407     }
3408     return adjustedRect;
3409 }
3410
3411 bool FrameView::adjustScrollbarExistence(ComputeScrollbarExistenceOption option)
3412 {
3413     ASSERT(m_inUpdateScrollbars);
3414
3415     // If we came in here with the view already needing a layout, then go ahead and do that
3416     // first.  (This will be the common case, e.g., when the page changes due to window resizing for example).
3417     // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
3418     if (!m_scrollbarsSuppressed)
3419         scrollbarExistenceDidChange();
3420
3421     bool hasHorizontalScrollbar = m_horizontalScrollbar;
3422     bool hasVerticalScrollbar = m_verticalScrollbar;
3423
3424     bool newHasHorizontalScrollbar = false;
3425     bool newHasVerticalScrollbar = false;
3426     computeScrollbarExistence(newHasHorizontalScrollbar, newHasVerticalScrollbar, contentsSize(), option);
3427
3428     bool scrollbarExistenceChanged = hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScrollbar != newHasVerticalScrollbar;
3429     if (!scrollbarExistenceChanged)
3430         return false;
3431
3432     setHasHorizontalScrollbar(newHasHorizontalScrollbar);
3433     setHasVerticalScrollbar(newHasVerticalScrollbar);
3434
3435     if (m_scrollbarsSuppressed)
3436         return true;
3437
3438     if (!useOverlayScrollbars())
3439         contentsResized();
3440     scrollbarExistenceDidChange();
3441     return true;
3442 }
3443
3444 void FrameView::updateScrollbars(const DoubleSize& desiredOffset)
3445 {
3446     if (scrollbarsDisabled()) {
3447         setScrollOffsetFromUpdateScrollbars(desiredOffset);
3448         return;
3449     }
3450
3451     if (m_inUpdateScrollbars)
3452         return;
3453     InUpdateScrollbarsScope inUpdateScrollbarsScope(this);
3454
3455     IntSize oldVisibleSize = visibleSize();
3456
3457     bool scrollbarExistenceChanged = false;
3458     int maxUpdateScrollbarsPass = useOverlayScrollbars() || m_scrollbarsSuppressed ? 1 : 3;
3459     for (int updateScrollbarsPass = 0; updateScrollbarsPass < maxUpdateScrollbarsPass; updateScrollbarsPass++) {
3460         if (!adjustScrollbarExistence(updateScrollbarsPass ? Incremental : FirstPass))
3461             break;
3462         scrollbarExistenceChanged = true;
3463     }
3464
3465     updateScrollbarGeometry();
3466
3467     if (scrollbarExistenceChanged) {
3468         // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
3469         frameRectsChanged();
3470         positionScrollbarLayers();
3471         updateScrollCorner();
3472     }
3473
3474     // FIXME: We don't need to do this if we are composited.
3475     IntSize newVisibleSize = visibleSize();
3476     if (newVisibleSize.width() > oldVisibleSize.width()) {
3477         if (shouldPlaceVerticalScrollbarOnLeft())
3478             invalidateRect(IntRect(0, 0, newVisibleSize.width() - oldVisibleSize.width(), newVisibleSize.height()));
3479         else
3480             invalidateRect(IntRect(oldVisibleSize.width(), 0, newVisibleSize.width() - oldVisibleSize.width(), newVisibleSize.height()));
3481     }
3482     if (newVisibleSize.height() > oldVisibleSize.height())
3483         invalidateRect(IntRect(0, oldVisibleSize.height(), newVisibleSize.width(), newVisibleSize.height() - oldVisibleSize.height()));
3484
3485     setScrollOffsetFromUpdateScrollbars(desiredOffset);
3486 }
3487
3488 void FrameView::setScrollOffsetFromUpdateScrollbars(const DoubleSize& offset)
3489 {
3490     DoublePoint adjustedScrollPosition = DoublePoint(offset);
3491
3492     if (!isRubberBandInProgress())
3493         adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollPosition);
3494
3495     if (adjustedScrollPosition != scrollPositionDouble() || scrollOriginChanged()) {
3496         ScrollableArea::scrollToOffsetWithoutAnimation(toFloatPoint(adjustedScrollPosition));
3497         resetScrollOriginChanged();
3498     }
3499 }
3500
3501 const int panIconSizeLength = 16;
3502
3503 IntRect FrameView::rectToCopyOnScroll() const
3504 {
3505     IntRect scrollViewRect = convertToContainingWindow(IntRect((shouldPlaceVerticalScrollbarOnLeft() && verticalScrollbar()) ? verticalScrollbar()->width() : 0, 0, visibleWidth(), visibleHeight()));
3506     if (hasOverlayScrollbars()) {
3507         int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
3508         int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
3509
3510         scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
3511         scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
3512     }
3513     return scrollViewRect;
3514 }
3515
3516 void FrameView::scrollContentsIfNeeded()
3517 {
3518     if (m_pendingScrollDelta.isZero())
3519         return;
3520     DoubleSize scrollDelta = m_pendingScrollDelta;
3521     m_pendingScrollDelta = DoubleSize();
3522     // FIXME: Change scrollContents() to take DoubleSize. crbug.com/414283.
3523     scrollContents(flooredIntSize(scrollDelta));
3524 }
3525
3526 void FrameView::scrollContents(const IntSize& scrollDelta)
3527 {
3528     HostWindow* window = hostWindow();
3529     if (!window)
3530         return;
3531
3532     IntRect clipRect = windowClipRect();
3533     IntRect updateRect = clipRect;
3534     updateRect.intersect(rectToCopyOnScroll());
3535
3536     if (m_shouldDrawPanScrollIcon) {
3537         // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers.
3538         // https://bugs.webkit.org/show_bug.cgi?id=47837
3539         int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + std::max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
3540         IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
3541         IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation, IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
3542         panScrollIconDirtyRect.intersect(clipRect);
3543         window->invalidateContentsAndRootView(panScrollIconDirtyRect);
3544     }
3545
3546     if (!scrollContentsFastPath(-scrollDelta))
3547         scrollContentsSlowPath(updateRect);
3548
3549     // Invalidate the overhang areas if they are visible.
3550     updateOverhangAreas();
3551
3552     // This call will move children with native widgets (plugins) and invalidate them as well.
3553     frameRectsChanged();
3554 }
3555
3556 IntPoint FrameView::rootViewToContents(const IntPoint& rootViewPoint) const
3557 {
3558     IntPoint viewPoint = convertFromContainingWindow(rootViewPoint);
3559     return viewPoint + scrollOffset();
3560 }
3561
3562 IntPoint FrameView::contentsToRootView(const IntPoint& contentsPoint) const
3563 {
3564     IntPoint viewPoint = contentsPoint - scrollOffset();
3565     return convertToContainingWindow(viewPoint);
3566 }
3567
3568 IntRect FrameView::rootViewToContents(const IntRect& rootViewRect) const
3569 {
3570     IntRect viewRect = convertFromContainingWindow(rootViewRect);
3571     viewRect.move(scrollOffset());
3572     return viewRect;
3573 }
3574
3575 IntRect FrameView::contentsToRootView(const IntRect& contentsRect) const
3576 {
3577     IntRect viewRect = contentsRect;
3578     viewRect.move(-scrollOffset());
3579     return convertToContainingWindow(viewRect);
3580 }
3581
3582 IntPoint FrameView::windowToContents(const IntPoint& windowPoint) const
3583 {
3584     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
3585     return viewPoint + scrollOffset();
3586 }
3587
3588 FloatPoint FrameView::windowToContents(const FloatPoint& windowPoint) const
3589 {
3590     FloatPoint viewPoint = convertFromContainingWindow(windowPoint);
3591     return viewPoint + scrollOffset();
3592 }
3593
3594 IntPoint FrameView::contentsToWindow(const IntPoint& contentsPoint) const
3595 {
3596     IntPoint viewPoint = contentsPoint - scrollOffset();
3597     return convertToContainingWindow(viewPoint);
3598 }
3599
3600 IntRect FrameView::windowToContents(const IntRect& windowRect) const
3601 {
3602     IntRect viewRect = convertFromContainingWindow(windowRect);
3603     viewRect.move(scrollOffset());
3604     return viewRect;
3605 }
3606
3607 IntRect FrameView::contentsToWindow(const IntRect& contentsRect) const
3608 {
3609     IntRect viewRect = contentsRect;
3610     viewRect.move(-scrollOffset());
3611     return convertToContainingWindow(viewRect);
3612 }
3613
3614 IntRect FrameView::contentsToScreen(const IntRect& rect) const
3615 {
3616     HostWindow* window = hostWindow();
3617     if (!window)
3618         return IntRect();
3619     return window->rootViewToScreen(contentsToRootView(rect));
3620 }
3621
3622 bool FrameView::containsScrollbarsAvoidingResizer() const
3623 {
3624     return !m_scrollbarsAvoidingResizer;
3625 }
3626
3627 void FrameView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
3628 {
3629     int oldCount = m_scrollbarsAvoidingResizer;
3630     m_scrollbarsAvoidingResizer += overlapDelta;
3631     if (parent()) {
3632         toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(overlapDelta);
3633     } else if (!scrollbarsSuppressed()) {
3634         // If we went from n to 0 or from 0 to n and we're the outermost view,
3635         // we need to invalidate the windowResizerRect(), since it will now need to paint
3636         // differently.
3637         if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0)
3638             || (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
3639             invalidateRect(windowResizerRect());
3640     }
3641 }
3642
3643 void FrameView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
3644 {
3645     if (suppressed == m_scrollbarsSuppressed)
3646         return;
3647
3648     m_scrollbarsSuppressed = suppressed;
3649
3650     if (repaintOnUnsuppress && !suppressed) {
3651         if (m_horizontalScrollbar)
3652             m_horizontalScrollbar->invalidate();
3653         if (m_verticalScrollbar)
3654             m_verticalScrollbar->invalidate();
3655
3656         // Invalidate the scroll corner too on unsuppress.
3657         invalidateRect(scrollCornerRect());
3658     }
3659 }
3660
3661 Scrollbar* FrameView::scrollbarAtWindowPoint(const IntPoint& windowPoint)
3662 {
3663     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
3664     return scrollbarAtViewPoint(viewPoint);
3665 }
3666
3667 Scrollbar* FrameView::scrollbarAtViewPoint(const IntPoint& viewPoint)
3668 {
3669     if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(viewPoint))
3670         return m_horizontalScrollbar.get();
3671     if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(viewPoint))
3672         return m_verticalScrollbar.get();
3673     return 0;
3674 }
3675
3676 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
3677 {
3678     if (!graphicsLayer || !scrollbar)
3679         return;
3680
3681     IntRect scrollbarRect = scrollbar->frameRect();
3682     graphicsLayer->setPosition(scrollbarRect.location());
3683
3684     if (scrollbarRect.size() == graphicsLayer->size())
3685         return;
3686
3687     graphicsLayer->setSize(scrollbarRect.size());
3688
3689     if (graphicsLayer->hasContentsLayer()) {
3690         graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scrollbarRect.height()));
3691         return;
3692     }
3693
3694     graphicsLayer->setDrawsContent(true);
3695     graphicsLayer->setNeedsDisplay();
3696 }
3697
3698 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
3699 {
3700     if (!graphicsLayer)
3701         return;
3702     graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
3703     graphicsLayer->setPosition(cornerRect.location());
3704     if (cornerRect.size() != graphicsLayer->size())
3705         graphicsLayer->setNeedsDisplay();
3706     graphicsLayer->setSize(cornerRect.size());
3707 }
3708
3709 void FrameView::positionScrollbarLayers()
3710 {
3711     positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
3712     positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
3713     positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
3714 }
3715
3716 bool FrameView::userInputScrollable(ScrollbarOrientation orientation) const
3717 {
3718     Document* document = frame().document();
3719     Element* fullscreenElement = Fullscreen::fullscreenElementFrom(*document);
3720     if (fullscreenElement && fullscreenElement != document->documentElement())
3721         return false;
3722
3723     ScrollbarMode mode = (orientation == HorizontalScrollbar) ?
3724         m_horizontalScrollbarMode : m_verticalScrollbarMode;
3725
3726     return mode == ScrollbarAuto || mode == ScrollbarAlwaysOn;
3727 }
3728
3729 bool FrameView::shouldPlaceVerticalScrollbarOnLeft() const
3730 {
3731     return false;
3732 }
3733
3734 IntRect FrameView::scrollCornerRect() const
3735 {
3736     IntRect cornerRect;
3737
3738     if (hasOverlayScrollbars())
3739         return cornerRect;
3740
3741     if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
3742         cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : m_horizontalScrollbar->width(),
3743             height() - m_horizontalScrollbar->height(),
3744             width() - m_horizontalScrollbar->width(),
3745             m_horizontalScrollbar->height()));
3746     }
3747
3748     if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
3749         cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()),
3750             m_verticalScrollbar->height(),
3751             m_verticalScrollbar->width(),
3752             height() - m_verticalScrollbar->height()));
3753     }
3754
3755     return cornerRect;
3756 }
3757
3758 bool FrameView::isScrollCornerVisible() const
3759 {
3760     return !scrollCornerRect().isEmpty();
3761 }
3762
3763 void FrameView::invalidateScrollCornerRect(const IntRect& rect)
3764 {
3765     invalidateRect(rect);
3766 }
3767
3768 void FrameView::paintPanScrollIcon(GraphicsContext* context)
3769 {
3770     DEFINE_STATIC_REF(Image, panScrollIcon, (Image::loadPlatformResource("panIcon")));
3771     IntPoint iconGCPoint = m_panScrollIconPoint;
3772     if (parent())
3773         iconGCPoint = toFrameView(parent())->windowToContents(iconGCPoint);
3774     context->drawImage(panScrollIcon, iconGCPoint);
3775 }
3776
3777 void FrameView::paint(GraphicsContext* context, const IntRect& rect)
3778 {
3779     FramePainter(*this).paint(context, rect);
3780 }
3781
3782 void FrameView::paintContents(GraphicsContext* context, const IntRect& damageRect)
3783 {
3784     FramePainter(*this).paintContents(context, damageRect);
3785 }
3786
3787 void FrameView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
3788 {
3789     int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
3790         ? verticalScrollbar()->width() : 0;
3791     int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
3792         ? horizontalScrollbar()->height() : 0;
3793
3794     int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
3795     if (physicalScrollY < 0) {
3796         horizontalOverhangRect = frameRect();
3797         horizontalOverhangRect.setHeight(-physicalScrollY);
3798         horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
3799     } else if (physicalScrollY > 0 && contentsHeight() && physicalScrollY > contentsHeight() - visibleHeight()) {
3800         int height = physicalScrollY - (contentsHeight() - visibleHeight());
3801         horizontalOverhangRect = frameRect();
3802         horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight);
3803         horizontalOverhangRect.setHeight(height);
3804         horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
3805     }
3806
3807     int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
3808     if (physicalScrollX < 0) {
3809         verticalOverhangRect.setWidth(-physicalScrollX);
3810         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
3811         verticalOverhangRect.setX(frameRect().x());
3812         if (horizontalOverhangRect.y() == frameRect().y())
3813             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
3814         else
3815             verticalOverhangRect.setY(frameRect().y());
3816     } else if (physicalScrollX > 0 && contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth()) {
3817         int width = physicalScrollX - (contentsWidth() - visibleWidth());
3818         verticalOverhangRect.setWidth(width);
3819         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
3820         verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth);
3821         if (horizontalOverhangRect.y() == frameRect().y())
3822             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
3823         else
3824             verticalOverhangRect.setY(frameRect().y());
3825     }
3826 }
3827
3828 void FrameView::updateOverhangAreas()
3829 {
3830     HostWindow* window = hostWindow();
3831     if (!window)
3832         return;
3833
3834     IntRect horizontalOverhangRect;
3835     IntRect verticalOverhangRect;
3836     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
3837     if (!horizontalOverhangRect.isEmpty())
3838         window->invalidateContentsAndRootView(horizontalOverhangRect);
3839     if (!verticalOverhangRect.isEmpty())
3840         window->invalidateContentsAndRootView(verticalOverhangRect);
3841 }
3842
3843 bool FrameView::isPointInScrollbarCorner(const IntPoint& windowPoint)
3844 {
3845     if (!scrollbarCornerPresent())
3846         return false;
3847
3848     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
3849
3850     if (m_horizontalScrollbar) {
3851         int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
3852         int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
3853         int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
3854
3855         return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
3856     }
3857
3858     int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
3859     int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
3860     int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
3861
3862     return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
3863 }
3864
3865 bool FrameView::scrollbarCornerPresent() const
3866 {
3867     return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0)
3868         || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
3869 }
3870
3871 IntRect FrameView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
3872 {
3873     // Scrollbars won't be transformed within us
3874     IntRect newRect = localRect;
3875     newRect.moveBy(scrollbar->location());
3876     return newRect;
3877 }
3878
3879 IntRect FrameView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
3880 {
3881     IntRect newRect = parentRect;
3882     // Scrollbars won't be transformed within us
3883     newRect.moveBy(-scrollbar->location());
3884     return newRect;
3885 }
3886
3887 // FIXME: test these on windows
3888 IntPoint FrameView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
3889 {
3890     // Scrollbars won't be transformed within us
3891     IntPoint newPoint = localPoint;
3892     newPoint.moveBy(scrollbar->location());
3893     return newPoint;
3894 }
3895
3896 IntPoint FrameView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
3897 {
3898     IntPoint newPoint = parentPoint;
3899     // Scrollbars won't be transformed within us
3900     newPoint.moveBy(-scrollbar->location());
3901     return newPoint;
3902 }
3903
3904 void FrameView::setParentVisible(bool visible)
3905 {
3906     if (isParentVisible() == visible)
3907         return;
3908
3909     Widget::setParentVisible(visible);
3910
3911     if (!isSelfVisible())
3912         return;
3913
3914     for (const auto& child : m_children)
3915         child->setParentVisible(visible);
3916 }
3917
3918 void FrameView::show()
3919 {
3920     if (!isSelfVisible()) {
3921         setSelfVisible(true);
3922         if (isParentVisible()) {
3923             for (const auto& child : m_children)
3924                 child->setParentVisible(true);
3925         }
3926     }
3927
3928     Widget::show();
3929 }
3930
3931 void FrameView::hide()
3932 {
3933     if (isSelfVisible()) {
3934         if (isParentVisible()) {
3935             for (const auto& child : m_children)
3936                 child->setParentVisible(false);
3937         }
3938         setSelfVisible(false);
3939     }
3940
3941     Widget::hide();
3942 }
3943
3944 void FrameView::addPanScrollIcon(const IntPoint& iconPosition)
3945 {
3946     HostWindow* window = hostWindow();
3947     if (!window)
3948         return;
3949     m_shouldDrawPanScrollIcon = true;
3950     m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2);
3951     window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
3952 }
3953
3954 void FrameView::removePanScrollIcon()
3955 {
3956     HostWindow* window = hostWindow();
3957     if (!window)
3958         return;
3959     m_shouldDrawPanScrollIcon = false;
3960     window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
3961 }
3962
3963 void FrameView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
3964 {
3965     if (scrollOrigin() == origin)
3966         return;
3967
3968     ScrollableArea::setScrollOrigin(origin);
3969
3970     // Update if the scroll origin changes, since our position will be different if the content size did not change.
3971     if (updatePositionAtAll && updatePositionSynchronously)
3972         updateScrollbars(scrollOffsetDouble());
3973 }
3974
3975 } // namespace blink