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, 2013 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 "FrameView.h"
29
30#include "AXObjectCache.h"
31#include "AnimationController.h"
32#include "BackForwardController.h"
33#include "CachedImage.h"
34#include "CachedResourceLoader.h"
35#include "Chrome.h"
36#include "ChromeClient.h"
37#include "DOMWindow.h"
38#include "DocumentMarkerController.h"
39#include "EventHandler.h"
40#include "FloatRect.h"
41#include "FocusController.h"
42#include "FontCache.h"
43#include "FontLoader.h"
44#include "FrameLoader.h"
45#include "FrameLoaderClient.h"
46#include "FrameSelection.h"
47#include "FrameTree.h"
48#include "GraphicsContext.h"
49#include "HTMLDocument.h"
50#include "HTMLFrameElement.h"
51#include "HTMLFrameSetElement.h"
52#include "HTMLNames.h"
53#include "HTMLPlugInImageElement.h"
54#include "ImageDocument.h"
55#include "InspectorClient.h"
56#include "InspectorController.h"
57#include "InspectorInstrumentation.h"
58#include "Logging.h"
59#include "MainFrame.h"
60#include "MemoryCache.h"
61#include "MemoryPressureHandler.h"
62#include "OverflowEvent.h"
63#include "ProgressTracker.h"
64#include "RenderEmbeddedObject.h"
65#include "RenderFullScreen.h"
66#include "RenderIFrame.h"
67#include "RenderInline.h"
68#include "RenderLayer.h"
69#include "RenderLayerBacking.h"
70#include "RenderLayerCompositor.h"
71#include "RenderSVGRoot.h"
72#include "RenderScrollbar.h"
73#include "RenderScrollbarPart.h"
74#include "RenderStyle.h"
75#include "RenderText.h"
76#include "RenderTheme.h"
77#include "RenderView.h"
78#include "RenderWidget.h"
79#include "SVGDocument.h"
80#include "SVGSVGElement.h"
81#include "ScrollAnimator.h"
82#include "ScrollingCoordinator.h"
83#include "Settings.h"
84#include "StyleResolver.h"
85#include "TextResourceDecoder.h"
86#include "TextStream.h"
87#include "TiledBacking.h"
88
89#include <wtf/CurrentTime.h>
90#include <wtf/Ref.h>
91#include <wtf/TemporaryChange.h>
92
93#if USE(TILED_BACKING_STORE)
94#include "TiledBackingStore.h"
95#endif
96
97#if ENABLE(TEXT_AUTOSIZING)
98#include "TextAutosizer.h"
99#endif
100
101#if PLATFORM(IOS)
102#include "DocumentLoader.h"
103#include "LegacyTileCache.h"
104#include "MemoryCache.h"
105#include "MemoryPressureHandler.h"
106#include "SystemMemory.h"
107#endif
108
109namespace WebCore {
110
111using namespace HTMLNames;
112
113double FrameView::sCurrentPaintTimeStamp = 0.0;
114
115// The maximum number of updateEmbeddedObjects iterations that should be done before returning.
116static const unsigned maxUpdateEmbeddedObjectsIterations = 2;
117
118static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint)
119{
120    RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags;
121    if (didFullRepaint) {
122        flags &= ~RenderLayer::CheckForRepaint;
123        flags |= RenderLayer::NeedsFullRepaintInBacking;
124    }
125    if (isRelayoutingSubtree && layer->enclosingPaginationLayer(RenderLayer::IncludeCompositedPaginatedLayers))
126        flags |= RenderLayer::UpdatePagination;
127    return flags;
128}
129
130Pagination::Mode paginationModeForRenderStyle(const RenderStyle& style)
131{
132    EOverflow overflow = style.overflowY();
133    if (overflow != OPAGEDX && overflow != OPAGEDY)
134        return Pagination::Unpaginated;
135
136    bool isHorizontalWritingMode = style.isHorizontalWritingMode();
137    TextDirection textDirection = style.direction();
138    WritingMode writingMode = style.writingMode();
139
140    // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode
141    // is horizontal, then we use TextDirection to choose between those options. If the WritingMode
142    // is vertical, then the direction of the verticality dictates the choice.
143    if (overflow == OPAGEDX) {
144        if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode)
145            return Pagination::LeftToRightPaginated;
146        return Pagination::RightToLeftPaginated;
147    }
148
149    // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode
150    // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode
151    // is vertical, then we use TextDirection to choose between those options.
152    if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL))
153        return Pagination::TopToBottomPaginated;
154    return Pagination::BottomToTopPaginated;
155}
156
157FrameView::FrameView(Frame& frame)
158    : m_frame(&frame)
159    , m_canHaveScrollbars(true)
160    , m_layoutTimer(this, &FrameView::layoutTimerFired)
161    , m_layoutRoot(0)
162    , m_layoutPhase(OutsideLayout)
163    , m_inSynchronousPostLayout(false)
164    , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
165    , m_updateEmbeddedObjectsTimer(this, &FrameView::updateEmbeddedObjectsTimerFired)
166    , m_isTransparent(false)
167    , m_baseBackgroundColor(Color::white)
168    , m_mediaType("screen")
169    , m_overflowStatusDirty(true)
170    , m_viewportRenderer(0)
171    , m_wasScrolledByUser(false)
172    , m_inProgrammaticScroll(false)
173    , m_safeToPropagateScrollToParent(true)
174    , m_delayedScrollEventTimer(this, &FrameView::delayedScrollEventTimerFired)
175    , m_isTrackingRepaints(false)
176    , m_shouldUpdateWhileOffscreen(true)
177    , m_exposedRect(FloatRect::infiniteRect())
178    , m_deferSetNeedsLayouts(0)
179    , m_setNeedsLayoutWasDeferred(false)
180    , m_speculativeTilingEnabled(false)
181    , m_speculativeTilingEnableTimer(this, &FrameView::speculativeTilingEnableTimerFired)
182#if PLATFORM(IOS)
183    , m_useCustomFixedPositionLayoutRect(false)
184    , m_useCustomSizeForResizeEvent(false)
185#endif
186    , m_hasOverrideViewportSize(false)
187    , m_shouldAutoSize(false)
188    , m_inAutoSize(false)
189    , m_didRunAutosize(false)
190    , m_autoSizeFixedMinimumHeight(0)
191    , m_headerHeight(0)
192    , m_footerHeight(0)
193    , m_milestonesPendingPaint(0)
194    , m_visualUpdatesAllowedByClient(true)
195    , m_scrollPinningBehavior(DoNotPin)
196{
197    init();
198
199    if (frame.isMainFrame()) {
200        ScrollableArea::setVerticalScrollElasticity(m_frame->page() ? m_frame->page()->verticalScrollElasticity() : ScrollElasticityAllowed);
201        ScrollableArea::setHorizontalScrollElasticity(m_frame->page() ? m_frame->page()->horizontalScrollElasticity() : ScrollElasticityAllowed);
202    }
203}
204
205PassRefPtr<FrameView> FrameView::create(Frame& frame)
206{
207    RefPtr<FrameView> view = adoptRef(new FrameView(frame));
208    view->show();
209    return view.release();
210}
211
212PassRefPtr<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize)
213{
214    RefPtr<FrameView> view = adoptRef(new FrameView(frame));
215    view->Widget::setFrameRect(IntRect(view->location(), initialSize));
216    view->show();
217    return view.release();
218}
219
220FrameView::~FrameView()
221{
222    if (m_postLayoutTasksTimer.isActive())
223        m_postLayoutTasksTimer.stop();
224
225    removeFromAXObjectCache();
226    resetScrollbars();
227
228    // Custom scrollbars should already be destroyed at this point
229    ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
230    ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
231
232    setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
233    setHasVerticalScrollbar(false);
234
235    ASSERT(!m_scrollCorner);
236
237    ASSERT(frame().view() != this || !frame().contentRenderer());
238}
239
240void FrameView::reset()
241{
242    m_cannotBlitToWindow = false;
243    m_isOverlapped = false;
244    m_contentIsOpaque = false;
245    m_layoutTimer.stop();
246    m_layoutRoot = 0;
247    m_delayedLayout = false;
248    m_needsFullRepaint = true;
249    m_layoutSchedulingEnabled = true;
250    m_layoutPhase = OutsideLayout;
251    m_inSynchronousPostLayout = false;
252    m_layoutCount = 0;
253    m_nestedLayoutCount = 0;
254    m_postLayoutTasksTimer.stop();
255    m_updateEmbeddedObjectsTimer.stop();
256    m_firstLayout = true;
257    m_firstLayoutCallbackPending = false;
258    m_wasScrolledByUser = false;
259    m_safeToPropagateScrollToParent = true;
260    m_delayedScrollEventTimer.stop();
261    m_lastViewportSize = IntSize();
262    m_lastZoomFactor = 1.0f;
263    m_isTrackingRepaints = false;
264    m_trackedRepaintRects.clear();
265    m_lastPaintTime = 0;
266    m_paintBehavior = PaintBehaviorNormal;
267    m_isPainting = false;
268    m_visuallyNonEmptyCharacterCount = 0;
269    m_visuallyNonEmptyPixelCount = 0;
270    m_isVisuallyNonEmpty = false;
271    m_firstVisuallyNonEmptyLayoutCallbackPending = true;
272    m_maintainScrollPositionAnchor = 0;
273}
274
275void FrameView::removeFromAXObjectCache()
276{
277    if (AXObjectCache* cache = axObjectCache())
278        cache->remove(this);
279}
280
281void FrameView::resetScrollbars()
282{
283    // Reset the document's scrollbars back to our defaults before we yield the floor.
284    m_firstLayout = true;
285    setScrollbarsSuppressed(true);
286    if (m_canHaveScrollbars)
287        setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
288    else
289        setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
290    setScrollbarsSuppressed(false);
291}
292
293void FrameView::resetScrollbarsAndClearContentsSize()
294{
295    resetScrollbars();
296
297    setScrollbarsSuppressed(true);
298    setContentsSize(IntSize());
299    setScrollbarsSuppressed(false);
300}
301
302void FrameView::init()
303{
304    reset();
305
306    m_margins = LayoutSize(-1, -1); // undefined
307    m_size = LayoutSize();
308
309    // Propagate the marginwidth/height and scrolling modes to the view.
310    Element* ownerElement = frame().ownerElement();
311    if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
312        HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
313        if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
314            setCanHaveScrollbars(false);
315        LayoutUnit marginWidth = frameElt->marginWidth();
316        LayoutUnit marginHeight = frameElt->marginHeight();
317        if (marginWidth != -1)
318            setMarginWidth(marginWidth);
319        if (marginHeight != -1)
320            setMarginHeight(marginHeight);
321    }
322
323    Page* page = frame().page();
324    if (page && page->chrome().client().shouldPaintEntireContents())
325        setPaintsEntireContents(true);
326}
327
328void FrameView::prepareForDetach()
329{
330    detachCustomScrollbars();
331    // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
332    // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
333    removeFromAXObjectCache();
334
335    if (frame().page()) {
336        if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
337            scrollingCoordinator->willDestroyScrollableArea(this);
338    }
339}
340
341void FrameView::detachCustomScrollbars()
342{
343    Scrollbar* horizontalBar = horizontalScrollbar();
344    if (horizontalBar && horizontalBar->isCustomScrollbar())
345        setHasHorizontalScrollbar(false);
346
347    Scrollbar* verticalBar = verticalScrollbar();
348    if (verticalBar && verticalBar->isCustomScrollbar())
349        setHasVerticalScrollbar(false);
350
351    m_scrollCorner = nullptr;
352}
353
354void FrameView::recalculateScrollbarOverlayStyle()
355{
356    ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
357    ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
358
359    Color backgroundColor = documentBackgroundColor();
360    if (backgroundColor.isValid()) {
361        // Reduce the background color from RGB to a lightness value
362        // and determine which scrollbar style to use based on a lightness
363        // heuristic.
364        double hue, saturation, lightness;
365        backgroundColor.getHSL(hue, saturation, lightness);
366        if (lightness <= .5 && backgroundColor.alpha() > 0)
367            overlayStyle = ScrollbarOverlayStyleLight;
368    }
369
370    if (oldOverlayStyle != overlayStyle)
371        setScrollbarOverlayStyle(overlayStyle);
372}
373
374void FrameView::clear()
375{
376    setCanBlitOnScroll(true);
377
378    reset();
379
380    setScrollbarsSuppressed(true);
381
382#if PLATFORM(IOS)
383    // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load.
384    // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw.
385    if (LegacyTileCache* tileCache = legacyTileCache())
386        tileCache->setTilingMode(LegacyTileCache::Disabled);
387#endif
388}
389
390bool FrameView::didFirstLayout() const
391{
392    return !m_firstLayout;
393}
394
395void FrameView::invalidateRect(const IntRect& rect)
396{
397    if (!parent()) {
398        if (HostWindow* window = hostWindow())
399            window->invalidateContentsAndRootView(rect);
400        return;
401    }
402
403    RenderWidget* renderer = frame().ownerRenderer();
404    if (!renderer)
405        return;
406
407    IntRect repaintRect = rect;
408    repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
409                     renderer->borderTop() + renderer->paddingTop());
410    renderer->repaintRectangle(repaintRect);
411}
412
413void FrameView::setFrameRect(const IntRect& newRect)
414{
415    IntRect oldRect = frameRect();
416    if (newRect == oldRect)
417        return;
418
419#if ENABLE(TEXT_AUTOSIZING)
420    // Autosized font sizes depend on the width of the viewing area.
421    if (newRect.width() != oldRect.width()) {
422        Page* page = frame().page();
423        if (frame().isMainFrame() && page->settings().textAutosizingEnabled()) {
424            for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
425                frame().document()->textAutosizer()->recalculateMultipliers();
426        }
427    }
428#endif
429
430    ScrollView::setFrameRect(newRect);
431
432    updateScrollableAreaSet();
433
434    if (RenderView* renderView = this->renderView()) {
435        if (renderView->usesCompositing())
436            renderView->compositor().frameViewDidChangeSize();
437    }
438}
439
440#if ENABLE(REQUEST_ANIMATION_FRAME)
441bool FrameView::scheduleAnimation()
442{
443    if (HostWindow* window = hostWindow()) {
444        window->scheduleAnimation();
445        return true;
446    }
447    return false;
448}
449#endif
450
451void FrameView::setMarginWidth(LayoutUnit w)
452{
453    // make it update the rendering area when set
454    m_margins.setWidth(w);
455}
456
457void FrameView::setMarginHeight(LayoutUnit h)
458{
459    // make it update the rendering area when set
460    m_margins.setHeight(h);
461}
462
463bool FrameView::frameFlatteningEnabled() const
464{
465    return frame().settings().frameFlatteningEnabled();
466}
467
468bool FrameView::isFrameFlatteningValidForThisFrame() const
469{
470    if (!frameFlatteningEnabled())
471        return false;
472
473    HTMLFrameOwnerElement* owner = frame().ownerElement();
474    if (!owner)
475        return false;
476
477    // Frame flattening is valid only for <frame> and <iframe>.
478    return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag);
479}
480
481bool FrameView::avoidScrollbarCreation() const
482{
483    // with frame flattening no subframe can have scrollbars
484    // but we also cannot turn scrollbars off as we determine
485    // our flattening policy using that.
486    return isFrameFlatteningValidForThisFrame();
487}
488
489void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
490{
491    m_canHaveScrollbars = canHaveScrollbars;
492    ScrollView::setCanHaveScrollbars(canHaveScrollbars);
493}
494
495void FrameView::updateCanHaveScrollbars()
496{
497    ScrollbarMode hMode;
498    ScrollbarMode vMode;
499    scrollbarModes(hMode, vMode);
500    if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
501        setCanHaveScrollbars(false);
502    else
503        setCanHaveScrollbars(true);
504}
505
506PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
507{
508    if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame())
509        return ScrollView::createScrollbar(orientation);
510
511    // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
512    Document* doc = frame().document();
513
514    // Try the <body> element first as a scrollbar source.
515    Element* body = doc ? doc->body() : 0;
516    if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR))
517        return RenderScrollbar::createCustomScrollbar(this, orientation, body);
518
519    // If the <body> didn't have a custom style, then the root element might.
520    Element* docElement = doc ? doc->documentElement() : 0;
521    if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR))
522        return RenderScrollbar::createCustomScrollbar(this, orientation, docElement);
523
524    // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
525    RenderWidget* frameRenderer = frame().ownerRenderer();
526    if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR))
527        return RenderScrollbar::createCustomScrollbar(this, orientation, 0, &frame());
528
529    // Nobody set a custom style, so we just use a native scrollbar.
530    return ScrollView::createScrollbar(orientation);
531}
532
533void FrameView::setContentsSize(const IntSize& size)
534{
535    if (size == contentsSize())
536        return;
537
538    m_deferSetNeedsLayouts++;
539
540    ScrollView::setContentsSize(size);
541    ScrollView::contentsResized();
542
543    Page* page = frame().page();
544    if (!page)
545        return;
546
547    updateScrollableAreaSet();
548
549    page->chrome().contentsSizeChanged(&frame(), size); // Notify only.
550
551    ASSERT(m_deferSetNeedsLayouts);
552    m_deferSetNeedsLayouts--;
553
554    if (!m_deferSetNeedsLayouts)
555        m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
556}
557
558void FrameView::adjustViewSize()
559{
560    RenderView* renderView = this->renderView();
561    if (!renderView)
562        return;
563
564    ASSERT(frame().view() == this);
565
566    const IntRect rect = renderView->documentRect();
567    const IntSize& size = rect.size();
568    ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize());
569
570    setContentsSize(size);
571}
572
573void FrameView::applyOverflowToViewport(RenderElement* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
574{
575    // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
576    // overflow:hidden and overflow:scroll on <body> as applying to the document's
577    // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
578    // use the root element.
579
580    // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when
581    // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a
582    // header or footer.
583
584    bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
585
586    EOverflow overflowX = o->style().overflowX();
587    EOverflow overflowY = o->style().overflowY();
588
589    if (o->isSVGRoot()) {
590        // FIXME: evaluate if we can allow overflow for these cases too.
591        // Overflow is always hidden when stand-alone SVG documents are embedded.
592        if (toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) {
593            overflowX = OHIDDEN;
594            overflowY = OHIDDEN;
595        }
596    }
597
598    switch (overflowX) {
599        case OHIDDEN:
600            if (overrideHidden)
601                hMode = ScrollbarAuto;
602            else
603                hMode = ScrollbarAlwaysOff;
604            break;
605        case OSCROLL:
606            hMode = ScrollbarAlwaysOn;
607            break;
608        case OAUTO:
609            hMode = ScrollbarAuto;
610            break;
611        default:
612            // Don't set it at all.
613            ;
614    }
615
616     switch (overflowY) {
617        case OHIDDEN:
618            if (overrideHidden)
619                vMode = ScrollbarAuto;
620            else
621                vMode = ScrollbarAlwaysOff;
622            break;
623        case OSCROLL:
624            vMode = ScrollbarAlwaysOn;
625            break;
626        case OAUTO:
627            vMode = ScrollbarAuto;
628            break;
629        default:
630            // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort().
631            ;
632    }
633
634    m_viewportRenderer = o;
635}
636
637void FrameView::applyPaginationToViewport()
638{
639    Document* document = frame().document();
640    auto documentElement = document->documentElement();
641    RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr;
642    RenderElement* documentOrBodyRenderer = documentRenderer;
643    auto body = document->body();
644    if (body && body->renderer()) {
645        if (body->hasTagName(bodyTag))
646            documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && documentElement->hasTagName(htmlTag) ? body->renderer() : documentRenderer;
647    }
648
649    Pagination pagination;
650
651    if (!documentOrBodyRenderer) {
652        setPagination(pagination);
653        return;
654    }
655
656    EOverflow overflowY = documentOrBodyRenderer->style().overflowY();
657    if (overflowY == OPAGEDX || overflowY == OPAGEDY) {
658        pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style());
659        pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap());
660    }
661
662    setPagination(pagination);
663}
664
665void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
666{
667    m_viewportRenderer = 0;
668
669    const HTMLFrameOwnerElement* owner = frame().ownerElement();
670    if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
671        hMode = ScrollbarAlwaysOff;
672        vMode = ScrollbarAlwaysOff;
673        return;
674    }
675
676    if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
677        hMode = ScrollbarAuto;
678        vMode = ScrollbarAuto;
679    } else {
680        hMode = ScrollbarAlwaysOff;
681        vMode = ScrollbarAlwaysOff;
682    }
683
684    if (!m_layoutRoot) {
685        Document* document = frame().document();
686        auto documentElement = document->documentElement();
687        RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr;
688        auto body = document->body();
689        if (body && body->renderer()) {
690            if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) {
691                vMode = ScrollbarAlwaysOff;
692                hMode = ScrollbarAlwaysOff;
693            } else if (body->hasTagName(bodyTag)) {
694                // It's sufficient to just check the X overflow,
695                // since it's illegal to have visible in only one direction.
696                RenderElement* o = rootRenderer->style().overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
697                applyOverflowToViewport(o, hMode, vMode);
698            }
699        } else if (rootRenderer)
700            applyOverflowToViewport(rootRenderer, hMode, vMode);
701    }
702}
703
704void FrameView::updateCompositingLayersAfterStyleChange()
705{
706    RenderView* renderView = this->renderView();
707    if (!renderView)
708        return;
709
710    // If we expect to update compositing after an incipient layout, don't do so here.
711    if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout())
712        return;
713
714    RenderLayerCompositor& compositor = renderView->compositor();
715    // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
716    compositor.cacheAcceleratedCompositingFlags();
717    compositor.updateCompositingLayers(CompositingUpdateAfterStyleChange);
718}
719
720void FrameView::updateCompositingLayersAfterLayout()
721{
722    RenderView* renderView = this->renderView();
723    if (!renderView)
724        return;
725
726    // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
727    renderView->compositor().cacheAcceleratedCompositingFlags();
728    renderView->compositor().updateCompositingLayers(CompositingUpdateAfterLayout);
729}
730
731void FrameView::clearBackingStores()
732{
733    RenderView* renderView = this->renderView();
734    if (!renderView)
735        return;
736
737    RenderLayerCompositor& compositor = renderView->compositor();
738    ASSERT(compositor.inCompositingMode());
739    compositor.enableCompositingMode(false);
740    compositor.clearBackingForAllLayers();
741}
742
743void FrameView::restoreBackingStores()
744{
745    RenderView* renderView = this->renderView();
746    if (!renderView)
747        return;
748
749    RenderLayerCompositor& compositor = renderView->compositor();
750    compositor.enableCompositingMode(true);
751    compositor.updateCompositingLayers(CompositingUpdateAfterLayout);
752}
753
754GraphicsLayer* FrameView::layerForScrolling() const
755{
756    RenderView* renderView = this->renderView();
757    if (!renderView)
758        return 0;
759    return renderView->compositor().scrollLayer();
760}
761
762GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
763{
764    RenderView* renderView = this->renderView();
765    if (!renderView)
766        return 0;
767    return renderView->compositor().layerForHorizontalScrollbar();
768}
769
770GraphicsLayer* FrameView::layerForVerticalScrollbar() const
771{
772    RenderView* renderView = this->renderView();
773    if (!renderView)
774        return 0;
775    return renderView->compositor().layerForVerticalScrollbar();
776}
777
778GraphicsLayer* FrameView::layerForScrollCorner() const
779{
780    RenderView* renderView = this->renderView();
781    if (!renderView)
782        return 0;
783    return renderView->compositor().layerForScrollCorner();
784}
785
786TiledBacking* FrameView::tiledBacking() const
787{
788    RenderView* renderView = this->renderView();
789    if (!renderView)
790        return 0;
791
792    RenderLayerBacking* backing = renderView->layer()->backing();
793    if (!backing)
794        return 0;
795
796    return backing->graphicsLayer()->tiledBacking();
797}
798
799uint64_t FrameView::scrollLayerID() const
800{
801    RenderView* renderView = this->renderView();
802    if (!renderView)
803        return 0;
804
805    RenderLayerBacking* backing = renderView->layer()->backing();
806    if (!backing)
807        return 0;
808
809    return backing->scrollingNodeIDForRole(FrameScrollingNode);
810}
811
812ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const
813{
814    RenderView* renderView = this->renderView();
815    if (!renderView)
816        return nullptr;
817
818    return renderView->compositor().scrollableAreaForScrollLayerID(nodeID);
819}
820
821#if ENABLE(RUBBER_BANDING)
822GraphicsLayer* FrameView::layerForOverhangAreas() const
823{
824    RenderView* renderView = this->renderView();
825    if (!renderView)
826        return 0;
827    return renderView->compositor().layerForOverhangAreas();
828}
829
830GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const
831{
832    RenderView* renderView = this->renderView();
833    if (!renderView)
834        return 0;
835
836    return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer);
837}
838
839GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const
840{
841    RenderView* renderView = this->renderView();
842    if (!renderView)
843        return 0;
844
845    return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer);
846}
847
848#endif // ENABLE(RUBBER_BANDING)
849
850bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush)
851{
852    RenderView* renderView = this->renderView();
853    if (!renderView)
854        return true; // We don't want to keep trying to update layers if we have no renderer.
855
856    ASSERT(frame().view() == this);
857
858    // If we sync compositing layers when a layout is pending, we may cause painting of compositing
859    // layer content to occur before layout has happened, which will cause paintContents() to bail.
860    if (needsLayout())
861        return false;
862
863#if PLATFORM(IOS)
864    if (LegacyTileCache* tileCache = legacyTileCache())
865        tileCache->doPendingRepaints();
866#endif
867
868    renderView->compositor().flushPendingLayerChanges(rootFrameForFlush == &frame());
869
870    return true;
871}
872
873void FrameView::setNeedsOneShotDrawingSynchronization()
874{
875    if (Page* page = frame().page())
876        page->chrome().client().setNeedsOneShotDrawingSynchronization();
877}
878
879GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget)
880{
881    // To find the Widget that corresponds with platformWidget we have to do a linear
882    // search of our child widgets.
883    Widget* foundWidget = nullptr;
884    for (auto& widget : children()) {
885        if (widget->platformWidget() != platformWidget)
886            continue;
887        foundWidget = widget.get();
888        break;
889    }
890
891    if (!foundWidget)
892        return nullptr;
893
894    auto* renderWidget = RenderWidget::find(foundWidget);
895    if (!renderWidget)
896        return nullptr;
897
898    RenderLayer* widgetLayer = renderWidget->layer();
899    if (!widgetLayer || !widgetLayer->isComposited())
900        return nullptr;
901
902    return widgetLayer->backing()->parentForSublayers();
903}
904
905void FrameView::scheduleLayerFlushAllowingThrottling()
906{
907    RenderView* view = this->renderView();
908    if (!view)
909        return;
910    view->compositor().scheduleLayerFlush(true /* canThrottle */);
911}
912
913void FrameView::setHeaderHeight(int headerHeight)
914{
915    if (frame().page())
916        ASSERT(frame().isMainFrame());
917    m_headerHeight = headerHeight;
918
919    if (RenderView* renderView = this->renderView())
920        renderView->setNeedsLayout();
921}
922
923void FrameView::setFooterHeight(int footerHeight)
924{
925    if (frame().page())
926        ASSERT(frame().isMainFrame());
927    m_footerHeight = footerHeight;
928
929    if (RenderView* renderView = this->renderView())
930        renderView->setNeedsLayout();
931}
932
933float FrameView::topContentInset(TopContentInsetType contentInsetTypeToReturn) const
934{
935    if (platformWidget() && contentInsetTypeToReturn == TopContentInsetType::WebCoreOrPlatformContentInset)
936        return platformTopContentInset();
937
938    if (!frame().isMainFrame())
939        return 0;
940
941    Page* page = frame().page();
942    return page ? page->topContentInset() : 0;
943}
944
945void FrameView::topContentInsetDidChange(float newTopContentInset)
946{
947    RenderView* renderView = this->renderView();
948    if (!renderView)
949        return;
950
951    if (platformWidget())
952        platformSetTopContentInset(newTopContentInset);
953
954    layout();
955
956    updateScrollbars(scrollOffset());
957    if (renderView->usesCompositing())
958        renderView->compositor().frameViewDidChangeSize();
959
960    if (TiledBacking* tiledBacking = this->tiledBacking())
961        tiledBacking->setTopContentInset(newTopContentInset);
962}
963
964bool FrameView::hasCompositedContent() const
965{
966    if (RenderView* renderView = this->renderView())
967        return renderView->compositor().inCompositingMode();
968    return false;
969}
970
971bool FrameView::hasCompositedContentIncludingDescendants() const
972{
973    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
974        RenderView* renderView = frame->contentRenderer();
975        if (RenderLayerCompositor* compositor = renderView ? &renderView->compositor() : 0) {
976            if (compositor->inCompositingMode())
977                return true;
978
979            if (!RenderLayerCompositor::allowsIndependentlyCompositedFrames(this))
980                break;
981        }
982    }
983    return false;
984}
985
986bool FrameView::hasCompositingAncestor() const
987{
988    for (Frame* frame = this->frame().tree().parent(); frame; frame = frame->tree().parent()) {
989        if (FrameView* view = frame->view()) {
990            if (view->hasCompositedContent())
991                return true;
992        }
993    }
994    return false;
995}
996
997// Sometimes (for plug-ins) we need to eagerly go into compositing mode.
998void FrameView::enterCompositingMode()
999{
1000    if (RenderView* renderView = this->renderView()) {
1001        renderView->compositor().enableCompositingMode();
1002        if (!needsLayout())
1003            renderView->compositor().scheduleCompositingLayerUpdate();
1004    }
1005}
1006
1007bool FrameView::isEnclosedInCompositingLayer() const
1008{
1009    auto frameOwnerRenderer = frame().ownerRenderer();
1010    if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
1011        return true;
1012
1013    if (FrameView* parentView = parentFrameView())
1014        return parentView->isEnclosedInCompositingLayer();
1015    return false;
1016}
1017
1018bool FrameView::flushCompositingStateIncludingSubframes()
1019{
1020    bool allFramesFlushed = flushCompositingStateForThisFrame(&frame());
1021
1022    for (Frame* child = frame().tree().firstChild(); child; child = child->tree().traverseNext(&frame())) {
1023        bool flushed = child->view()->flushCompositingStateForThisFrame(&frame());
1024        allFramesFlushed &= flushed;
1025    }
1026    return allFramesFlushed;
1027}
1028
1029bool FrameView::isSoftwareRenderable() const
1030{
1031    RenderView* renderView = this->renderView();
1032    return !renderView || !renderView->compositor().has3DContent();
1033}
1034
1035void FrameView::setIsInWindow(bool isInWindow)
1036{
1037    if (RenderView* renderView = this->renderView())
1038        renderView->setIsInWindow(isInWindow);
1039}
1040
1041RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
1042{
1043    return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot;
1044}
1045
1046inline void FrameView::forceLayoutParentViewIfNeeded()
1047{
1048    RenderWidget* ownerRenderer = frame().ownerRenderer();
1049    if (!ownerRenderer)
1050        return;
1051
1052    RenderBox* contentBox = embeddedContentBox();
1053    if (!contentBox)
1054        return;
1055
1056    RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
1057    if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
1058        return;
1059
1060    // If the embedded SVG document appears the first time, the ownerRenderer has already finished
1061    // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
1062    // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
1063    // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
1064    // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
1065    // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
1066    // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
1067    Ref<FrameView> frameView(ownerRenderer->view().frameView());
1068
1069    // Mark the owner renderer as needing layout.
1070    ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
1071
1072    // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
1073    frameView->layout();
1074}
1075
1076void FrameView::layout(bool allowSubtree)
1077{
1078    if (isInLayout())
1079        return;
1080
1081    // Protect the view from being deleted during layout (in recalcStyle).
1082    Ref<FrameView> protect(*this);
1083
1084    // Many of the tasks performed during layout can cause this function to be re-entered,
1085    // so save the layout phase now and restore it on exit.
1086    TemporaryChange<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout);
1087
1088    // Every scroll that happens during layout is programmatic.
1089    TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1090
1091    bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening();
1092
1093    if (inChildFrameLayoutWithFrameFlattening) {
1094        startLayoutAtMainFrameViewIfNeeded(allowSubtree);
1095        RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
1096        if (!root || !root->needsLayout())
1097            return;
1098    }
1099
1100#if PLATFORM(IOS)
1101    if (updateFixedPositionLayoutRect())
1102        allowSubtree = false;
1103#endif
1104
1105    m_layoutTimer.stop();
1106    m_delayedLayout = false;
1107    m_setNeedsLayoutWasDeferred = false;
1108
1109    // we shouldn't enter layout() while painting
1110    ASSERT(!isPainting());
1111    if (isPainting())
1112        return;
1113
1114    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(&frame());
1115
1116    if (!allowSubtree && m_layoutRoot) {
1117        m_layoutRoot->markContainingBlocksForLayout(false);
1118        m_layoutRoot = 0;
1119    }
1120
1121    ASSERT(frame().view() == this);
1122    ASSERT(frame().document());
1123
1124    Document& document = *frame().document();
1125    ASSERT(!document.inPageCache());
1126
1127    bool subtree;
1128    RenderElement* root;
1129
1130    {
1131        TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1132
1133        if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) {
1134            // This is a new top-level layout. If there are any remaining tasks from the previous
1135            // layout, finish them now.
1136            TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1137            performPostLayoutTasks();
1138        }
1139
1140        m_layoutPhase = InPreLayoutStyleUpdate;
1141
1142        // Viewport-dependent media queries may cause us to need completely different style information.
1143        StyleResolver* styleResolver = document.styleResolverIfExists();
1144        if (!styleResolver || styleResolver->hasMediaQueriesAffectedByViewportChange()) {
1145            document.styleResolverChanged(DeferRecalcStyle);
1146            // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
1147            InspectorInstrumentation::mediaQueryResultChanged(&document);
1148        } else
1149            document.evaluateMediaQueryList();
1150
1151        // If there is any pagination to apply, it will affect the RenderView's style, so we should
1152        // take care of that now.
1153        applyPaginationToViewport();
1154
1155        // Always ensure our style info is up-to-date. This can happen in situations where
1156        // the layout beats any sort of style recalc update that needs to occur.
1157        document.updateStyleIfNeeded();
1158        m_layoutPhase = InPreLayout;
1159
1160        subtree = m_layoutRoot;
1161
1162        // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
1163        // so there's no point to continuing to layout
1164        if (hasOneRef())
1165            return;
1166
1167        root = subtree ? m_layoutRoot : document.renderView();
1168        if (!root) {
1169            // FIXME: Do we need to set m_size here?
1170            return;
1171        }
1172
1173        // Close block here so we can set up the font cache purge preventer, which we will still
1174        // want in scope even after we want m_layoutSchedulingEnabled to be restored again.
1175        // The next block sets m_layoutSchedulingEnabled back to false once again.
1176    }
1177
1178    FontCachePurgePreventer fontCachePurgePreventer;
1179    RenderLayer* layer;
1180
1181    ++m_nestedLayoutCount;
1182
1183    {
1184        TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1185
1186        if (!m_layoutRoot) {
1187            HTMLElement* body = document.body();
1188            if (body && body->renderer()) {
1189                if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) {
1190                    body->renderer()->setChildNeedsLayout();
1191                } else if (body->hasTagName(bodyTag)) {
1192                    if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox().stretchesToViewport())
1193                        body->renderer()->setChildNeedsLayout();
1194                }
1195            }
1196
1197#ifdef INSTRUMENT_LAYOUT_SCHEDULING
1198            if (m_firstLayout && !frame().ownerElement())
1199                printf("Elapsed time before first layout: %lld\n", document.elapsedTime().count());
1200#endif
1201        }
1202
1203        autoSizeIfEnabled();
1204
1205        m_needsFullRepaint = !subtree && (m_firstLayout || toRenderView(*root).printing());
1206
1207        if (!subtree) {
1208            ScrollbarMode hMode;
1209            ScrollbarMode vMode;
1210            calculateScrollbarModesForLayout(hMode, vMode);
1211
1212            if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) {
1213                if (m_firstLayout) {
1214                    setScrollbarsSuppressed(true);
1215
1216                    m_firstLayout = false;
1217                    m_firstLayoutCallbackPending = true;
1218                    m_lastViewportSize = sizeForResizeEvent();
1219                    m_lastZoomFactor = root->style().zoom();
1220
1221                    // Set the initial vMode to AlwaysOn if we're auto.
1222                    if (vMode == ScrollbarAuto)
1223                        setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
1224                    // Set the initial hMode to AlwaysOff if we're auto.
1225                    if (hMode == ScrollbarAuto)
1226                        setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
1227
1228                    setScrollbarModes(hMode, vMode);
1229                    setScrollbarsSuppressed(false, true);
1230                } else
1231                    setScrollbarModes(hMode, vMode);
1232            }
1233
1234            LayoutSize oldSize = m_size;
1235
1236            m_size = layoutSize();
1237
1238            if (oldSize != m_size) {
1239                m_needsFullRepaint = true;
1240                if (!m_firstLayout) {
1241                    RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : 0;
1242                    RenderBox* bodyRenderer = rootRenderer && document.body() ? document.body()->renderBox() : 0;
1243                    if (bodyRenderer && bodyRenderer->stretchesToViewport())
1244                        bodyRenderer->setChildNeedsLayout();
1245                    else if (rootRenderer && rootRenderer->stretchesToViewport())
1246                        rootRenderer->setChildNeedsLayout();
1247
1248                    document.updateViewportUnitsOnResize();
1249                }
1250            }
1251
1252            m_layoutPhase = InPreLayout;
1253        }
1254
1255        layer = root->enclosingLayer();
1256
1257        bool disableLayoutState = false;
1258        if (subtree) {
1259            disableLayoutState = root->view().shouldDisableLayoutStateForSubtree(root);
1260            root->view().pushLayoutState(*root);
1261        }
1262        LayoutStateDisabler layoutStateDisabler(disableLayoutState ? &root->view() : 0);
1263        RenderView::RepaintRegionAccumulator repaintRegionAccumulator(&root->view());
1264
1265        ASSERT(m_layoutPhase == InPreLayout);
1266        m_layoutPhase = InLayout;
1267
1268        forceLayoutParentViewIfNeeded();
1269
1270        ASSERT(m_layoutPhase == InLayout);
1271
1272        root->layout();
1273#if ENABLE(IOS_TEXT_AUTOSIZING)
1274        float minZoomFontSize = frame().settings().minimumZoomFontSize();
1275        float visWidth = frame().page()->textAutosizingWidth();
1276        if (minZoomFontSize && visWidth && !root->view().printing()) {
1277            root->adjustComputedFontSizesOnBlocks(minZoomFontSize, visWidth);
1278            bool needsLayout = root->needsLayout();
1279            if (needsLayout)
1280                root->layout();
1281        }
1282#endif
1283#if ENABLE(TEXT_AUTOSIZING)
1284        if (document.textAutosizer()->processSubtree(root) && root->needsLayout())
1285            root->layout();
1286#endif
1287
1288        ASSERT(m_layoutPhase == InLayout);
1289
1290        if (subtree)
1291            root->view().popLayoutState(*root);
1292
1293        m_layoutRoot = 0;
1294
1295        // Close block here to end the scope of changeSchedulingEnabled and layoutStateDisabler.
1296    }
1297
1298    m_layoutPhase = InViewSizeAdjust;
1299
1300    bool neededFullRepaint = m_needsFullRepaint;
1301
1302    if (!subtree && !toRenderView(*root).printing())
1303        adjustViewSize();
1304
1305    m_layoutPhase = InPostLayout;
1306
1307    m_needsFullRepaint = neededFullRepaint;
1308
1309    // Now update the positions of all layers.
1310    if (m_needsFullRepaint)
1311        root->view().repaintRootContents();
1312
1313    layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint));
1314
1315    updateCompositingLayersAfterLayout();
1316
1317    m_layoutCount++;
1318
1319#if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL)
1320    if (AXObjectCache* cache = root->document().existingAXObjectCache())
1321        cache->postNotification(root, AXObjectCache::AXLayoutComplete);
1322#endif
1323
1324#if ENABLE(DASHBOARD_SUPPORT)
1325    updateAnnotatedRegions();
1326#endif
1327
1328#if ENABLE(IOS_TOUCH_EVENTS)
1329    document.dirtyTouchEventRects();
1330#endif
1331
1332    ASSERT(!root->needsLayout());
1333
1334    updateCanBlitOnScrollRecursively();
1335
1336    if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1337        updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
1338
1339    if (!m_postLayoutTasksTimer.isActive()) {
1340        if (!m_inSynchronousPostLayout) {
1341            if (inChildFrameLayoutWithFrameFlattening)
1342                updateWidgetPositions();
1343            else {
1344                TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1345                performPostLayoutTasks(); // Calls resumeScheduledEvents().
1346            }
1347        }
1348
1349        if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) {
1350            // If we need layout or are already in a synchronous call to postLayoutTasks(),
1351            // defer widget updates and event dispatch until after we return. postLayoutTasks()
1352            // can make us need to update again, and we can get stuck in a nasty cycle unless
1353            // we call it through the timer here.
1354            m_postLayoutTasksTimer.startOneShot(0);
1355            if (needsLayout())
1356                layout();
1357        }
1358    }
1359
1360    InspectorInstrumentation::didLayout(cookie, root);
1361
1362    --m_nestedLayoutCount;
1363}
1364
1365RenderBox* FrameView::embeddedContentBox() const
1366{
1367    RenderView* renderView = this->renderView();
1368    if (!renderView)
1369        return nullptr;
1370
1371    RenderObject* firstChild = renderView->firstChild();
1372    if (!firstChild || !firstChild->isBox())
1373        return nullptr;
1374
1375    // Curently only embedded SVG documents participate in the size-negotiation logic.
1376    if (toRenderBox(firstChild)->isSVGRoot())
1377        return toRenderBox(firstChild);
1378
1379    return nullptr;
1380}
1381
1382void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1383{
1384    if (!m_embeddedObjectsToUpdate)
1385        m_embeddedObjectsToUpdate = std::make_unique<ListHashSet<RenderEmbeddedObject*>>();
1386
1387    HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
1388    if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) {
1389        // Tell the DOM element that it needs a widget update.
1390        HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
1391        if (!pluginElement.needsCheckForSizeChange())
1392            pluginElement.setNeedsWidgetUpdate(true);
1393    }
1394
1395    m_embeddedObjectsToUpdate->add(&embeddedObject);
1396}
1397
1398void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1399{
1400    if (!m_embeddedObjectsToUpdate)
1401        return;
1402
1403    m_embeddedObjectsToUpdate->remove(&embeddedObject);
1404}
1405
1406void FrameView::setMediaType(const String& mediaType)
1407{
1408    m_mediaType = mediaType;
1409}
1410
1411String FrameView::mediaType() const
1412{
1413    // See if we have an override type.
1414    String overrideType = frame().loader().client().overrideMediaType();
1415    InspectorInstrumentation::applyEmulatedMedia(&frame(), &overrideType);
1416    if (!overrideType.isNull())
1417        return overrideType;
1418    return m_mediaType;
1419}
1420
1421void FrameView::adjustMediaTypeForPrinting(bool printing)
1422{
1423    if (printing) {
1424        if (m_mediaTypeWhenNotPrinting.isNull())
1425            m_mediaTypeWhenNotPrinting = mediaType();
1426            setMediaType("print");
1427    } else {
1428        if (!m_mediaTypeWhenNotPrinting.isNull())
1429            setMediaType(m_mediaTypeWhenNotPrinting);
1430        m_mediaTypeWhenNotPrinting = String();
1431    }
1432}
1433
1434bool FrameView::useSlowRepaints(bool considerOverlap) const
1435{
1436    bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects());
1437
1438    // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints ==
1439    // m_contentIsOpaque, so don't take the fast path for composited layers
1440    // if they are a platform widget in order to get painting correctness
1441    // for transparent layers. See the comment in WidgetMac::paint.
1442    if (contentsInCompositedLayer() && !platformWidget())
1443        return mustBeSlow;
1444
1445    bool isOverlapped = m_isOverlapped && considerOverlap;
1446
1447    if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1448        return true;
1449
1450    if (FrameView* parentView = parentFrameView())
1451        return parentView->useSlowRepaints(considerOverlap);
1452
1453    return false;
1454}
1455
1456bool FrameView::useSlowRepaintsIfNotOverlapped() const
1457{
1458    return useSlowRepaints(false);
1459}
1460
1461void FrameView::updateCanBlitOnScrollRecursively()
1462{
1463    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1464        if (FrameView* view = frame->view())
1465            view->setCanBlitOnScroll(!view->useSlowRepaints());
1466    }
1467}
1468
1469bool FrameView::contentsInCompositedLayer() const
1470{
1471    RenderView* renderView = this->renderView();
1472    if (renderView && renderView->isComposited()) {
1473        GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer();
1474        if (layer && layer->drawsContent())
1475            return true;
1476    }
1477
1478    return false;
1479}
1480
1481void FrameView::setCannotBlitToWindow()
1482{
1483    m_cannotBlitToWindow = true;
1484    updateCanBlitOnScrollRecursively();
1485}
1486
1487void FrameView::addSlowRepaintObject(RenderElement* o)
1488{
1489    bool hadSlowRepaintObjects = hasSlowRepaintObjects();
1490
1491    if (!m_slowRepaintObjects)
1492        m_slowRepaintObjects = std::make_unique<HashSet<RenderElement*>>();
1493
1494    m_slowRepaintObjects->add(o);
1495
1496    if (!hadSlowRepaintObjects) {
1497        updateCanBlitOnScrollRecursively();
1498
1499        if (Page* page = frame().page()) {
1500            if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1501                scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1502        }
1503    }
1504}
1505
1506void FrameView::removeSlowRepaintObject(RenderElement* o)
1507{
1508    if (!m_slowRepaintObjects)
1509        return;
1510
1511    m_slowRepaintObjects->remove(o);
1512    if (m_slowRepaintObjects->isEmpty()) {
1513        m_slowRepaintObjects = nullptr;
1514        updateCanBlitOnScrollRecursively();
1515
1516        if (Page* page = frame().page()) {
1517            if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1518                scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1519        }
1520    }
1521}
1522
1523void FrameView::addViewportConstrainedObject(RenderElement* object)
1524{
1525    if (!m_viewportConstrainedObjects)
1526        m_viewportConstrainedObjects = std::make_unique<ViewportConstrainedObjectSet>();
1527
1528    if (!m_viewportConstrainedObjects->contains(object)) {
1529        m_viewportConstrainedObjects->add(object);
1530        if (platformWidget())
1531            updateCanBlitOnScrollRecursively();
1532
1533        if (Page* page = frame().page()) {
1534            if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1535                scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1536        }
1537    }
1538}
1539
1540void FrameView::removeViewportConstrainedObject(RenderElement* object)
1541{
1542    if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) {
1543        if (Page* page = frame().page()) {
1544            if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1545                scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1546        }
1547
1548        // FIXME: In addFixedObject() we only call this if there's a platform widget,
1549        // why isn't the same check being made here?
1550        updateCanBlitOnScrollRecursively();
1551    }
1552}
1553
1554LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1555{
1556#if PLATFORM(IOS)
1557    if (useCustomFixedPositionLayoutRect())
1558        return customFixedPositionLayoutRect();
1559#endif
1560    LayoutRect viewportRect = visibleContentRect();
1561
1562    viewportRect.setLocation(toLayoutPoint(scrollOffsetForFixedPosition()));
1563    return viewportRect;
1564}
1565
1566LayoutSize FrameView::scrollOffsetForFixedPosition(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, const LayoutPoint& scrollPosition, const LayoutPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements behaviorForFixed, int headerHeight, int footerHeight)
1567{
1568    LayoutPoint position;
1569    if (behaviorForFixed == StickToDocumentBounds)
1570        position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight);
1571    else {
1572        position = scrollPosition;
1573        position.setY(position.y() - headerHeight);
1574    }
1575
1576    LayoutSize maxSize = totalContentsSize - visibleContentRect.size();
1577
1578    float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width();
1579    float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height();
1580
1581    return LayoutSize(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor);
1582}
1583
1584LayoutSize FrameView::scrollOffsetForFixedPosition() const
1585{
1586    IntRect visibleContentRect = this->visibleContentRect();
1587    IntSize totalContentsSize = this->totalContentsSize();
1588    IntPoint scrollPosition = this->scrollPosition();
1589    IntPoint scrollOrigin = this->scrollOrigin();
1590    float frameScaleFactor = frame().frameScaleFactor();
1591    ScrollBehaviorForFixedElements behaviorForFixed = scrollBehaviorForFixedElements();
1592    return scrollOffsetForFixedPosition(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame(), behaviorForFixed, headerHeight(), footerHeight());
1593}
1594
1595float FrameView::yPositionForInsetClipLayer(const FloatPoint& scrollPosition, float topContentInset)
1596{
1597    if (!topContentInset)
1598        return 0;
1599
1600    // The insetClipLayer should not move for negative scroll values.
1601    float scrollY = std::max<float>(0, scrollPosition.y());
1602
1603    if (scrollY >= topContentInset)
1604        return 0;
1605
1606    return topContentInset - scrollY;
1607}
1608
1609float FrameView::yPositionForHeaderLayer(const FloatPoint& scrollPosition, float topContentInset)
1610{
1611    if (!topContentInset)
1612        return 0;
1613
1614    float scrollY = std::max<float>(0, scrollPosition.y());
1615
1616    if (scrollY >= topContentInset)
1617        return topContentInset;
1618
1619    return scrollY;
1620}
1621
1622float FrameView::yPositionForRootContentLayer(const FloatPoint& scrollPosition, float topContentInset, float headerHeight)
1623{
1624    return yPositionForHeaderLayer(scrollPosition, topContentInset) + headerHeight;
1625}
1626
1627float FrameView::yPositionForFooterLayer(const FloatPoint& scrollPosition, float topContentInset, float totalContentsHeight, float footerHeight)
1628{
1629    return yPositionForHeaderLayer(scrollPosition, topContentInset) + totalContentsHeight - footerHeight;
1630}
1631
1632#if PLATFORM(IOS)
1633LayoutRect FrameView::rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements scrollBehavior)
1634{
1635    if (fixedElementsLayoutRelativeToFrame)
1636        return visibleContentRect;
1637
1638    if (totalContentsSize.isEmpty())
1639        return visibleContentRect;
1640
1641    // We impose an lower limit on the size (so an upper limit on the scale) of
1642    // the rect used to position fixed objects so that they don't crowd into the
1643    // center of the screen at larger scales.
1644    const LayoutUnit maxContentWidthForZoomThreshold = LayoutUnit::fromPixel(1024);
1645    float zoomedOutScale = frameScaleFactor * visibleContentRect.width() / std::min(maxContentWidthForZoomThreshold, totalContentsSize.width());
1646    float constraintThresholdScale = 1.5 * zoomedOutScale;
1647    float maxPostionedObjectsRectScale = std::min(frameScaleFactor, constraintThresholdScale);
1648
1649    LayoutRect viewportConstrainedObjectsRect = visibleContentRect;
1650
1651    if (frameScaleFactor > constraintThresholdScale) {
1652        FloatRect contentRect(FloatPoint(), totalContentsSize);
1653        FloatRect viewportRect = visibleContentRect;
1654
1655        // Scale the rect up from a point that is relative to its position in the viewport.
1656        FloatSize sizeDelta = contentRect.size() - viewportRect.size();
1657
1658        FloatPoint scaleOrigin;
1659        scaleOrigin.setX(contentRect.x() + sizeDelta.width() > 0 ? contentRect.width() * (viewportRect.x() - contentRect.x()) / sizeDelta.width() : 0);
1660        scaleOrigin.setY(contentRect.y() + sizeDelta.height() > 0 ? contentRect.height() * (viewportRect.y() - contentRect.y()) / sizeDelta.height() : 0);
1661
1662        AffineTransform rescaleTransform = AffineTransform::translation(scaleOrigin.x(), scaleOrigin.y());
1663        rescaleTransform.scale(frameScaleFactor / maxPostionedObjectsRectScale, frameScaleFactor / maxPostionedObjectsRectScale);
1664        rescaleTransform = CGAffineTransformTranslate(rescaleTransform, -scaleOrigin.x(), -scaleOrigin.y());
1665
1666        viewportConstrainedObjectsRect = enclosingLayoutRect(rescaleTransform.mapRect(visibleContentRect));
1667    }
1668
1669    if (scrollBehavior == StickToDocumentBounds) {
1670        LayoutRect documentBounds(LayoutPoint(), totalContentsSize);
1671        viewportConstrainedObjectsRect.intersect(documentBounds);
1672    }
1673
1674    return viewportConstrainedObjectsRect;
1675}
1676
1677LayoutRect FrameView::viewportConstrainedObjectsRect() const
1678{
1679    return rectForViewportConstrainedObjects(visibleContentRect(), totalContentsSize(), frame().frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements());
1680}
1681#endif
1682
1683IntPoint FrameView::minimumScrollPosition() const
1684{
1685    IntPoint minimumPosition(ScrollView::minimumScrollPosition());
1686
1687    if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
1688        minimumPosition.setY(maximumScrollPosition().y());
1689
1690    return minimumPosition;
1691}
1692
1693IntPoint FrameView::maximumScrollPosition() const
1694{
1695    IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
1696
1697    maximumOffset.clampNegativeToZero();
1698
1699    if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
1700        maximumOffset.setY(minimumScrollPosition().y());
1701
1702    return maximumOffset;
1703}
1704
1705void FrameView::delayedScrollEventTimerFired(Timer<FrameView>&)
1706{
1707    sendScrollEvent();
1708}
1709
1710bool FrameView::fixedElementsLayoutRelativeToFrame() const
1711{
1712    return frame().settings().fixedElementsLayoutRelativeToFrame();
1713}
1714
1715IntPoint FrameView::lastKnownMousePosition() const
1716{
1717    return frame().eventHandler().lastKnownMousePosition();
1718}
1719
1720bool FrameView::isHandlingWheelEvent() const
1721{
1722    return frame().eventHandler().isHandlingWheelEvent();
1723}
1724
1725bool FrameView::shouldSetCursor() const
1726{
1727    Page* page = frame().page();
1728    return page && page->isVisible() && page->focusController().isActive();
1729}
1730
1731bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1732{
1733    if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1734        hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1735        return true;
1736    }
1737
1738    const bool isCompositedContentLayer = contentsInCompositedLayer();
1739
1740    // Get the rects of the fixed objects visible in the rectToScroll
1741    Region regionToUpdate;
1742    for (auto& renderer : *m_viewportConstrainedObjects) {
1743        if (!renderer->style().hasViewportConstrainedPosition())
1744            continue;
1745        if (renderer->isComposited())
1746            continue;
1747
1748        // Fixed items should always have layers.
1749        ASSERT(renderer->hasLayer());
1750        RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1751
1752        if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1753            || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1754            // Don't invalidate for invisible fixed layers.
1755            continue;
1756        }
1757
1758#if ENABLE(CSS_FILTERS)
1759        if (layer->hasAncestorWithFilterOutsets()) {
1760            // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1761            // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1762            return false;
1763        }
1764#endif
1765        IntRect updateRect = pixelSnappedIntRect(layer->repaintRectIncludingNonCompositingDescendants());
1766        updateRect = contentsToRootView(updateRect);
1767        if (!isCompositedContentLayer && clipsRepaints())
1768            updateRect.intersect(rectToScroll);
1769        if (!updateRect.isEmpty())
1770            regionToUpdate.unite(updateRect);
1771    }
1772
1773    // 1) scroll
1774    hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1775
1776    // 2) update the area of fixed objects that has been invalidated
1777    Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1778    size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1779    for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1780        IntRect updateRect = subRectsToUpdate[i];
1781        IntRect scrolledRect = updateRect;
1782        scrolledRect.move(scrollDelta);
1783        updateRect.unite(scrolledRect);
1784        if (isCompositedContentLayer) {
1785            updateRect = rootViewToContents(updateRect);
1786            ASSERT(renderView());
1787            renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
1788            continue;
1789        }
1790        if (clipsRepaints())
1791            updateRect.intersect(rectToScroll);
1792        hostWindow()->invalidateContentsAndRootView(updateRect);
1793    }
1794
1795    return true;
1796}
1797
1798void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1799{
1800    if (contentsInCompositedLayer()) {
1801        // FIXME: respect paintsEntireContents()?
1802        IntRect updateRect = visibleContentRect(LegacyIOSDocumentVisibleRect);
1803
1804        // Make sure to "apply" the scale factor here since we're converting from frame view
1805        // coordinates to layer backing coordinates.
1806        updateRect.scale(1 / frame().frameScaleFactor());
1807
1808        ASSERT(renderView());
1809        renderView()->layer()->setBackingNeedsRepaintInRect(updateRect, GraphicsLayer::DoNotClipToLayer);
1810    }
1811
1812    repaintSlowRepaintObjects();
1813
1814    if (RenderWidget* frameRenderer = frame().ownerRenderer()) {
1815        if (isEnclosedInCompositingLayer()) {
1816            LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1817                            frameRenderer->borderTop() + frameRenderer->paddingTop(),
1818                            visibleWidth(), visibleHeight());
1819            frameRenderer->repaintRectangle(rect);
1820            return;
1821        }
1822    }
1823
1824    ScrollView::scrollContentsSlowPath(updateRect);
1825}
1826
1827void FrameView::repaintSlowRepaintObjects()
1828{
1829    if (!m_slowRepaintObjects)
1830        return;
1831
1832    // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly
1833    // repaint them after scrolling.
1834    for (auto& renderer : *m_slowRepaintObjects)
1835        renderer->repaintSlowRepaintObject();
1836}
1837
1838// Note that this gets called at painting time.
1839void FrameView::setIsOverlapped(bool isOverlapped)
1840{
1841    if (isOverlapped == m_isOverlapped)
1842        return;
1843
1844    m_isOverlapped = isOverlapped;
1845    updateCanBlitOnScrollRecursively();
1846
1847    if (hasCompositedContentIncludingDescendants()) {
1848        // Overlap can affect compositing tests, so if it changes, we need to trigger
1849        // a layer update in the parent document.
1850        if (Frame* parentFrame = frame().tree().parent()) {
1851            if (RenderView* parentView = parentFrame->contentRenderer()) {
1852                RenderLayerCompositor& compositor = parentView->compositor();
1853                compositor.setCompositingLayersNeedRebuild();
1854                compositor.scheduleCompositingLayerUpdate();
1855            }
1856        }
1857
1858        if (RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) {
1859            // We also need to trigger reevaluation for this and all descendant frames,
1860            // since a frame uses compositing if any ancestor is compositing.
1861            for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1862                if (RenderView* view = frame->contentRenderer()) {
1863                    RenderLayerCompositor& compositor = view->compositor();
1864                    compositor.setCompositingLayersNeedRebuild();
1865                    compositor.scheduleCompositingLayerUpdate();
1866                }
1867            }
1868        }
1869    }
1870}
1871
1872bool FrameView::isOverlappedIncludingAncestors() const
1873{
1874    if (isOverlapped())
1875        return true;
1876
1877    if (FrameView* parentView = parentFrameView()) {
1878        if (parentView->isOverlapped())
1879            return true;
1880    }
1881
1882    return false;
1883}
1884
1885void FrameView::setContentIsOpaque(bool contentIsOpaque)
1886{
1887    if (contentIsOpaque == m_contentIsOpaque)
1888        return;
1889
1890    m_contentIsOpaque = contentIsOpaque;
1891    updateCanBlitOnScrollRecursively();
1892}
1893
1894void FrameView::restoreScrollbar()
1895{
1896    setScrollbarsSuppressed(false);
1897}
1898
1899bool FrameView::scrollToFragment(const URL& url)
1900{
1901    // If our URL has no ref, then we have no place we need to jump to.
1902    // OTOH If CSS target was set previously, we want to set it to 0, recalc
1903    // and possibly repaint because :target pseudo class may have been
1904    // set (see bug 11321).
1905    if (!url.hasFragmentIdentifier() && !frame().document()->cssTarget())
1906        return false;
1907
1908    String fragmentIdentifier = url.fragmentIdentifier();
1909    if (scrollToAnchor(fragmentIdentifier))
1910        return true;
1911
1912    // Try again after decoding the ref, based on the document's encoding.
1913    if (TextResourceDecoder* decoder = frame().document()->decoder())
1914        return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
1915
1916    return false;
1917}
1918
1919bool FrameView::scrollToAnchor(const String& name)
1920{
1921    ASSERT(frame().document());
1922
1923    if (!frame().document()->haveStylesheetsLoaded()) {
1924        frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1925        return false;
1926    }
1927
1928    frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1929
1930    Element* anchorElement = frame().document()->findAnchor(name);
1931
1932    // Setting to null will clear the current target.
1933    frame().document()->setCSSTarget(anchorElement);
1934
1935    if (frame().document()->isSVGDocument()) {
1936        if (SVGSVGElement* svg = toSVGDocument(frame().document())->rootElement()) {
1937            svg->setupInitialView(name, anchorElement);
1938            if (!anchorElement)
1939                return true;
1940        }
1941    }
1942
1943    // Implement the rule that "" and "top" both mean top of page as in other browsers.
1944    if (!anchorElement && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1945        return false;
1946
1947    maintainScrollPositionAtAnchor(anchorElement ? static_cast<Node*>(anchorElement) : frame().document());
1948
1949    // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1950    if (anchorElement && anchorElement->isFocusable())
1951        frame().document()->setFocusedElement(anchorElement);
1952
1953    return true;
1954}
1955
1956void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1957{
1958    m_maintainScrollPositionAnchor = anchorNode;
1959    if (!m_maintainScrollPositionAnchor)
1960        return;
1961
1962    // We need to update the layout before scrolling, otherwise we could
1963    // really mess things up if an anchor scroll comes at a bad moment.
1964    frame().document()->updateStyleIfNeeded();
1965    // Only do a layout if changes have occurred that make it necessary.
1966    RenderView* renderView = this->renderView();
1967    if (renderView && renderView->needsLayout())
1968        layout();
1969    else
1970        scrollToAnchor();
1971}
1972
1973void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1974{
1975    frame().document()->updateLayoutIgnorePendingStylesheets();
1976
1977    LayoutRect bounds = element->boundingBox();
1978    int centeringOffsetX = (rect.width() - bounds.width()) / 2;
1979    int centeringOffsetY = (rect.height() - bounds.height()) / 2;
1980    setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
1981}
1982
1983void FrameView::setScrollPosition(const IntPoint& scrollPoint)
1984{
1985    TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1986    m_maintainScrollPositionAnchor = 0;
1987    ScrollView::setScrollPosition(scrollPoint);
1988}
1989
1990void FrameView::delegatesScrollingDidChange()
1991{
1992    // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor.
1993    if (hasCompositedContent())
1994        clearBackingStores();
1995}
1996
1997#if USE(TILED_BACKING_STORE)
1998void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
1999{
2000    bool visibleContentSizeDidChange = false;
2001    if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) {
2002        // When the viewport size changes or the content is scaled, we need to
2003        // reposition the fixed and sticky positioned elements.
2004        setViewportConstrainedObjectsNeedLayout();
2005        visibleContentSizeDidChange = true;
2006    }
2007
2008    IntSize offset = scrollOffset();
2009    IntPoint oldPosition = scrollPosition();
2010    ScrollView::setFixedVisibleContentRect(visibleContentRect);
2011    if (offset != scrollOffset()) {
2012        updateLayerPositionsAfterScrolling();
2013        if (frame().page()->settings().acceleratedCompositingForFixedPositionEnabled())
2014            updateCompositingLayersAfterScrolling();
2015        IntPoint newPosition = scrollPosition();
2016        scrollAnimator()->setCurrentPosition(scrollPosition());
2017        scrollPositionChanged(oldPosition, newPosition);
2018    }
2019    if (visibleContentSizeDidChange) {
2020        // Update the scroll-bars to calculate new page-step size.
2021        updateScrollbars(scrollOffset());
2022    }
2023    frame().loader().client().didChangeScrollOffset();
2024}
2025#endif
2026
2027void FrameView::setViewportConstrainedObjectsNeedLayout()
2028{
2029    if (!hasViewportConstrainedObjects())
2030        return;
2031
2032    for (auto& renderer : *m_viewportConstrainedObjects)
2033        renderer->setNeedsLayout();
2034}
2035
2036void FrameView::scrollPositionChangedViaPlatformWidget(const IntPoint& oldPosition, const IntPoint& newPosition)
2037{
2038    updateLayerPositionsAfterScrolling();
2039    updateCompositingLayersAfterScrolling();
2040    repaintSlowRepaintObjects();
2041    scrollPositionChanged(oldPosition, newPosition);
2042}
2043
2044void FrameView::scrollPositionChanged(const IntPoint& oldPosition, const IntPoint& newPosition)
2045{
2046    std::chrono::milliseconds throttlingDelay = frame().page()->chrome().client().eventThrottlingDelay();
2047
2048    if (throttlingDelay == std::chrono::milliseconds::zero()) {
2049        m_delayedScrollEventTimer.stop();
2050        sendScrollEvent();
2051    } else if (!m_delayedScrollEventTimer.isActive())
2052        m_delayedScrollEventTimer.startOneShot(throttlingDelay);
2053
2054    if (Document* document = frame().document())
2055        document->sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize());
2056
2057    if (RenderView* renderView = this->renderView()) {
2058        if (renderView->usesCompositing())
2059            renderView->compositor().frameViewDidScroll();
2060    }
2061
2062    resumeVisibleImageAnimationsIncludingSubframes();
2063}
2064
2065void FrameView::resumeVisibleImageAnimationsIncludingSubframes()
2066{
2067    // A change in scroll position may affect image visibility in subframes.
2068    for (auto* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2069        if (auto* renderView = frame->contentRenderer())
2070            renderView->resumePausedImageAnimationsIfNeeded();
2071    }
2072}
2073
2074void FrameView::updateLayerPositionsAfterScrolling()
2075{
2076    // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
2077    if (m_layoutPhase == InViewSizeAdjust)
2078        return;
2079
2080    if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2081        if (RenderView* renderView = this->renderView()) {
2082            updateWidgetPositions();
2083            renderView->layer()->updateLayerPositionsAfterDocumentScroll();
2084        }
2085    }
2086}
2087
2088bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const
2089{
2090#if ENABLE(ASYNC_SCROLLING)
2091    // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
2092
2093    Page* page = frame().page();
2094    if (!page)
2095        return true;
2096
2097    if (&page->mainFrame() != &frame())
2098        return true;
2099
2100    ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
2101    if (!scrollingCoordinator)
2102        return true;
2103
2104    if (!scrollingCoordinator->supportsFixedPositionLayers())
2105        return true;
2106
2107    if (scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2108        return true;
2109
2110    if (inProgrammaticScroll())
2111        return true;
2112
2113    return false;
2114#endif
2115    return true;
2116}
2117
2118void FrameView::updateCompositingLayersAfterScrolling()
2119{
2120    if (!shouldUpdateCompositingLayersAfterScrolling())
2121        return;
2122
2123    if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2124        if (RenderView* renderView = this->renderView())
2125            renderView->compositor().updateCompositingLayers(CompositingUpdateOnScroll);
2126    }
2127}
2128
2129bool FrameView::isRubberBandInProgress() const
2130{
2131    if (scrollbarsSuppressed())
2132        return false;
2133
2134    // If the scrolling thread updates the scroll position for this FrameView, then we should return
2135    // ScrollingCoordinator::isRubberBandInProgress().
2136    if (Page* page = frame().page()) {
2137        if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
2138            if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2139                return scrollingCoordinator->isRubberBandInProgress();
2140        }
2141    }
2142
2143    // If the main thread updates the scroll position for this FrameView, we should return
2144    // ScrollAnimator::isRubberBandInProgress().
2145    if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
2146        return scrollAnimator->isRubberBandInProgress();
2147
2148    return false;
2149}
2150
2151bool FrameView::requestScrollPositionUpdate(const IntPoint& position)
2152{
2153#if ENABLE(ASYNC_SCROLLING)
2154    if (TiledBacking* tiledBacking = this->tiledBacking())
2155        tiledBacking->prepopulateRect(FloatRect(position, visibleContentRect().size()));
2156
2157    if (Page* page = frame().page()) {
2158        if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2159            return scrollingCoordinator->requestScrollPositionUpdate(this, position);
2160    }
2161#else
2162    UNUSED_PARAM(position);
2163#endif
2164
2165    return false;
2166}
2167
2168HostWindow* FrameView::hostWindow() const
2169{
2170    if (Page* page = frame().page())
2171        return &page->chrome();
2172    return 0;
2173}
2174
2175void FrameView::addTrackedRepaintRect(const FloatRect& r)
2176{
2177    if (!m_isTrackingRepaints || r.isEmpty())
2178        return;
2179
2180    FloatRect repaintRect = r;
2181    repaintRect.move(-scrollOffset());
2182    m_trackedRepaintRects.append(repaintRect);
2183}
2184
2185void FrameView::repaintContentRectangle(const IntRect& r)
2186{
2187    ASSERT(!frame().ownerElement());
2188
2189    if (!shouldUpdate())
2190        return;
2191
2192    ScrollView::repaintContentRectangle(r);
2193}
2194
2195static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderObject& renderer, unsigned countSoFar, unsigned threshold)
2196{
2197    // FIXME: Consider writing this using RenderObject::nextInPreOrder() instead of using recursion.
2198    if (renderer.isText())
2199        countSoFar += toRenderText(renderer).text()->length();
2200
2201    for (RenderObject* child = renderer.firstChildSlow(); child; child = child->nextSibling()) {
2202        if (countSoFar >= threshold)
2203            break;
2204        countSoFar = countRenderedCharactersInRenderObjectWithThreshold(*child, countSoFar, threshold);
2205    }
2206    return countSoFar;
2207}
2208
2209bool FrameView::renderedCharactersExceed(unsigned threshold)
2210{
2211    if (!m_frame->contentRenderer())
2212        return false;
2213    return countRenderedCharactersInRenderObjectWithThreshold(*m_frame->contentRenderer(), 0, threshold) >= threshold;
2214}
2215
2216void FrameView::contentsResized()
2217{
2218    ScrollView::contentsResized();
2219    setNeedsLayout();
2220}
2221
2222void FrameView::fixedLayoutSizeChanged()
2223{
2224    // Can be triggered before the view is set, see comment in FrameView::visibleContentsResized().
2225    // An ASSERT is triggered when a view schedules a layout before being attached to a frame.
2226    if (!frame().view())
2227        return;
2228    ScrollView::fixedLayoutSizeChanged();
2229}
2230
2231bool FrameView::shouldLayoutAfterContentsResized() const
2232{
2233    return !useFixedLayout() || useCustomFixedPositionLayoutRect();
2234}
2235
2236void FrameView::visibleContentsResized()
2237{
2238    // We check to make sure the view is attached to a frame() as this method can
2239    // be triggered before the view is attached by Frame::createView(...) setting
2240    // various values such as setScrollBarModes(...) for example.  An ASSERT is
2241    // triggered when a view is layout before being attached to a frame().
2242    if (!frame().view())
2243        return;
2244
2245#if PLATFORM(IOS)
2246    if (RenderView* root = m_frame->contentRenderer()) {
2247        if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) {
2248            setViewportConstrainedObjectsNeedLayout();
2249            // We must eagerly enter compositing mode because fixed position elements
2250            // will not have been made compositing via a preceding style change before
2251            // m_useCustomFixedPositionLayoutRect was true.
2252            root->compositor().enableCompositingMode();
2253        }
2254    }
2255#endif
2256
2257    if (shouldLayoutAfterContentsResized() && needsLayout())
2258        layout();
2259
2260    if (RenderView* renderView = this->renderView()) {
2261        if (renderView->usesCompositing())
2262            renderView->compositor().frameViewDidChangeSize();
2263    }
2264}
2265
2266void FrameView::addedOrRemovedScrollbar()
2267{
2268    if (RenderView* renderView = this->renderView()) {
2269        if (renderView->usesCompositing())
2270            renderView->compositor().frameViewDidAddOrRemoveScrollbars();
2271    }
2272}
2273
2274static LayerFlushThrottleState::Flags determineLayerFlushThrottleState(Page& page)
2275{
2276    // We only throttle when constantly receiving new data during the inital page load.
2277    if (!page.progress().isMainLoadProgressing())
2278        return 0;
2279    // Scrolling during page loading disables throttling.
2280    if (page.mainFrame().view()->wasScrolledByUser())
2281        return 0;
2282    // Disable for image documents so large GIF animations don't get throttled during loading.
2283    auto* document = page.mainFrame().document();
2284    if (!document || isImageDocument(*document))
2285        return 0;
2286    return LayerFlushThrottleState::Enabled;
2287}
2288
2289void FrameView::disableLayerFlushThrottlingTemporarilyForInteraction()
2290{
2291    if (!frame().page())
2292        return;
2293    auto& page = *frame().page();
2294
2295    LayerFlushThrottleState::Flags flags = LayerFlushThrottleState::UserIsInteracting | determineLayerFlushThrottleState(page);
2296    if (page.chrome().client().adjustLayerFlushThrottling(flags))
2297        return;
2298
2299    if (RenderView* view = renderView())
2300        view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction();
2301}
2302
2303void FrameView::loadProgressingStatusChanged()
2304{
2305    updateLayerFlushThrottling();
2306    adjustTiledBackingCoverage();
2307}
2308
2309void FrameView::updateLayerFlushThrottling()
2310{
2311    ASSERT(frame().isMainFrame());
2312    auto& page = *frame().page();
2313
2314    LayerFlushThrottleState::Flags flags = determineLayerFlushThrottleState(page);
2315
2316    // See if the client is handling throttling.
2317    if (page.chrome().client().adjustLayerFlushThrottling(flags))
2318        return;
2319
2320    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2321        if (RenderView* renderView = frame->contentRenderer())
2322            renderView->compositor().setLayerFlushThrottlingEnabled(flags & LayerFlushThrottleState::Enabled);
2323    }
2324}
2325
2326void FrameView::adjustTiledBackingCoverage()
2327{
2328    if (!m_speculativeTilingEnabled)
2329        enableSpeculativeTilingIfNeeded();
2330
2331    RenderView* renderView = this->renderView();
2332    if (renderView && renderView->layer()->backing())
2333        renderView->layer()->backing()->adjustTiledBackingCoverage();
2334#if PLATFORM(IOS)
2335    if (LegacyTileCache* tileCache = legacyTileCache())
2336        tileCache->setSpeculativeTileCreationEnabled(m_speculativeTilingEnabled);
2337#endif
2338}
2339
2340static bool shouldEnableSpeculativeTilingDuringLoading(const FrameView& view)
2341{
2342    return view.isVisuallyNonEmpty() && !view.frame().page()->progress().isMainLoadProgressing();
2343}
2344
2345void FrameView::enableSpeculativeTilingIfNeeded()
2346{
2347    ASSERT(!m_speculativeTilingEnabled);
2348    if (m_wasScrolledByUser) {
2349        m_speculativeTilingEnabled = true;
2350        return;
2351    }
2352    if (!shouldEnableSpeculativeTilingDuringLoading(*this))
2353        return;
2354    if (m_speculativeTilingEnableTimer.isActive())
2355        return;
2356    // Delay enabling a bit as load completion may trigger further loading from scripts.
2357    static const double speculativeTilingEnableDelay = 0.5;
2358    m_speculativeTilingEnableTimer.startOneShot(speculativeTilingEnableDelay);
2359}
2360
2361void FrameView::speculativeTilingEnableTimerFired(Timer<FrameView>&)
2362{
2363    if (m_speculativeTilingEnabled)
2364        return;
2365    m_speculativeTilingEnabled = shouldEnableSpeculativeTilingDuringLoading(*this);
2366    adjustTiledBackingCoverage();
2367}
2368
2369void FrameView::layoutTimerFired(Timer<FrameView>&)
2370{
2371#ifdef INSTRUMENT_LAYOUT_SCHEDULING
2372    if (!frame().document()->ownerElement())
2373        printf("Layout timer fired at %lld\n", frame().document()->elapsedTime().count());
2374#endif
2375    layout();
2376}
2377
2378void FrameView::scheduleRelayout()
2379{
2380    // FIXME: We should assert the page is not in the page cache, but that is causing
2381    // too many false assertions.  See <rdar://problem/7218118>.
2382    ASSERT(frame().view() == this);
2383
2384    if (m_layoutRoot) {
2385        m_layoutRoot->markContainingBlocksForLayout(false);
2386        m_layoutRoot = 0;
2387    }
2388    if (!m_layoutSchedulingEnabled)
2389        return;
2390    if (!needsLayout())
2391        return;
2392    if (!frame().document()->shouldScheduleLayout())
2393        return;
2394    InspectorInstrumentation::didInvalidateLayout(&frame());
2395    // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
2396    // Also invalidate parent frame starting from the owner element of this frame.
2397    if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening())
2398        frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
2399
2400    std::chrono::milliseconds delay = frame().document()->minimumLayoutDelay();
2401    if (m_layoutTimer.isActive() && m_delayedLayout && !delay.count())
2402        unscheduleRelayout();
2403    if (m_layoutTimer.isActive())
2404        return;
2405
2406    m_delayedLayout = delay.count();
2407
2408#ifdef INSTRUMENT_LAYOUT_SCHEDULING
2409    if (!frame().document()->ownerElement())
2410        printf("Scheduling layout for %d\n", delay);
2411#endif
2412
2413    m_layoutTimer.startOneShot(delay);
2414}
2415
2416static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
2417{
2418    for (RenderObject* r = descendant; r; r = r->container()) {
2419        if (r == ancestor)
2420            return true;
2421    }
2422    return false;
2423}
2424
2425void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot)
2426{
2427    ASSERT(renderView());
2428    RenderView& renderView = *this->renderView();
2429
2430    // Try to catch unnecessary work during render tree teardown.
2431    ASSERT(!renderView.documentBeingDestroyed());
2432    ASSERT(frame().view() == this);
2433
2434    if (renderView.needsLayout()) {
2435        newRelayoutRoot.markContainingBlocksForLayout(false);
2436        return;
2437    }
2438
2439    if (!layoutPending() && m_layoutSchedulingEnabled) {
2440        std::chrono::milliseconds delay = renderView.document().minimumLayoutDelay();
2441        ASSERT(!newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout());
2442        m_layoutRoot = &newRelayoutRoot;
2443        InspectorInstrumentation::didInvalidateLayout(&frame());
2444        m_delayedLayout = delay.count();
2445        m_layoutTimer.startOneShot(delay);
2446        return;
2447    }
2448
2449    if (m_layoutRoot == &newRelayoutRoot)
2450        return;
2451
2452    if (!m_layoutRoot) {
2453        // Just relayout the subtree.
2454        newRelayoutRoot.markContainingBlocksForLayout(false);
2455        InspectorInstrumentation::didInvalidateLayout(&frame());
2456        return;
2457    }
2458
2459    if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) {
2460        // Keep the current root.
2461        newRelayoutRoot.markContainingBlocksForLayout(false, m_layoutRoot);
2462        ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2463        return;
2464    }
2465
2466    if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) {
2467        // Re-root at newRelayoutRoot.
2468        m_layoutRoot->markContainingBlocksForLayout(false, &newRelayoutRoot);
2469        m_layoutRoot = &newRelayoutRoot;
2470        ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2471        InspectorInstrumentation::didInvalidateLayout(&frame());
2472        return;
2473    }
2474
2475    // Just do a full relayout.
2476    m_layoutRoot->markContainingBlocksForLayout(false);
2477    m_layoutRoot = 0;
2478    newRelayoutRoot.markContainingBlocksForLayout(false);
2479    InspectorInstrumentation::didInvalidateLayout(&frame());
2480}
2481
2482bool FrameView::layoutPending() const
2483{
2484    return m_layoutTimer.isActive();
2485}
2486
2487bool FrameView::needsLayout() const
2488{
2489    // This can return true in cases where the document does not have a body yet.
2490    // Document::shouldScheduleLayout takes care of preventing us from scheduling
2491    // layout in that case.
2492    RenderView* renderView = this->renderView();
2493    return layoutPending()
2494        || (renderView && renderView->needsLayout())
2495        || m_layoutRoot
2496        || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred);
2497}
2498
2499void FrameView::setNeedsLayout()
2500{
2501    if (m_deferSetNeedsLayouts) {
2502        m_setNeedsLayoutWasDeferred = true;
2503        return;
2504    }
2505
2506    if (RenderView* renderView = this->renderView())
2507        renderView->setNeedsLayout();
2508}
2509
2510void FrameView::unscheduleRelayout()
2511{
2512    if (!m_layoutTimer.isActive())
2513        return;
2514
2515#ifdef INSTRUMENT_LAYOUT_SCHEDULING
2516    if (!frame().document()->ownerElement())
2517        printf("Layout timer unscheduled at %d\n", frame().document()->elapsedTime());
2518#endif
2519
2520    m_layoutTimer.stop();
2521    m_delayedLayout = false;
2522}
2523
2524#if ENABLE(REQUEST_ANIMATION_FRAME)
2525void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime)
2526{
2527    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) {
2528        frame->view()->serviceScrollAnimations();
2529        frame->animation().serviceAnimations();
2530    }
2531
2532    Vector<RefPtr<Document>> documents;
2533    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext())
2534        documents.append(frame->document());
2535
2536    for (size_t i = 0; i < documents.size(); ++i)
2537        documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime);
2538}
2539#endif
2540
2541bool FrameView::isTransparent() const
2542{
2543    return m_isTransparent;
2544}
2545
2546void FrameView::setTransparent(bool isTransparent)
2547{
2548    if (m_isTransparent == isTransparent)
2549        return;
2550
2551    m_isTransparent = isTransparent;
2552
2553    RenderView* renderView = this->renderView();
2554    if (!renderView)
2555        return;
2556
2557    RenderLayerCompositor& compositor = renderView->compositor();
2558    compositor.setCompositingLayersNeedRebuild();
2559    compositor.scheduleCompositingLayerUpdate();
2560}
2561
2562bool FrameView::hasOpaqueBackground() const
2563{
2564    return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
2565}
2566
2567Color FrameView::baseBackgroundColor() const
2568{
2569    return m_baseBackgroundColor;
2570}
2571
2572void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
2573{
2574    if (!backgroundColor.isValid())
2575        m_baseBackgroundColor = Color::white;
2576    else
2577        m_baseBackgroundColor = backgroundColor;
2578
2579    recalculateScrollbarOverlayStyle();
2580}
2581
2582void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
2583{
2584    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2585        if (FrameView* view = frame->view()) {
2586            view->setTransparent(transparent);
2587            view->setBaseBackgroundColor(backgroundColor);
2588        }
2589    }
2590}
2591
2592bool FrameView::hasExtendedBackgroundRectForPainting() const
2593{
2594    if (!frame().settings().backgroundShouldExtendBeyondPage())
2595        return false;
2596
2597    TiledBacking* tiledBacking = this->tiledBacking();
2598    if (!tiledBacking)
2599        return false;
2600
2601    return tiledBacking->hasMargins();
2602}
2603
2604void FrameView::updateExtendBackgroundIfNecessary()
2605{
2606    ExtendedBackgroundMode mode = calculateExtendedBackgroundMode();
2607    if (mode == ExtendedBackgroundModeNone)
2608        return;
2609
2610    updateTilesForExtendedBackgroundMode(mode);
2611}
2612
2613FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() const
2614{
2615    // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
2616    // that the background rect needs to be extended for painting. Simple backgrounds can be extended
2617    // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
2618    // such as images, require extending the background rect to continue painting into the extended
2619    // region. This function finds out if it is necessary to extend the background rect for painting.
2620
2621#if PLATFORM(IOS)
2622    // <rdar://problem/16201373>
2623    return ExtendedBackgroundModeNone;
2624#endif
2625
2626    if (!frame().settings().backgroundShouldExtendBeyondPage())
2627        return ExtendedBackgroundModeNone;
2628
2629    if (!frame().isMainFrame())
2630        return ExtendedBackgroundModeNone;
2631
2632    Document* document = frame().document();
2633    if (!document)
2634        return ExtendedBackgroundModeNone;
2635
2636    auto documentElement = document->documentElement();
2637    auto documentElementRenderer = documentElement ? documentElement->renderer() : nullptr;
2638    if (!documentElementRenderer)
2639        return ExtendedBackgroundModeNone;
2640
2641    auto& renderer = documentElementRenderer->rendererForRootBackground();
2642    if (!renderer.style().hasBackgroundImage())
2643        return ExtendedBackgroundModeNone;
2644
2645    ExtendedBackgroundMode mode = ExtendedBackgroundModeNone;
2646
2647    if (renderer.style().backgroundRepeatX() == RepeatFill)
2648        mode |= ExtendedBackgroundModeHorizontal;
2649    if (renderer.style().backgroundRepeatY() == RepeatFill)
2650        mode |= ExtendedBackgroundModeVertical;
2651
2652    return mode;
2653}
2654
2655void FrameView::updateTilesForExtendedBackgroundMode(ExtendedBackgroundMode mode)
2656{
2657    if (!frame().settings().backgroundShouldExtendBeyondPage())
2658        return;
2659
2660    RenderView* renderView = this->renderView();
2661    if (!renderView)
2662        return;
2663
2664    RenderLayerBacking* backing = renderView->layer()->backing();
2665    if (!backing)
2666        return;
2667
2668    TiledBacking* tiledBacking = backing->graphicsLayer()->tiledBacking();
2669    if (!tiledBacking)
2670        return;
2671
2672    ExtendedBackgroundMode existingMode = ExtendedBackgroundModeNone;
2673    if (tiledBacking->hasVerticalMargins())
2674        existingMode |= ExtendedBackgroundModeVertical;
2675    if (tiledBacking->hasHorizontalMargins())
2676        existingMode |= ExtendedBackgroundModeHorizontal;
2677
2678    if (existingMode == mode)
2679        return;
2680
2681    renderView->compositor().setRootExtendedBackgroundColor(mode == ExtendedBackgroundModeAll ? Color() : documentBackgroundColor());
2682    backing->setTiledBackingHasMargins(mode & ExtendedBackgroundModeHorizontal, mode & ExtendedBackgroundModeVertical);
2683}
2684
2685IntRect FrameView::extendedBackgroundRectForPainting() const
2686{
2687    TiledBacking* tiledBacking = this->tiledBacking();
2688    if (!tiledBacking)
2689        return IntRect();
2690
2691    RenderView* renderView = this->renderView();
2692    if (!renderView)
2693        return IntRect();
2694
2695    LayoutRect extendedRect = renderView->unextendedBackgroundRect(renderView);
2696    if (!tiledBacking->hasMargins())
2697        return pixelSnappedIntRect(extendedRect);
2698
2699    extendedRect.moveBy(LayoutPoint(-tiledBacking->leftMarginWidth(), -tiledBacking->topMarginHeight()));
2700    extendedRect.expand(LayoutSize(tiledBacking->leftMarginWidth() + tiledBacking->rightMarginWidth(), tiledBacking->topMarginHeight() + tiledBacking->bottomMarginHeight()));
2701    return pixelSnappedIntRect(extendedRect);
2702}
2703
2704bool FrameView::shouldUpdateWhileOffscreen() const
2705{
2706    return m_shouldUpdateWhileOffscreen;
2707}
2708
2709void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
2710{
2711    m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
2712}
2713
2714bool FrameView::shouldUpdate() const
2715{
2716    if (isOffscreen() && !shouldUpdateWhileOffscreen())
2717        return false;
2718    return true;
2719}
2720
2721void FrameView::scrollToAnchor()
2722{
2723    RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
2724    if (!anchorNode)
2725        return;
2726
2727    if (!anchorNode->renderer())
2728        return;
2729
2730    LayoutRect rect;
2731    if (anchorNode != frame().document())
2732        rect = anchorNode->boundingBox();
2733
2734    // Scroll nested layers and frames to reveal the anchor.
2735    // Align to the top and to the closest side (this matches other browsers).
2736    anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
2737
2738    if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
2739        cache->handleScrolledToAnchor(anchorNode.get());
2740
2741    // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
2742    m_maintainScrollPositionAnchor = anchorNode;
2743}
2744
2745void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject)
2746{
2747    // No need to update if it's already crashed or known to be missing.
2748    if (embeddedObject.isPluginUnavailable())
2749        return;
2750
2751    HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
2752
2753    if (embeddedObject.isSnapshottedPlugIn()) {
2754        if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) {
2755            HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
2756            pluginElement.checkSnapshotStatus();
2757        }
2758        return;
2759    }
2760
2761    auto weakRenderer = embeddedObject.createWeakPtr();
2762
2763    // FIXME: This could turn into a real virtual dispatch if we defined
2764    // updateWidget(PluginCreationOption) on HTMLElement.
2765    if (isHTMLObjectElement(element) || isHTMLEmbedElement(element) || isHTMLAppletElement(element)) {
2766        HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
2767        if (pluginElement.needsCheckForSizeChange()) {
2768            pluginElement.checkSnapshotStatus();
2769            return;
2770        }
2771        if (pluginElement.needsWidgetUpdate())
2772            pluginElement.updateWidget(CreateAnyWidgetType);
2773    } else
2774        ASSERT_NOT_REACHED();
2775
2776    // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript.
2777    if (!weakRenderer)
2778        return;
2779
2780    embeddedObject.updateWidgetPosition();
2781}
2782
2783bool FrameView::updateEmbeddedObjects()
2784{
2785    if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty())
2786        return true;
2787
2788    WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
2789
2790    // Insert a marker for where we should stop.
2791    ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr));
2792    m_embeddedObjectsToUpdate->add(nullptr);
2793
2794    while (!m_embeddedObjectsToUpdate->isEmpty()) {
2795        RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst();
2796        if (!embeddedObject)
2797            break;
2798        updateEmbeddedObject(*embeddedObject);
2799    }
2800
2801    return m_embeddedObjectsToUpdate->isEmpty();
2802}
2803
2804void FrameView::updateEmbeddedObjectsTimerFired(Timer<FrameView>*)
2805{
2806    RefPtr<FrameView> protect(this);
2807    m_updateEmbeddedObjectsTimer.stop();
2808    for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) {
2809        if (updateEmbeddedObjects())
2810            break;
2811    }
2812}
2813
2814void FrameView::flushAnyPendingPostLayoutTasks()
2815{
2816    if (m_postLayoutTasksTimer.isActive())
2817        performPostLayoutTasks();
2818    if (m_updateEmbeddedObjectsTimer.isActive())
2819        updateEmbeddedObjectsTimerFired(nullptr);
2820}
2821
2822void FrameView::performPostLayoutTasks()
2823{
2824    // FIXME: We should not run any JavaScript code in this function.
2825
2826    m_postLayoutTasksTimer.stop();
2827
2828    frame().selection().didLayout();
2829
2830    if (m_nestedLayoutCount <= 1 && frame().document()->documentElement())
2831        fireLayoutRelatedMilestonesIfNeeded();
2832
2833#if PLATFORM(IOS)
2834    // Only send layout-related delegate callbacks synchronously for the main frame to
2835    // avoid re-entering layout for the main frame while delivering a layout-related delegate
2836    // callback for a subframe.
2837    if (frame().isMainFrame())
2838        frame().page()->chrome().client().didLayout();
2839#endif
2840
2841#if ENABLE(FONT_LOAD_EVENTS)
2842    if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
2843        frame().document()->fontloader()->didLayout();
2844#endif
2845
2846    // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this
2847    // with didLayout(LayoutMilestones).
2848    frame().loader().client().dispatchDidLayout();
2849
2850    updateWidgetPositions();
2851
2852    // layout() protects FrameView, but it still can get destroyed when updateEmbeddedObjects()
2853    // is called through the post layout timer.
2854    Ref<FrameView> protect(*this);
2855
2856    m_updateEmbeddedObjectsTimer.startOneShot(0);
2857
2858    if (auto* page = frame().page()) {
2859        if (auto* scrollingCoordinator = page->scrollingCoordinator())
2860            scrollingCoordinator->frameViewLayoutUpdated(this);
2861    }
2862
2863    if (RenderView* renderView = this->renderView()) {
2864        if (renderView->usesCompositing())
2865            renderView->compositor().frameViewDidLayout();
2866    }
2867
2868    scrollToAnchor();
2869
2870    sendResizeEventIfNeeded();
2871}
2872
2873IntSize FrameView::sizeForResizeEvent() const
2874{
2875#if PLATFORM(IOS)
2876    if (m_useCustomSizeForResizeEvent)
2877        return m_customSizeForResizeEvent;
2878#endif
2879    if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
2880        return fixedLayoutSize();
2881    return visibleContentRectIncludingScrollbars().size();
2882}
2883
2884void FrameView::sendResizeEventIfNeeded()
2885{
2886    if (isInLayout() || needsLayout())
2887        return;
2888
2889    RenderView* renderView = this->renderView();
2890    if (!renderView || renderView->printing())
2891        return;
2892
2893    if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient())
2894        return;
2895
2896    IntSize currentSize = sizeForResizeEvent();
2897    float currentZoomFactor = renderView->style().zoom();
2898
2899    if (currentSize == m_lastViewportSize && currentZoomFactor == m_lastZoomFactor)
2900        return;
2901
2902    m_lastViewportSize = currentSize;
2903    m_lastZoomFactor = currentZoomFactor;
2904
2905    if (m_firstLayout)
2906        return;
2907
2908#if PLATFORM(IOS)
2909    // Don't send the resize event if the document is loading. Some pages automatically reload
2910    // when the window is resized; Safari on iOS often resizes the window while setting up its
2911    // viewport. This obviously can cause problems.
2912    if (DocumentLoader* documentLoader = frame().loader().documentLoader()) {
2913        if (documentLoader->isLoadingInAPISense())
2914            return;
2915    }
2916#endif
2917
2918    bool isMainFrame = frame().isMainFrame();
2919    bool canSendResizeEventSynchronously = isMainFrame && !m_shouldAutoSize;
2920
2921    RefPtr<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false);
2922    if (canSendResizeEventSynchronously)
2923        frame().document()->dispatchWindowEvent(resizeEvent.release());
2924    else {
2925        // FIXME: Queueing this event for an unpredictable time in the future seems
2926        // intrinsically racy. By the time this resize event fires, the frame might
2927        // be resized again, so we could end up with two resize events for the same size.
2928        frame().document()->enqueueWindowEvent(resizeEvent.release());
2929    }
2930
2931#if ENABLE(INSPECTOR)
2932    if (InspectorInstrumentation::hasFrontends() && isMainFrame) {
2933        if (Page* page = frame().page()) {
2934            if (InspectorClient* inspectorClient = page->inspectorController().inspectorClient())
2935                inspectorClient->didResizeMainFrame(&frame());
2936        }
2937    }
2938#endif
2939}
2940
2941void FrameView::willStartLiveResize()
2942{
2943    ScrollView::willStartLiveResize();
2944    adjustTiledBackingCoverage();
2945}
2946
2947void FrameView::willEndLiveResize()
2948{
2949    ScrollView::willEndLiveResize();
2950    adjustTiledBackingCoverage();
2951}
2952
2953void FrameView::postLayoutTimerFired(Timer<FrameView>&)
2954{
2955    performPostLayoutTasks();
2956}
2957
2958void FrameView::autoSizeIfEnabled()
2959{
2960    if (!m_shouldAutoSize)
2961        return;
2962
2963    if (m_inAutoSize)
2964        return;
2965
2966    TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
2967
2968    Document* document = frame().document();
2969    if (!document)
2970        return;
2971
2972    RenderView* documentView = document->renderView();
2973    Element* documentElement = document->documentElement();
2974    if (!documentView || !documentElement)
2975        return;
2976
2977    // Start from the minimum size and allow it to grow.
2978    resize(m_minAutoSize.width(), m_minAutoSize.height());
2979
2980    IntSize size = frameRect().size();
2981
2982    // Do the resizing twice. The first time is basically a rough calculation using the preferred width
2983    // which may result in a height change during the second iteration.
2984    for (int i = 0; i < 2; i++) {
2985        // Update various sizes including contentsSize, scrollHeight, etc.
2986        document->updateLayoutIgnorePendingStylesheets();
2987        int width = documentView->minPreferredLogicalWidth();
2988        int height = documentView->documentRect().height();
2989        IntSize newSize(width, height);
2990
2991        // Check to see if a scrollbar is needed for a given dimension and
2992        // if so, increase the other dimension to account for the scrollbar.
2993        // Since the dimensions are only for the view rectangle, once a
2994        // dimension exceeds the maximum, there is no need to increase it further.
2995        if (newSize.width() > m_maxAutoSize.width()) {
2996            RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
2997            if (!localHorizontalScrollbar)
2998                localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
2999            if (!localHorizontalScrollbar->isOverlayScrollbar())
3000                newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
3001
3002            // Don't bother checking for a vertical scrollbar because the width is at
3003            // already greater the maximum.
3004        } else if (newSize.height() > m_maxAutoSize.height()) {
3005            RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
3006            if (!localVerticalScrollbar)
3007                localVerticalScrollbar = createScrollbar(VerticalScrollbar);
3008            if (!localVerticalScrollbar->isOverlayScrollbar())
3009                newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
3010
3011            // Don't bother checking for a horizontal scrollbar because the height is
3012            // already greater the maximum.
3013        }
3014
3015        // Ensure the size is at least the min bounds.
3016        newSize = newSize.expandedTo(m_minAutoSize);
3017
3018        // Bound the dimensions by the max bounds and determine what scrollbars to show.
3019        ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
3020        if (newSize.width() > m_maxAutoSize.width()) {
3021            newSize.setWidth(m_maxAutoSize.width());
3022            horizonalScrollbarMode = ScrollbarAlwaysOn;
3023        }
3024        ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
3025        if (newSize.height() > m_maxAutoSize.height()) {
3026            newSize.setHeight(m_maxAutoSize.height());
3027            verticalScrollbarMode = ScrollbarAlwaysOn;
3028        }
3029
3030        if (newSize == size)
3031            continue;
3032
3033        // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
3034        // unless autoresize has just been turned on or the maximum size is smaller than the current size.
3035        if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
3036            && !frame().loader().isComplete() && (newSize.height() < size.height() || newSize.width() < size.width()))
3037            break;
3038
3039        resize(newSize.width(), newSize.height());
3040        // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
3041        // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
3042        setVerticalScrollbarLock(false);
3043        setHorizontalScrollbarLock(false);
3044        setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
3045    }
3046
3047    m_autoSizeContentSize = contentsSize();
3048
3049    if (m_autoSizeFixedMinimumHeight) {
3050        resize(m_autoSizeContentSize.width(), std::max(m_autoSizeFixedMinimumHeight, m_autoSizeContentSize.height()));
3051        document->updateLayoutIgnorePendingStylesheets();
3052    }
3053
3054    m_didRunAutosize = true;
3055}
3056
3057void FrameView::setAutoSizeFixedMinimumHeight(int fixedMinimumHeight)
3058{
3059    if (m_autoSizeFixedMinimumHeight == fixedMinimumHeight)
3060        return;
3061
3062    m_autoSizeFixedMinimumHeight = fixedMinimumHeight;
3063
3064    setNeedsLayout();
3065}
3066
3067void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
3068{
3069    if (!m_viewportRenderer)
3070        return;
3071
3072    if (m_overflowStatusDirty) {
3073        m_horizontalOverflow = horizontalOverflow;
3074        m_verticalOverflow = verticalOverflow;
3075        m_overflowStatusDirty = false;
3076        return;
3077    }
3078
3079    bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
3080    bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
3081
3082    if (horizontalOverflowChanged || verticalOverflowChanged) {
3083        m_horizontalOverflow = horizontalOverflow;
3084        m_verticalOverflow = verticalOverflow;
3085
3086        RefPtr<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
3087            verticalOverflowChanged, verticalOverflow);
3088        overflowEvent->setTarget(m_viewportRenderer->element());
3089
3090        frame().document()->enqueueOverflowEvent(overflowEvent.release());
3091    }
3092
3093}
3094
3095const Pagination& FrameView::pagination() const
3096{
3097    if (m_pagination != Pagination())
3098        return m_pagination;
3099
3100    if (frame().isMainFrame())
3101        return frame().page()->pagination();
3102
3103    return m_pagination;
3104}
3105
3106void FrameView::setPagination(const Pagination& pagination)
3107{
3108    if (m_pagination == pagination)
3109        return;
3110
3111    m_pagination = pagination;
3112
3113    frame().document()->styleResolverChanged(DeferRecalcStyle);
3114}
3115
3116IntRect FrameView::windowClipRect(bool clipToContents) const
3117{
3118    ASSERT(frame().view() == this);
3119
3120    if (paintsEntireContents())
3121        return IntRect(IntPoint(), totalContentsSize());
3122
3123    // Set our clip rect to be our contents.
3124    IntRect clipRect;
3125    if (clipToContents)
3126        clipRect = contentsToWindow(visibleContentRect(LegacyIOSDocumentVisibleRect));
3127    else
3128        clipRect = contentsToWindow(visibleContentRectIncludingScrollbars(LegacyIOSDocumentVisibleRect));
3129    if (!frame().ownerElement())
3130        return clipRect;
3131
3132    // Take our owner element and get its clip rect.
3133    HTMLFrameOwnerElement* ownerElement = frame().ownerElement();
3134    if (FrameView* parentView = ownerElement->document().view())
3135        clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true));
3136    return clipRect;
3137}
3138
3139IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const
3140{
3141    // The renderer can sometimes be null when style="display:none" interacts
3142    // with external content and plugins.
3143    if (!ownerElement->renderer())
3144        return windowClipRect();
3145
3146    // If we have no layer, just return our window clip rect.
3147    const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
3148    if (!enclosingLayer)
3149        return windowClipRect();
3150
3151    // Apply the clip from the layer.
3152    IntRect clipRect;
3153    if (clipToLayerContents)
3154        clipRect = pixelSnappedIntRect(enclosingLayer->childrenClipRect());
3155    else
3156        clipRect = pixelSnappedIntRect(enclosingLayer->selfClipRect());
3157    clipRect = contentsToWindow(clipRect);
3158    return intersection(clipRect, windowClipRect());
3159}
3160
3161bool FrameView::isActive() const
3162{
3163    Page* page = frame().page();
3164    return page && page->focusController().isActive();
3165}
3166
3167bool FrameView::updatesScrollLayerPositionOnMainThread() const
3168{
3169    if (Page* page = frame().page()) {
3170        if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
3171            return scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously();
3172    }
3173
3174    return true;
3175}
3176
3177bool FrameView::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
3178{
3179    Page* page = frame().page();
3180    return page && page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
3181}
3182
3183void FrameView::scrollTo(const IntSize& newOffset)
3184{
3185    LayoutSize offset = scrollOffset();
3186    IntPoint oldPosition = scrollPosition();
3187    ScrollView::scrollTo(newOffset);
3188    if (offset != scrollOffset())
3189        scrollPositionChanged(oldPosition, scrollPosition());
3190    frame().loader().client().didChangeScrollOffset();
3191}
3192
3193void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
3194{
3195    // Add in our offset within the FrameView.
3196    IntRect dirtyRect = rect;
3197    dirtyRect.moveBy(scrollbar->location());
3198    invalidateRect(dirtyRect);
3199}
3200
3201IntRect FrameView::windowResizerRect() const
3202{
3203    if (Page* page = frame().page())
3204        return page->chrome().windowResizerRect();
3205    return IntRect();
3206}
3207
3208float FrameView::visibleContentScaleFactor() const
3209{
3210    if (!frame().isMainFrame() || !frame().settings().delegatesPageScaling())
3211        return 1;
3212
3213    return frame().page()->pageScaleFactor();
3214}
3215
3216void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb)
3217{
3218    if (!frame().isMainFrame())
3219        return;
3220
3221    frame().page()->chrome().client().notifyScrollerThumbIsVisibleInRect(scrollerThumb);
3222}
3223
3224ScrollableArea* FrameView::enclosingScrollableArea() const
3225{
3226    // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
3227    return 0;
3228}
3229
3230IntRect FrameView::scrollableAreaBoundingBox() const
3231{
3232    RenderWidget* ownerRenderer = frame().ownerRenderer();
3233    if (!ownerRenderer)
3234        return frameRect();
3235
3236    return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
3237}
3238
3239bool FrameView::isScrollable()
3240{
3241    // Check for:
3242    // 1) If there an actual overflow.
3243    // 2) display:none or visibility:hidden set to self or inherited.
3244    // 3) overflow{-x,-y}: hidden;
3245    // 4) scrolling: no;
3246
3247    // Covers #1
3248    IntSize totalContentsSize = this->totalContentsSize();
3249    IntSize visibleContentSize = visibleContentRect(LegacyIOSDocumentVisibleRect).size();
3250    if ((totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width()))
3251        return false;
3252
3253    // Covers #2.
3254    HTMLFrameOwnerElement* owner = frame().ownerElement();
3255    if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
3256        return false;
3257
3258    // Cover #3 and #4.
3259    ScrollbarMode horizontalMode;
3260    ScrollbarMode verticalMode;
3261    calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly);
3262    if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
3263        return false;
3264
3265    return true;
3266}
3267
3268void FrameView::updateScrollableAreaSet()
3269{
3270    // That ensures that only inner frames are cached.
3271    FrameView* parentFrameView = this->parentFrameView();
3272    if (!parentFrameView)
3273        return;
3274
3275    if (!isScrollable()) {
3276        parentFrameView->removeScrollableArea(this);
3277        return;
3278    }
3279
3280    parentFrameView->addScrollableArea(this);
3281}
3282
3283bool FrameView::shouldSuspendScrollAnimations() const
3284{
3285    return frame().loader().state() != FrameStateComplete;
3286}
3287
3288void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate)
3289{
3290    if (!frame().isMainFrame())
3291        return;
3292
3293    frame().page()->chrome().client().recommendedScrollbarStyleDidChange(newStyle);
3294
3295    if (forceUpdate)
3296        ScrollView::scrollbarStyleChanged(newStyle, forceUpdate);
3297}
3298
3299void FrameView::notifyPageThatContentAreaWillPaint() const
3300{
3301    Page* page = frame().page();
3302    if (!page)
3303        return;
3304
3305    contentAreaWillPaint();
3306
3307    if (!m_scrollableAreas)
3308        return;
3309
3310    for (auto& scrollableArea : *m_scrollableAreas)
3311        scrollableArea->contentAreaWillPaint();
3312}
3313
3314bool FrameView::scrollAnimatorEnabled() const
3315{
3316#if ENABLE(SMOOTH_SCROLLING)
3317    if (Page* page = frame().page())
3318        return page->settings().scrollAnimatorEnabled();
3319#endif
3320
3321    return false;
3322}
3323
3324#if ENABLE(DASHBOARD_SUPPORT)
3325void FrameView::updateAnnotatedRegions()
3326{
3327    Document* document = frame().document();
3328    if (!document->hasAnnotatedRegions())
3329        return;
3330    Vector<AnnotatedRegionValue> newRegions;
3331    document->renderBox()->collectAnnotatedRegions(newRegions);
3332    if (newRegions == document->annotatedRegions())
3333        return;
3334    document->setAnnotatedRegions(newRegions);
3335    Page* page = frame().page();
3336    if (!page)
3337        return;
3338    page->chrome().client().annotatedRegionsChanged();
3339}
3340#endif
3341
3342void FrameView::updateScrollCorner()
3343{
3344    RenderElement* renderer = 0;
3345    RefPtr<RenderStyle> cornerStyle;
3346    IntRect cornerRect = scrollCornerRect();
3347
3348    if (!cornerRect.isEmpty()) {
3349        // Try the <body> element first as a scroll corner source.
3350        Document* doc = frame().document();
3351        Element* body = doc ? doc->body() : 0;
3352        if (body && body->renderer()) {
3353            renderer = body->renderer();
3354            cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3355        }
3356
3357        if (!cornerStyle) {
3358            // If the <body> didn't have a custom style, then the root element might.
3359            Element* docElement = doc ? doc->documentElement() : 0;
3360            if (docElement && docElement->renderer()) {
3361                renderer = docElement->renderer();
3362                cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3363            }
3364        }
3365
3366        if (!cornerStyle) {
3367            // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
3368            if (RenderWidget* renderer = frame().ownerRenderer())
3369                cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3370        }
3371    }
3372
3373    if (!cornerStyle)
3374        m_scrollCorner = nullptr;
3375    else {
3376        if (!m_scrollCorner) {
3377            m_scrollCorner = createRenderer<RenderScrollbarPart>(renderer->document(), cornerStyle.releaseNonNull());
3378            m_scrollCorner->initializeStyle();
3379        } else
3380            m_scrollCorner->setStyle(cornerStyle.releaseNonNull());
3381        invalidateScrollCorner(cornerRect);
3382    }
3383
3384    ScrollView::updateScrollCorner();
3385}
3386
3387void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
3388{
3389    if (context->updatingControlTints()) {
3390        updateScrollCorner();
3391        return;
3392    }
3393
3394    if (m_scrollCorner) {
3395        if (frame().isMainFrame())
3396            context->fillRect(cornerRect, baseBackgroundColor(), ColorSpaceDeviceRGB);
3397        m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
3398        return;
3399    }
3400
3401    ScrollView::paintScrollCorner(context, cornerRect);
3402}
3403
3404void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
3405{
3406    if (bar->isCustomScrollbar() && frame().isMainFrame()) {
3407        IntRect toFill = bar->frameRect();
3408        toFill.intersect(rect);
3409        context->fillRect(toFill, baseBackgroundColor(), ColorSpaceDeviceRGB);
3410    }
3411
3412    ScrollView::paintScrollbar(context, bar, rect);
3413}
3414
3415Color FrameView::documentBackgroundColor() const
3416{
3417    // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
3418    // the document and the body against the base background color of the frame view.
3419    // Background images are unfortunately impractical to include.
3420
3421    // Return invalid Color objects whenever there is insufficient information.
3422    if (!frame().document())
3423        return Color();
3424
3425    Element* htmlElement = frame().document()->documentElement();
3426    Element* bodyElement = frame().document()->body();
3427
3428    // Start with invalid colors.
3429    Color htmlBackgroundColor;
3430    Color bodyBackgroundColor;
3431    if (htmlElement && htmlElement->renderer())
3432        htmlBackgroundColor = htmlElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3433    if (bodyElement && bodyElement->renderer())
3434        bodyBackgroundColor = bodyElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3435
3436    if (!bodyBackgroundColor.isValid()) {
3437        if (!htmlBackgroundColor.isValid())
3438            return Color();
3439        return baseBackgroundColor().blend(htmlBackgroundColor);
3440    }
3441
3442    if (!htmlBackgroundColor.isValid())
3443        return baseBackgroundColor().blend(bodyBackgroundColor);
3444
3445    // We take the aggregate of the base background color
3446    // the <html> background color, and the <body>
3447    // background color to find the document color. The
3448    // addition of the base background color is not
3449    // technically part of the document background, but it
3450    // otherwise poses problems when the aggregate is not
3451    // fully opaque.
3452    return baseBackgroundColor().blend(htmlBackgroundColor).blend(bodyBackgroundColor);
3453}
3454
3455bool FrameView::hasCustomScrollbars() const
3456{
3457    for (auto& widget : children()) {
3458        if (widget->isFrameView()) {
3459            if (toFrameView(*widget).hasCustomScrollbars())
3460                return true;
3461        } else if (widget->isScrollbar()) {
3462            if (toScrollbar(*widget).isCustomScrollbar())
3463                return true;
3464        }
3465    }
3466
3467    return false;
3468}
3469
3470FrameView* FrameView::parentFrameView() const
3471{
3472    if (!parent())
3473        return 0;
3474
3475    if (Frame* parentFrame = frame().tree().parent())
3476        return parentFrame->view();
3477
3478    return 0;
3479}
3480
3481bool FrameView::isInChildFrameWithFrameFlattening() const
3482{
3483    if (!parent() || !frame().ownerElement())
3484        return false;
3485
3486    // Frame flattening applies when the owner element is either in a frameset or
3487    // an iframe with flattening parameters.
3488    if (frame().ownerElement()->hasTagName(iframeTag)) {
3489        RenderIFrame* iframeRenderer = toRenderIFrame(frame().ownerElement()->renderWidget());
3490        if (iframeRenderer->flattenFrame())
3491            return true;
3492    }
3493
3494    if (!frameFlatteningEnabled())
3495        return false;
3496
3497    if (frame().ownerElement()->hasTagName(frameTag))
3498        return true;
3499
3500    return false;
3501}
3502
3503void FrameView::startLayoutAtMainFrameViewIfNeeded(bool allowSubtree)
3504{
3505    // When we start a layout at the child level as opposed to the topmost frame view and this child
3506    // frame requires flattening, we need to re-initiate the layout at the topmost view. Layout
3507    // will hit this view eventually.
3508    FrameView* parentView = parentFrameView();
3509    if (!parentView)
3510        return;
3511
3512    // In the middle of parent layout, no need to restart from topmost.
3513    if (parentView->m_nestedLayoutCount)
3514        return;
3515
3516    // Parent tree is clean. Starting layout from it would have no effect.
3517    if (!parentView->needsLayout())
3518        return;
3519
3520    while (parentView->parentFrameView())
3521        parentView = parentView->parentFrameView();
3522
3523    parentView->layout(allowSubtree);
3524
3525    RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
3526    ASSERT_UNUSED(root, !root->needsLayout());
3527}
3528
3529void FrameView::updateControlTints()
3530{
3531    // This is called when control tints are changed from aqua/graphite to clear and vice versa.
3532    // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
3533    // This is only done if the theme supports control tinting. It's up to the theme and platform
3534    // to define when controls get the tint and to call this function when that changes.
3535
3536    // Optimize the common case where we bring a window to the front while it's still empty.
3537    if (frame().document()->url().isEmpty())
3538        return;
3539
3540    RenderView* renderView = this->renderView();
3541    if ((renderView && renderView->theme().supportsControlTints()) || hasCustomScrollbars())
3542        paintControlTints();
3543}
3544
3545void FrameView::paintControlTints()
3546{
3547    if (needsLayout())
3548        layout();
3549    PlatformGraphicsContext* const noContext = 0;
3550    GraphicsContext context(noContext);
3551    context.setUpdatingControlTints(true);
3552    if (platformWidget()) {
3553        // FIXME: consult paintsEntireContents().
3554        paintContents(&context, visibleContentRect(LegacyIOSDocumentVisibleRect));
3555    } else
3556        paint(&context, frameRect());
3557}
3558
3559bool FrameView::wasScrolledByUser() const
3560{
3561    return m_wasScrolledByUser;
3562}
3563
3564void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
3565{
3566    if (m_inProgrammaticScroll)
3567        return;
3568    m_maintainScrollPositionAnchor = 0;
3569    if (m_wasScrolledByUser == wasScrolledByUser)
3570        return;
3571    m_wasScrolledByUser = wasScrolledByUser;
3572    if (frame().isMainFrame())
3573        updateLayerFlushThrottling();
3574    adjustTiledBackingCoverage();
3575}
3576
3577void FrameView::willPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState)
3578{
3579    Document* document = frame().document();
3580
3581    if (!context->paintingDisabled())
3582        InspectorInstrumentation::willPaint(renderView());
3583
3584    paintingState.isTopLevelPainter = !sCurrentPaintTimeStamp;
3585
3586    if (paintingState.isTopLevelPainter && memoryPressureHandler().isUnderMemoryPressure()) {
3587        LOG(MemoryPressure, "Under memory pressure: %s", WTF_PRETTY_FUNCTION);
3588
3589        // To avoid unnecessary image decoding, we don't prune recently-decoded live resources here since
3590        // we might need some live bitmaps on painting.
3591        memoryCache()->prune();
3592    }
3593
3594    if (paintingState.isTopLevelPainter)
3595        sCurrentPaintTimeStamp = monotonicallyIncreasingTime();
3596
3597    paintingState.paintBehavior = m_paintBehavior;
3598
3599    if (FrameView* parentView = parentFrameView()) {
3600        if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
3601            m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3602    }
3603
3604    if (m_paintBehavior == PaintBehaviorNormal)
3605        document->markers().invalidateRenderedRectsForMarkersInRect(dirtyRect);
3606
3607    if (document->printing())
3608        m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3609
3610    paintingState.isFlatteningPaintOfRootFrame = (m_paintBehavior & PaintBehaviorFlattenCompositingLayers) && !frame().ownerElement();
3611    if (paintingState.isFlatteningPaintOfRootFrame)
3612        notifyWidgetsInAllFrames(WillPaintFlattened);
3613
3614    ASSERT(!m_isPainting);
3615    m_isPainting = true;
3616}
3617
3618void FrameView::didPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState)
3619{
3620    m_isPainting = false;
3621
3622    if (paintingState.isFlatteningPaintOfRootFrame)
3623        notifyWidgetsInAllFrames(DidPaintFlattened);
3624
3625    m_paintBehavior = paintingState.paintBehavior;
3626    m_lastPaintTime = monotonicallyIncreasingTime();
3627
3628    // Painting can lead to decoding of large amounts of bitmaps
3629    // If we are low on memory, wipe them out after the paint.
3630    if (paintingState.isTopLevelPainter && memoryPressureHandler().isUnderMemoryPressure())
3631        memoryCache()->pruneLiveResources(true);
3632
3633    // Regions may have changed as a result of the visibility/z-index of element changing.
3634#if ENABLE(DASHBOARD_SUPPORT)
3635    if (frame().document()->annotatedRegionsDirty())
3636        updateAnnotatedRegions();
3637#endif
3638
3639    if (paintingState.isTopLevelPainter)
3640        sCurrentPaintTimeStamp = 0;
3641
3642    if (!context->paintingDisabled()) {
3643        InspectorInstrumentation::didPaint(renderView(), context, dirtyRect);
3644        // FIXME: should probably not fire milestones for snapshot painting. https://bugs.webkit.org/show_bug.cgi?id=117623
3645        firePaintRelatedMilestonesIfNeeded();
3646    }
3647}
3648
3649void FrameView::paintContents(GraphicsContext* context, const IntRect& dirtyRect)
3650{
3651#ifndef NDEBUG
3652    bool fillWithRed;
3653    if (frame().document()->printing())
3654        fillWithRed = false; // Printing, don't fill with red (can't remember why).
3655    else if (frame().ownerElement())
3656        fillWithRed = false; // Subframe, don't fill with red.
3657    else if (isTransparent())
3658        fillWithRed = false; // Transparent, don't fill with red.
3659    else if (m_paintBehavior & PaintBehaviorSelectionOnly)
3660        fillWithRed = false; // Selections are transparent, don't fill with red.
3661    else if (m_nodeToDraw)
3662        fillWithRed = false; // Element images are transparent, don't fill with red.
3663    else
3664        fillWithRed = true;
3665
3666    if (fillWithRed)
3667        context->fillRect(dirtyRect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB);
3668#endif
3669
3670    RenderView* renderView = this->renderView();
3671    if (!renderView) {
3672        LOG_ERROR("called FrameView::paint with nil renderer");
3673        return;
3674    }
3675
3676    ASSERT(!needsLayout());
3677    if (needsLayout())
3678        return;
3679
3680    PaintingState paintingState;
3681    willPaintContents(context, dirtyRect, paintingState);
3682
3683    FontCachePurgePreventer fontCachePurgePreventer;
3684
3685    // m_nodeToDraw is used to draw only one element (and its descendants)
3686    RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
3687    RenderLayer* rootLayer = renderView->layer();
3688
3689#ifndef NDEBUG
3690    RenderElement::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(&rootLayer->renderer());
3691#endif
3692
3693    // To work around http://webkit.org/b/135106, ensure that the paint root isn't an inline with culled line boxes.
3694    // FIXME: This can cause additional content to be included in the snapshot, so remove this once that bug is fixed.
3695    while (eltRenderer && eltRenderer->isRenderInline() && !toRenderInline(eltRenderer)->firstLineBox())
3696        eltRenderer = eltRenderer->parent();
3697
3698    rootLayer->paint(context, dirtyRect, m_paintBehavior, eltRenderer);
3699    if (rootLayer->containsDirtyOverlayScrollbars())
3700        rootLayer->paintOverlayScrollbars(context, dirtyRect, m_paintBehavior, eltRenderer);
3701
3702    didPaintContents(context, dirtyRect, paintingState);
3703}
3704
3705void FrameView::setPaintBehavior(PaintBehavior behavior)
3706{
3707    m_paintBehavior = behavior;
3708}
3709
3710PaintBehavior FrameView::paintBehavior() const
3711{
3712    return m_paintBehavior;
3713}
3714
3715bool FrameView::isPainting() const
3716{
3717    return m_isPainting;
3718}
3719
3720// FIXME: change this to use the subtreePaint terminology.
3721void FrameView::setNodeToDraw(Node* node)
3722{
3723    m_nodeToDraw = node;
3724}
3725
3726void FrameView::paintContentsForSnapshot(GraphicsContext* context, const IntRect& imageRect, SelectionInSnapshot shouldPaintSelection, CoordinateSpaceForSnapshot coordinateSpace)
3727{
3728    updateLayoutAndStyleIfNeededRecursive();
3729
3730    // Cache paint behavior and set a new behavior appropriate for snapshots.
3731    PaintBehavior oldBehavior = paintBehavior();
3732    setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
3733
3734    // If the snapshot should exclude selection, then we'll clear the current selection
3735    // in the render tree only. This will allow us to restore the selection from the DOM
3736    // after we paint the snapshot.
3737    if (shouldPaintSelection == ExcludeSelection) {
3738        for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
3739            if (RenderView* root = frame->contentRenderer())
3740                root->clearSelection();
3741        }
3742    }
3743
3744    if (coordinateSpace == DocumentCoordinates)
3745        paintContents(context, imageRect);
3746    else {
3747        // A snapshot in ViewCoordinates will include a scrollbar, and the snapshot will contain
3748        // whatever content the document is currently scrolled to.
3749        paint(context, imageRect);
3750    }
3751
3752    // Restore selection.
3753    if (shouldPaintSelection == ExcludeSelection) {
3754        for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get()))
3755            frame->selection().updateAppearance();
3756    }
3757
3758    // Restore cached paint behavior.
3759    setPaintBehavior(oldBehavior);
3760}
3761
3762void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
3763{
3764    if (context->paintingDisabled())
3765        return;
3766
3767    if (frame().document()->printing())
3768        return;
3769
3770    ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
3771}
3772
3773void FrameView::updateLayoutAndStyleIfNeededRecursive()
3774{
3775    // We have to crawl our entire tree looking for any FrameViews that need
3776    // layout and make sure they are up to date.
3777    // Mac actually tests for intersection with the dirty region and tries not to
3778    // update layout for frames that are outside the dirty region.  Not only does this seem
3779    // pointless (since those frames will have set a zero timer to layout anyway), but
3780    // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
3781    // region but then become included later by the second frame adding rects to the dirty region
3782    // when it lays out.
3783
3784    frame().document()->updateStyleIfNeeded();
3785
3786    if (needsLayout())
3787        layout();
3788
3789    // Grab a copy of the children() set, as it may be mutated by the following updateLayoutAndStyleIfNeededRecursive
3790    // calls, as they can potentially re-enter a layout of the parent frame view, which may add/remove scrollbars
3791    // and thus mutates the children() set.
3792    Vector<Ref<FrameView>, 16> childViews;
3793    childViews.reserveInitialCapacity(children().size());
3794    for (auto& widget : children()) {
3795        if (widget->isFrameView())
3796            childViews.uncheckedAppend(toFrameView(*widget));
3797    }
3798
3799    for (unsigned i = 0; i < childViews.size(); ++i)
3800        childViews[i]->updateLayoutAndStyleIfNeededRecursive();
3801
3802    // When frame flattening is on, child frame can mark parent frame dirty. In such case, child frame
3803    // needs to call layout on parent frame recursively.
3804    // This assert ensures that parent frames are clean, when child frames finished updating layout and style.
3805    ASSERT(!needsLayout());
3806}
3807
3808bool FrameView::qualifiesAsVisuallyNonEmpty() const
3809{
3810    // No content yet.
3811    Element* documentElement = frame().document()->documentElement();
3812    if (!documentElement || !documentElement->renderer())
3813        return false;
3814
3815    // Ensure that we always get marked visually non-empty eventually.
3816    if (!frame().document()->parsing() && frame().loader().stateMachine().committedFirstRealDocumentLoad())
3817        return true;
3818
3819    // Require the document to grow a bit.
3820    static const int documentHeightThreshold = 200;
3821    if (documentElement->renderBox()->layoutOverflowRect().pixelSnappedHeight() < documentHeightThreshold)
3822        return false;
3823
3824    // The first few hundred characters rarely contain the interesting content of the page.
3825    if (m_visuallyNonEmptyCharacterCount > visualCharacterThreshold)
3826        return true;
3827    // Use a threshold value to prevent very small amounts of visible content from triggering didFirstVisuallyNonEmptyLayout
3828    if (m_visuallyNonEmptyPixelCount > visualPixelThreshold)
3829        return true;
3830    return false;
3831}
3832
3833void FrameView::updateIsVisuallyNonEmpty()
3834{
3835    if (m_isVisuallyNonEmpty)
3836        return;
3837    if (!qualifiesAsVisuallyNonEmpty())
3838        return;
3839    m_isVisuallyNonEmpty = true;
3840    adjustTiledBackingCoverage();
3841}
3842
3843void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize)
3844{
3845    ASSERT(!enable || !minSize.isEmpty());
3846    ASSERT(minSize.width() <= maxSize.width());
3847    ASSERT(minSize.height() <= maxSize.height());
3848
3849    if (m_shouldAutoSize == enable && m_minAutoSize == minSize && m_maxAutoSize == maxSize)
3850        return;
3851
3852    m_shouldAutoSize = enable;
3853    m_minAutoSize = minSize;
3854    m_maxAutoSize = maxSize;
3855    m_didRunAutosize = false;
3856
3857    setNeedsLayout();
3858    scheduleRelayout();
3859    if (m_shouldAutoSize)
3860        return;
3861
3862    // Since autosize mode forces the scrollbar mode, change them to being auto.
3863    setVerticalScrollbarLock(false);
3864    setHorizontalScrollbarLock(false);
3865    setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
3866}
3867
3868void FrameView::forceLayout(bool allowSubtree)
3869{
3870    layout(allowSubtree);
3871}
3872
3873void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor, AdjustViewSizeOrNot shouldAdjustViewSize)
3874{
3875    // Dumping externalRepresentation(frame().renderer()).ascii() is a good trick to see
3876    // the state of things before and after the layout
3877    if (RenderView* renderView = this->renderView()) {
3878        float pageLogicalWidth = renderView->style().isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
3879        float pageLogicalHeight = renderView->style().isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
3880
3881        renderView->setLogicalWidth(floor(pageLogicalWidth));
3882        renderView->setPageLogicalHeight(floor(pageLogicalHeight));
3883        renderView->setNeedsLayoutAndPrefWidthsRecalc();
3884        forceLayout();
3885
3886        // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
3887        // page width when shrunk, we will lay out at maximum shrink and clip extra content.
3888        // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
3889        // implementation should not do this!
3890        bool horizontalWritingMode = renderView->style().isHorizontalWritingMode();
3891        const LayoutRect& documentRect = renderView->documentRect();
3892        LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
3893        if (docLogicalWidth > pageLogicalWidth) {
3894            int expectedPageWidth = std::min<float>(documentRect.width(), pageSize.width() * maximumShrinkFactor);
3895            int expectedPageHeight = std::min<float>(documentRect.height(), pageSize.height() * maximumShrinkFactor);
3896            FloatSize maxPageSize = frame().resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), FloatSize(expectedPageWidth, expectedPageHeight));
3897            pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
3898            pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
3899
3900            renderView->setLogicalWidth(floor(pageLogicalWidth));
3901            renderView->setPageLogicalHeight(floor(pageLogicalHeight));
3902            renderView->setNeedsLayoutAndPrefWidthsRecalc();
3903            forceLayout();
3904
3905            const LayoutRect& updatedDocumentRect = renderView->documentRect();
3906            LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
3907            LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
3908            LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
3909            LayoutUnit clippedLogicalLeft = 0;
3910            if (!renderView->style().isLeftToRightDirection())
3911                clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
3912            LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
3913
3914            if (!horizontalWritingMode)
3915                overflow = overflow.transposedRect();
3916            renderView->clearLayoutOverflow();
3917            renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
3918        }
3919    }
3920
3921    if (shouldAdjustViewSize)
3922        adjustViewSize();
3923}
3924
3925void FrameView::adjustPageHeightDeprecated(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/)
3926{
3927    RenderView* renderView = this->renderView();
3928    if (!renderView) {
3929        *newBottom = oldBottom;
3930        return;
3931
3932    }
3933    // Use a context with painting disabled.
3934    GraphicsContext context((PlatformGraphicsContext*)0);
3935    renderView->setTruncatedAt(static_cast<int>(floorf(oldBottom)));
3936    IntRect dirtyRect(0, static_cast<int>(floorf(oldTop)), renderView->layoutOverflowRect().maxX(), static_cast<int>(ceilf(oldBottom - oldTop)));
3937    renderView->setPrintRect(dirtyRect);
3938    renderView->layer()->paint(&context, dirtyRect);
3939    *newBottom = renderView->bestTruncatedAt();
3940    if (!*newBottom)
3941        *newBottom = oldBottom;
3942    renderView->setPrintRect(IntRect());
3943}
3944
3945IntRect FrameView::convertFromRendererToContainingView(const RenderElement* renderer, const IntRect& rendererRect) const
3946{
3947    IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
3948
3949    // Convert from page ("absolute") to FrameView coordinates.
3950    if (!delegatesScrolling())
3951        rect.moveBy(-scrollPosition() + IntPoint(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)));
3952
3953    return rect;
3954}
3955
3956IntRect FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, const IntRect& viewRect) const
3957{
3958    IntRect rect = viewRect;
3959
3960    // Convert from FrameView coords into page ("absolute") coordinates.
3961    if (!delegatesScrolling())
3962        rect.moveBy(documentScrollPositionRelativeToViewOrigin());
3963
3964    // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
3965    // move the rect for now.
3966    rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms)));
3967    return rect;
3968}
3969
3970IntPoint FrameView::convertFromRendererToContainingView(const RenderElement* renderer, const IntPoint& rendererPoint) const
3971{
3972    IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms));
3973
3974    // Convert from page ("absolute") to FrameView coordinates.
3975    if (!delegatesScrolling())
3976        point.moveBy(-scrollPosition() + IntPoint(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)));
3977    return point;
3978}
3979
3980IntPoint FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, const IntPoint& viewPoint) const
3981{
3982    IntPoint point = viewPoint;
3983
3984    // Convert from FrameView coords into page ("absolute") coordinates.
3985    if (!delegatesScrolling())
3986        point = point + documentScrollPositionRelativeToViewOrigin();
3987
3988    return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms));
3989}
3990
3991IntRect FrameView::convertToContainingView(const IntRect& localRect) const
3992{
3993    if (const ScrollView* parentScrollView = parent()) {
3994        if (parentScrollView->isFrameView()) {
3995            const FrameView* parentView = toFrameView(parentScrollView);
3996            // Get our renderer in the parent view
3997            RenderWidget* renderer = frame().ownerRenderer();
3998            if (!renderer)
3999                return localRect;
4000
4001            IntRect rect(localRect);
4002            // Add borders and padding??
4003            rect.move(renderer->borderLeft() + renderer->paddingLeft(),
4004                      renderer->borderTop() + renderer->paddingTop());
4005            return parentView->convertFromRendererToContainingView(renderer, rect);
4006        }
4007
4008        return Widget::convertToContainingView(localRect);
4009    }
4010
4011    return localRect;
4012}
4013
4014IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
4015{
4016    if (const ScrollView* parentScrollView = parent()) {
4017        if (parentScrollView->isFrameView()) {
4018            const FrameView* parentView = toFrameView(parentScrollView);
4019
4020            // Get our renderer in the parent view
4021            RenderWidget* renderer = frame().ownerRenderer();
4022            if (!renderer)
4023                return parentRect;
4024
4025            IntRect rect = parentView->convertFromContainingViewToRenderer(renderer, parentRect);
4026            // Subtract borders and padding
4027            rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
4028                      -renderer->borderTop() - renderer->paddingTop());
4029            return rect;
4030        }
4031
4032        return Widget::convertFromContainingView(parentRect);
4033    }
4034
4035    return parentRect;
4036}
4037
4038IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
4039{
4040    if (const ScrollView* parentScrollView = parent()) {
4041        if (parentScrollView->isFrameView()) {
4042            const FrameView* parentView = toFrameView(parentScrollView);
4043
4044            // Get our renderer in the parent view
4045            RenderWidget* renderer = frame().ownerRenderer();
4046            if (!renderer)
4047                return localPoint;
4048
4049            IntPoint point(localPoint);
4050
4051            // Add borders and padding
4052            point.move(renderer->borderLeft() + renderer->paddingLeft(),
4053                       renderer->borderTop() + renderer->paddingTop());
4054            return parentView->convertFromRendererToContainingView(renderer, point);
4055        }
4056
4057        return Widget::convertToContainingView(localPoint);
4058    }
4059
4060    return localPoint;
4061}
4062
4063IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
4064{
4065    if (const ScrollView* parentScrollView = parent()) {
4066        if (parentScrollView->isFrameView()) {
4067            const FrameView* parentView = toFrameView(parentScrollView);
4068
4069            // Get our renderer in the parent view
4070            RenderWidget* renderer = frame().ownerRenderer();
4071            if (!renderer)
4072                return parentPoint;
4073
4074            IntPoint point = parentView->convertFromContainingViewToRenderer(renderer, parentPoint);
4075            // Subtract borders and padding
4076            point.move(-renderer->borderLeft() - renderer->paddingLeft(),
4077                       -renderer->borderTop() - renderer->paddingTop());
4078            return point;
4079        }
4080
4081        return Widget::convertFromContainingView(parentPoint);
4082    }
4083
4084    return parentPoint;
4085}
4086
4087void FrameView::setTracksRepaints(bool trackRepaints)
4088{
4089    if (trackRepaints == m_isTrackingRepaints)
4090        return;
4091
4092    // Force layout to flush out any pending repaints.
4093    if (trackRepaints) {
4094        if (frame().document())
4095            frame().document()->updateLayout();
4096    }
4097
4098    for (Frame* frame = &m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) {
4099        if (RenderView* renderView = frame->contentRenderer())
4100            renderView->compositor().setTracksRepaints(trackRepaints);
4101    }
4102
4103    resetTrackedRepaints();
4104    m_isTrackingRepaints = trackRepaints;
4105}
4106
4107void FrameView::resetTrackedRepaints()
4108{
4109    m_trackedRepaintRects.clear();
4110    if (RenderView* renderView = this->renderView())
4111        renderView->compositor().resetTrackedRepaintRects();
4112}
4113
4114String FrameView::trackedRepaintRectsAsText() const
4115{
4116    if (frame().document())
4117        frame().document()->updateLayout();
4118
4119    TextStream ts;
4120    if (!m_trackedRepaintRects.isEmpty()) {
4121        ts << "(repaint rects\n";
4122        for (size_t i = 0; i < m_trackedRepaintRects.size(); ++i)
4123            ts << "  (rect " << LayoutUnit(m_trackedRepaintRects[i].x()) << " " << LayoutUnit(m_trackedRepaintRects[i].y()) << " " << LayoutUnit(m_trackedRepaintRects[i].width()) << " " << LayoutUnit(m_trackedRepaintRects[i].height()) << ")\n";
4124        ts << ")\n";
4125    }
4126    return ts.release();
4127}
4128
4129bool FrameView::addScrollableArea(ScrollableArea* scrollableArea)
4130{
4131    if (!m_scrollableAreas)
4132        m_scrollableAreas = std::make_unique<ScrollableAreaSet>();
4133
4134    if (m_scrollableAreas->add(scrollableArea).isNewEntry) {
4135        scrollableAreaSetChanged();
4136        return true;
4137    }
4138
4139    return false;
4140}
4141
4142bool FrameView::removeScrollableArea(ScrollableArea* scrollableArea)
4143{
4144    if (m_scrollableAreas && m_scrollableAreas->remove(scrollableArea)) {
4145        scrollableAreaSetChanged();
4146        return true;
4147    }
4148    return false;
4149}
4150
4151bool FrameView::containsScrollableArea(ScrollableArea* scrollableArea) const
4152{
4153    return m_scrollableAreas && m_scrollableAreas->contains(scrollableArea);
4154}
4155
4156void FrameView::scrollableAreaSetChanged()
4157{
4158    if (auto* page = frame().page()) {
4159        if (auto* scrollingCoordinator = page->scrollingCoordinator())
4160            scrollingCoordinator->frameViewNonFastScrollableRegionChanged(this);
4161    }
4162}
4163
4164void FrameView::sendScrollEvent()
4165{
4166    frame().eventHandler().sendScrollEvent();
4167    frame().eventHandler().dispatchFakeMouseMoveEventSoon();
4168}
4169
4170void FrameView::removeChild(Widget* widget)
4171{
4172    if (widget->isFrameView())
4173        removeScrollableArea(toFrameView(widget));
4174
4175    ScrollView::removeChild(widget);
4176}
4177
4178bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent)
4179{
4180    // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views
4181    // should handle wheel events.
4182#if !ENABLE(RUBBER_BANDING)
4183    if (!isScrollable())
4184        return false;
4185#endif
4186
4187    if (delegatesScrolling()) {
4188        IntSize offset = scrollOffset();
4189        IntPoint oldPosition = scrollPosition();
4190        IntSize newOffset = IntSize(offset.width() - wheelEvent.deltaX(), offset.height() - wheelEvent.deltaY());
4191        if (offset != newOffset) {
4192            ScrollView::scrollTo(newOffset);
4193            scrollPositionChanged(oldPosition, scrollPosition());
4194            frame().loader().client().didChangeScrollOffset();
4195        }
4196        return true;
4197    }
4198
4199    // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled.
4200    if (!canHaveScrollbars())
4201        return false;
4202
4203    if (platformWidget())
4204        return false;
4205
4206#if ENABLE(ASYNC_SCROLLING)
4207    if (Page* page = frame().page()) {
4208        if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
4209            if (scrollingCoordinator->coordinatesScrollingForFrameView(this))
4210                return scrollingCoordinator->handleWheelEvent(this, wheelEvent);
4211        }
4212    }
4213#endif
4214
4215    return ScrollableArea::handleWheelEvent(wheelEvent);
4216}
4217
4218
4219bool FrameView::isVerticalDocument() const
4220{
4221    RenderView* renderView = this->renderView();
4222    if (!renderView)
4223        return true;
4224
4225    return renderView->style().isHorizontalWritingMode();
4226}
4227
4228bool FrameView::isFlippedDocument() const
4229{
4230    RenderView* renderView = this->renderView();
4231    if (!renderView)
4232        return false;
4233
4234    return renderView->style().isFlippedBlocksWritingMode();
4235}
4236
4237void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification)
4238{
4239    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
4240        if (FrameView* view = frame->view())
4241            view->notifyWidgets(notification);
4242    }
4243}
4244
4245AXObjectCache* FrameView::axObjectCache() const
4246{
4247    if (frame().document())
4248        return frame().document()->existingAXObjectCache();
4249    return 0;
4250}
4251
4252#if PLATFORM(IOS)
4253void FrameView::setCustomFixedPositionLayoutRect(const IntRect& rect)
4254{
4255    if (m_useCustomFixedPositionLayoutRect && m_customFixedPositionLayoutRect == rect)
4256        return;
4257    m_useCustomFixedPositionLayoutRect = true;
4258    m_customFixedPositionLayoutRect = rect;
4259    visibleContentsResized();
4260}
4261
4262bool FrameView::updateFixedPositionLayoutRect()
4263{
4264    if (!m_useCustomFixedPositionLayoutRect)
4265        return false;
4266
4267    IntRect newRect;
4268    Page* page = frame().page();
4269    if (!page || !page->chrome().client().fetchCustomFixedPositionLayoutRect(newRect))
4270        return false;
4271
4272    if (newRect != m_customFixedPositionLayoutRect) {
4273        m_customFixedPositionLayoutRect = newRect;
4274        setViewportConstrainedObjectsNeedLayout();
4275        return true;
4276    }
4277    return false;
4278}
4279
4280void FrameView::setCustomSizeForResizeEvent(IntSize customSize)
4281{
4282    m_useCustomSizeForResizeEvent = true;
4283    m_customSizeForResizeEvent = customSize;
4284    sendResizeEventIfNeeded();
4285}
4286
4287void FrameView::setScrollVelocity(double horizontalVelocity, double verticalVelocity, double scaleChangeRate, double timestamp)
4288{
4289    m_horizontalVelocity = horizontalVelocity;
4290    m_verticalVelocity = verticalVelocity;
4291    m_scaleChangeRate = scaleChangeRate;
4292    m_lastVelocityUpdateTime = timestamp;
4293}
4294
4295FloatRect FrameView::computeCoverageRect(double horizontalMargin, double verticalMargin) const
4296{
4297    FloatRect exposedContentRect = this->exposedContentRect();
4298    if (!m_speculativeTilingEnabled || memoryPressureHandler().isUnderMemoryPressure())
4299        return exposedContentRect;
4300
4301    double currentTime = monotonicallyIncreasingTime();
4302    double timeDelta = currentTime - m_lastVelocityUpdateTime;
4303
4304    FloatRect futureRect = exposedContentRect;
4305    futureRect.setLocation(FloatPoint(futureRect.location().x() + timeDelta * m_horizontalVelocity, futureRect.location().y() + timeDelta * m_verticalVelocity));
4306
4307    if (m_horizontalVelocity) {
4308        futureRect.setWidth(futureRect.width() + horizontalMargin);
4309        if (m_horizontalVelocity < 0)
4310            futureRect.setX(futureRect.x() - horizontalMargin);
4311    }
4312
4313    if (m_verticalVelocity) {
4314        futureRect.setHeight(futureRect.height() + verticalMargin);
4315        if (m_verticalVelocity < 0)
4316            futureRect.setY(futureRect.y() - verticalMargin);
4317    }
4318
4319    if (m_scaleChangeRate <= 0 && !m_horizontalVelocity && !m_verticalVelocity) {
4320        futureRect.setWidth(futureRect.width() + horizontalMargin);
4321        futureRect.setHeight(futureRect.height() + verticalMargin);
4322        futureRect.setX(futureRect.x() - horizontalMargin / 2);
4323        futureRect.setY(futureRect.y() - verticalMargin / 2);
4324    }
4325
4326    IntSize contentSize = contentsSize();
4327    if (futureRect.maxX() > contentSize.width())
4328        futureRect.setX(contentSize.width() - futureRect.width());
4329    if (futureRect.maxY() > contentSize.height())
4330        futureRect.setY(contentSize.height() - futureRect.height());
4331    if (futureRect.x() < 0)
4332        futureRect.setX(0);
4333    if (futureRect.y() < 0)
4334        futureRect.setY(0);
4335
4336    return futureRect;
4337}
4338#endif // PLATFORM(IOS)
4339
4340void FrameView::setScrollingPerformanceLoggingEnabled(bool flag)
4341{
4342    if (TiledBacking* tiledBacking = this->tiledBacking())
4343        tiledBacking->setScrollingPerformanceLoggingEnabled(flag);
4344}
4345
4346void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
4347{
4348    ScrollableArea::didAddScrollbar(scrollbar, orientation);
4349    if (AXObjectCache* cache = axObjectCache())
4350        cache->handleScrollbarUpdate(this);
4351}
4352
4353void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
4354{
4355    ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
4356    if (AXObjectCache* cache = axObjectCache()) {
4357        cache->remove(scrollbar);
4358        cache->handleScrollbarUpdate(this);
4359    }
4360}
4361
4362void FrameView::addPaintPendingMilestones(LayoutMilestones milestones)
4363{
4364    m_milestonesPendingPaint |= milestones;
4365}
4366
4367void FrameView::fireLayoutRelatedMilestonesIfNeeded()
4368{
4369    LayoutMilestones requestedMilestones = 0;
4370    LayoutMilestones milestonesAchieved = 0;
4371    Page* page = frame().page();
4372    if (page)
4373        requestedMilestones = page->requestedLayoutMilestones();
4374
4375    if (m_firstLayoutCallbackPending) {
4376        m_firstLayoutCallbackPending = false;
4377        frame().loader().didFirstLayout();
4378        if (requestedMilestones & DidFirstLayout)
4379            milestonesAchieved |= DidFirstLayout;
4380        if (frame().isMainFrame())
4381            page->startCountingRelevantRepaintedObjects();
4382    }
4383    updateIsVisuallyNonEmpty();
4384
4385    // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
4386    if (m_isVisuallyNonEmpty && !frame().document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
4387        m_firstVisuallyNonEmptyLayoutCallbackPending = false;
4388        if (requestedMilestones & DidFirstVisuallyNonEmptyLayout)
4389            milestonesAchieved |= DidFirstVisuallyNonEmptyLayout;
4390    }
4391
4392    if (milestonesAchieved && frame().isMainFrame())
4393        frame().loader().didLayout(milestonesAchieved);
4394}
4395
4396void FrameView::firePaintRelatedMilestonesIfNeeded()
4397{
4398    Page* page = frame().page();
4399    if (!page)
4400        return;
4401
4402    LayoutMilestones milestonesAchieved = 0;
4403
4404    // Make sure the pending paint milestones have actually been requested before we send them.
4405    if (m_milestonesPendingPaint & DidFirstFlushForHeaderLayer) {
4406        if (page->requestedLayoutMilestones() & DidFirstFlushForHeaderLayer)
4407            milestonesAchieved |= DidFirstFlushForHeaderLayer;
4408    }
4409
4410    if (m_milestonesPendingPaint & DidFirstPaintAfterSuppressedIncrementalRendering) {
4411        if (page->requestedLayoutMilestones() & DidFirstPaintAfterSuppressedIncrementalRendering)
4412            milestonesAchieved |= DidFirstPaintAfterSuppressedIncrementalRendering;
4413    }
4414
4415    m_milestonesPendingPaint = 0;
4416
4417    if (milestonesAchieved)
4418        page->mainFrame().loader().didLayout(milestonesAchieved);
4419}
4420
4421void FrameView::setVisualUpdatesAllowedByClient(bool visualUpdatesAllowed)
4422{
4423    if (m_visualUpdatesAllowedByClient == visualUpdatesAllowed)
4424        return;
4425
4426    m_visualUpdatesAllowedByClient = visualUpdatesAllowed;
4427
4428    frame().document()->setVisualUpdatesAllowedByClient(visualUpdatesAllowed);
4429}
4430
4431void FrameView::setScrollPinningBehavior(ScrollPinningBehavior pinning)
4432{
4433    m_scrollPinningBehavior = pinning;
4434
4435    if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
4436        scrollingCoordinator->setScrollPinningBehavior(pinning);
4437
4438    updateScrollbars(scrollOffset());
4439}
4440
4441ScrollBehaviorForFixedElements FrameView::scrollBehaviorForFixedElements() const
4442{
4443    return frame().settings().backgroundShouldExtendBeyondPage() ? StickToViewportBounds : StickToDocumentBounds;
4444}
4445
4446RenderView* FrameView::renderView() const
4447{
4448    return frame().contentRenderer();
4449}
4450
4451int FrameView::mapFromLayoutToCSSUnits(LayoutUnit value) const
4452{
4453    return value / (frame().pageZoomFactor() * frame().frameScaleFactor());
4454}
4455
4456LayoutUnit FrameView::mapFromCSSToLayoutUnits(int value) const
4457{
4458    return value * frame().pageZoomFactor() * frame().frameScaleFactor();
4459}
4460
4461void FrameView::didAddWidgetToRenderTree(Widget& widget)
4462{
4463    ASSERT(!m_widgetsInRenderTree.contains(&widget));
4464    m_widgetsInRenderTree.add(&widget);
4465}
4466
4467void FrameView::willRemoveWidgetFromRenderTree(Widget& widget)
4468{
4469    ASSERT(m_widgetsInRenderTree.contains(&widget));
4470    m_widgetsInRenderTree.remove(&widget);
4471}
4472
4473static Vector<RefPtr<Widget>> collectAndProtectWidgets(const HashSet<Widget*>& set)
4474{
4475    Vector<RefPtr<Widget>> widgets;
4476    copyToVector(set, widgets);
4477    return widgets;
4478}
4479
4480void FrameView::updateWidgetPositions()
4481{
4482    // updateWidgetPosition() can possibly cause layout to be re-entered (via plug-ins running
4483    // scripts in response to NPP_SetWindow, for example), so we need to keep the Widgets
4484    // alive during enumeration.
4485    auto protectedWidgets = collectAndProtectWidgets(m_widgetsInRenderTree);
4486
4487    for (unsigned i = 0, size = protectedWidgets.size(); i < size; ++i) {
4488        if (RenderWidget* renderWidget = RenderWidget::find(protectedWidgets[i].get()))
4489            renderWidget->updateWidgetPosition();
4490    }
4491}
4492
4493void FrameView::notifyWidgets(WidgetNotification notification)
4494{
4495    auto protectedWidgets = collectAndProtectWidgets(m_widgetsInRenderTree);
4496
4497    for (unsigned i = 0, size = protectedWidgets.size(); i < size; ++i)
4498        protectedWidgets[i]->notifyWidget(notification);
4499}
4500
4501void FrameView::setExposedRect(FloatRect exposedRect)
4502{
4503    if (m_exposedRect == exposedRect)
4504        return;
4505    m_exposedRect = exposedRect;
4506
4507    // FIXME: We should support clipping to the exposed rect for subframes as well.
4508    if (!m_frame->isMainFrame())
4509        return;
4510    if (TiledBacking* tiledBacking = this->tiledBacking()) {
4511        adjustTiledBackingCoverage();
4512        tiledBacking->setTiledScrollingIndicatorPosition(exposedRect.location());
4513    }
4514
4515    if (auto* view = renderView())
4516        view->compositor().scheduleLayerFlush(false /* canThrottle */);
4517}
4518
4519void FrameView::setViewportSizeForCSSViewportUnits(IntSize size)
4520{
4521    if (m_hasOverrideViewportSize && m_overrideViewportSize == size)
4522        return;
4523
4524    m_overrideViewportSize = size;
4525    m_hasOverrideViewportSize = true;
4526
4527    if (Document* document = m_frame->document())
4528        document->styleResolverChanged(DeferRecalcStyle);
4529}
4530
4531IntSize FrameView::viewportSizeForCSSViewportUnits() const
4532{
4533    if (m_hasOverrideViewportSize)
4534        return m_overrideViewportSize;
4535
4536    return visibleContentRectIncludingScrollbars().size();
4537}
4538
4539} // namespace WebCore
4540