From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WebCore/page/FrameView.cpp | 3137 ++++++++++++++++++++++++------------- 1 file changed, 2089 insertions(+), 1048 deletions(-) (limited to 'Source/WebCore/page/FrameView.cpp') diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp index 804c0420f..725c62f32 100644 --- a/Source/WebCore/page/FrameView.cpp +++ b/Source/WebCore/page/FrameView.cpp @@ -3,7 +3,7 @@ * 1999 Lars Knoll * 1999 Antti Koivisto * 2000 Dirk Mueller - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2004-2017 Apple Inc. All rights reserved. * (C) 2006 Graham Dennis (graham.dennis@gmail.com) * (C) 2006 Alexey Proskuryakov (ap@nypop.com) * Copyright (C) 2009 Google Inc. All rights reserved. @@ -28,40 +28,55 @@ #include "FrameView.h" #include "AXObjectCache.h" -#include "AnimationController.h" #include "BackForwardController.h" +#include "CSSAnimationController.h" #include "CachedImage.h" #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" #include "DOMWindow.h" +#include "DebugPageOverlays.h" #include "DocumentMarkerController.h" #include "EventHandler.h" +#include "EventNames.h" #include "FloatRect.h" #include "FocusController.h" -#include "FontCache.h" -#include "FontLoader.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" #include "FrameSelection.h" #include "FrameTree.h" #include "GraphicsContext.h" +#include "HTMLBodyElement.h" #include "HTMLDocument.h" +#include "HTMLEmbedElement.h" #include "HTMLFrameElement.h" #include "HTMLFrameSetElement.h" +#include "HTMLHtmlElement.h" +#include "HTMLIFrameElement.h" #include "HTMLNames.h" +#include "HTMLObjectElement.h" #include "HTMLPlugInImageElement.h" +#include "ImageDocument.h" #include "InspectorClient.h" #include "InspectorController.h" #include "InspectorInstrumentation.h" +#include "Logging.h" #include "MainFrame.h" +#include "MemoryCache.h" +#include "MemoryPressureHandler.h" #include "OverflowEvent.h" +#include "Page.h" +#include "PageCache.h" +#include "PageOverlayController.h" #include "ProgressTracker.h" #include "RenderEmbeddedObject.h" #include "RenderFullScreen.h" #include "RenderIFrame.h" +#include "RenderInline.h" #include "RenderLayer.h" #include "RenderLayerBacking.h" +#include "RenderLayerCompositor.h" +#include "RenderSVGRoot.h" #include "RenderScrollbar.h" #include "RenderScrollbarPart.h" #include "RenderStyle.h" @@ -69,47 +84,35 @@ #include "RenderTheme.h" #include "RenderView.h" #include "RenderWidget.h" +#include "SVGDocument.h" +#include "SVGSVGElement.h" +#include "ScriptedAnimationController.h" #include "ScrollAnimator.h" #include "ScrollingCoordinator.h" #include "Settings.h" #include "StyleResolver.h" +#include "StyleScope.h" #include "TextResourceDecoder.h" #include "TextStream.h" +#include "TiledBacking.h" +#include "WheelEventTestTrigger.h" #include #include -#include - -#if USE(ACCELERATED_COMPOSITING) -#include "RenderLayerCompositor.h" -#include "TiledBacking.h" -#endif - -#if ENABLE(SVG) -#include "RenderSVGRoot.h" -#include "SVGDocument.h" -#include "SVGSVGElement.h" -#endif +#include +#include -#if USE(TILED_BACKING_STORE) +#if USE(COORDINATED_GRAPHICS) #include "TiledBackingStore.h" #endif -#if ENABLE(TEXT_AUTOSIZING) -#include "TextAutosizer.h" +#if ENABLE(CSS_SCROLL_SNAP) +#include "AxisScrollSnapOffsets.h" #endif #if PLATFORM(IOS) #include "DocumentLoader.h" -#include "Logging.h" -#include "MemoryCache.h" -#include "MemoryPressureHandler.h" -#include "SystemMemory.h" -#include "TileCache.h" -#endif - -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) -#include "HTMLMediaElement.h" +#include "LegacyTileCache.h" #endif namespace WebCore { @@ -128,7 +131,7 @@ static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLay flags &= ~RenderLayer::CheckForRepaint; flags |= RenderLayer::NeedsFullRepaintInBacking; } - if (isRelayoutingSubtree && layer->isPaginated()) + if (isRelayoutingSubtree && layer->enclosingPaginationLayer(RenderLayer::IncludeCompositedPaginatedLayers)) flags |= RenderLayer::UpdatePagination; return flags; } @@ -160,33 +163,107 @@ Pagination::Mode paginationModeForRenderStyle(const RenderStyle& style) return Pagination::BottomToTopPaginated; } +class SubtreeLayoutStateMaintainer { +public: + SubtreeLayoutStateMaintainer(RenderElement* subtreeLayoutRoot) + : m_layoutRoot(subtreeLayoutRoot) + { + if (m_layoutRoot) { + RenderView& view = m_layoutRoot->view(); + view.pushLayoutState(*m_layoutRoot); + if (shouldDisableLayoutStateForSubtree()) { + view.disableLayoutState(); + m_didDisableLayoutState = true; + } + } + } + + ~SubtreeLayoutStateMaintainer() + { + if (m_layoutRoot) { + RenderView& view = m_layoutRoot->view(); + view.popLayoutState(*m_layoutRoot); + if (m_didDisableLayoutState) + view.enableLayoutState(); + } + } + + bool shouldDisableLayoutStateForSubtree() + { + for (auto* renderer = m_layoutRoot; renderer; renderer = renderer->container()) { + if (renderer->hasTransform() || renderer->hasReflection()) + return true; + } + return false; + } + +private: + RenderElement* m_layoutRoot { nullptr }; + bool m_didDisableLayoutState { false }; +}; + +#ifndef NDEBUG +class RenderTreeNeedsLayoutChecker { +public : + RenderTreeNeedsLayoutChecker(const RenderElement& layoutRoot) + : m_layoutRoot(layoutRoot) + { + } + + ~RenderTreeNeedsLayoutChecker() + { + auto reportNeedsLayoutError = [] (const RenderObject& renderer) { + WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "post-layout: dirty renderer(s)"); + renderer.showRenderTreeForThis(); + ASSERT_NOT_REACHED(); + }; + + if (m_layoutRoot.needsLayout()) { + reportNeedsLayoutError(m_layoutRoot); + return; + } + + for (auto* descendant = m_layoutRoot.firstChild(); descendant; descendant = descendant->nextInPreOrder(&m_layoutRoot)) { + if (!descendant->needsLayout()) + continue; + + reportNeedsLayoutError(*descendant); + return; + } + } + +private: + const RenderElement& m_layoutRoot; +}; +#endif + FrameView::FrameView(Frame& frame) - : m_frame(&frame) + : m_frame(frame) , m_canHaveScrollbars(true) - , m_layoutTimer(this, &FrameView::layoutTimerFired) - , m_layoutRoot(0) + , m_layoutTimer(*this, &FrameView::layoutTimerFired) , m_layoutPhase(OutsideLayout) , m_inSynchronousPostLayout(false) - , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) - , m_updateEmbeddedObjectsTimer(this, &FrameView::updateEmbeddedObjectsTimerFired) + , m_postLayoutTasksTimer(*this, &FrameView::performPostLayoutTasks) + , m_updateEmbeddedObjectsTimer(*this, &FrameView::updateEmbeddedObjectsTimerFired) , m_isTransparent(false) , m_baseBackgroundColor(Color::white) , m_mediaType("screen") , m_overflowStatusDirty(true) - , m_viewportRenderer(0) , m_wasScrolledByUser(false) , m_inProgrammaticScroll(false) , m_safeToPropagateScrollToParent(true) + , m_delayedScrollEventTimer(*this, &FrameView::sendScrollEvent) , m_isTrackingRepaints(false) , m_shouldUpdateWhileOffscreen(true) - , m_exposedRect(FloatRect::infiniteRect()) - , m_deferSetNeedsLayouts(0) + , m_deferSetNeedsLayoutCount(0) , m_setNeedsLayoutWasDeferred(false) , m_speculativeTilingEnabled(false) - , m_speculativeTilingEnableTimer(this, &FrameView::speculativeTilingEnableTimerFired) + , m_speculativeTilingEnableTimer(*this, &FrameView::speculativeTilingEnableTimerFired) #if PLATFORM(IOS) , m_useCustomFixedPositionLayoutRect(false) + , m_useCustomSizeForResizeEvent(false) #endif + , m_hasOverrideViewportSize(false) , m_shouldAutoSize(false) , m_inAutoSize(false) , m_didRunAutosize(false) @@ -195,29 +272,40 @@ FrameView::FrameView(Frame& frame) , m_footerHeight(0) , m_milestonesPendingPaint(0) , m_visualUpdatesAllowedByClient(true) + , m_hasFlippedBlockRenderers(false) , m_scrollPinningBehavior(DoNotPin) { init(); - if (frame.isMainFrame()) { - ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed); - ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAutomatic); +#if ENABLE(RUBBER_BANDING) + ScrollElasticity verticalElasticity = ScrollElasticityNone; + ScrollElasticity horizontalElasticity = ScrollElasticityNone; + if (m_frame->isMainFrame()) { + verticalElasticity = m_frame->page() ? m_frame->page()->verticalScrollElasticity() : ScrollElasticityAllowed; + horizontalElasticity = m_frame->page() ? m_frame->page()->horizontalScrollElasticity() : ScrollElasticityAllowed; + } else if (m_frame->settings().rubberBandingForSubScrollableRegionsEnabled()) { + verticalElasticity = ScrollElasticityAutomatic; + horizontalElasticity = ScrollElasticityAutomatic; } + + ScrollableArea::setVerticalScrollElasticity(verticalElasticity); + ScrollableArea::setHorizontalScrollElasticity(horizontalElasticity); +#endif } -PassRefPtr FrameView::create(Frame& frame) +Ref FrameView::create(Frame& frame) { - RefPtr view = adoptRef(new FrameView(frame)); + Ref view = adoptRef(*new FrameView(frame)); view->show(); - return view.release(); + return view; } -PassRefPtr FrameView::create(Frame& frame, const IntSize& initialSize) +Ref FrameView::create(Frame& frame, const IntSize& initialSize) { - RefPtr view = adoptRef(new FrameView(frame)); + Ref view = adoptRef(*new FrameView(frame)); view->Widget::setFrameRect(IntRect(view->location(), initialSize)); view->show(); - return view.release(); + return view; } FrameView::~FrameView() @@ -245,10 +333,8 @@ void FrameView::reset() m_cannotBlitToWindow = false; m_isOverlapped = false; m_contentIsOpaque = false; - m_borderX = 30; - m_borderY = 30; m_layoutTimer.stop(); - m_layoutRoot = 0; + m_layoutRoot = nullptr; m_delayedLayout = false; m_needsFullRepaint = true; m_layoutSchedulingEnabled = true; @@ -262,6 +348,7 @@ void FrameView::reset() m_firstLayoutCallbackPending = false; m_wasScrolledByUser = false; m_safeToPropagateScrollToParent = true; + m_delayedScrollEventTimer.stop(); m_lastViewportSize = IntSize(); m_lastZoomFactor = 1.0f; m_isTrackingRepaints = false; @@ -273,13 +360,17 @@ void FrameView::reset() m_visuallyNonEmptyPixelCount = 0; m_isVisuallyNonEmpty = false; m_firstVisuallyNonEmptyLayoutCallbackPending = true; - m_maintainScrollPositionAnchor = 0; + m_needsDeferredScrollbarsUpdate = false; + m_maintainScrollPositionAnchor = nullptr; } void FrameView::removeFromAXObjectCache() { - if (AXObjectCache* cache = axObjectCache()) + if (AXObjectCache* cache = axObjectCache()) { + if (HTMLFrameOwnerElement* owner = frame().ownerElement()) + cache->childrenChanged(owner->renderer()); cache->remove(this); + } } void FrameView::resetScrollbars() @@ -312,12 +403,12 @@ void FrameView::init() // Propagate the marginwidth/height and scrolling modes to the view. Element* ownerElement = frame().ownerElement(); - if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { - HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement); - if (frameElt->scrollingMode() == ScrollbarAlwaysOff) + if (is(ownerElement)) { + HTMLFrameElementBase& frameElement = downcast(*ownerElement); + if (frameElement.scrollingMode() == ScrollbarAlwaysOff) setCanHaveScrollbars(false); - LayoutUnit marginWidth = frameElt->marginWidth(); - LayoutUnit marginHeight = frameElt->marginHeight(); + LayoutUnit marginWidth = frameElement.marginWidth(); + LayoutUnit marginHeight = frameElement.marginHeight(); if (marginWidth != -1) setMarginWidth(marginWidth); if (marginHeight != -1) @@ -338,7 +429,7 @@ void FrameView::prepareForDetach() if (frame().page()) { if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator()) - scrollingCoordinator->willDestroyScrollableArea(this); + scrollingCoordinator->willDestroyScrollableArea(*this); } } @@ -358,7 +449,14 @@ void FrameView::detachCustomScrollbars() void FrameView::recalculateScrollbarOverlayStyle() { ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle(); - ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault; + std::optional clientOverlayStyle = frame().page() ? frame().page()->chrome().client().preferredScrollbarOverlayStyle() : ScrollbarOverlayStyleDefault; + if (clientOverlayStyle) { + if (clientOverlayStyle.value() != oldOverlayStyle) + setScrollbarOverlayStyle(clientOverlayStyle.value()); + return; + } + + ScrollbarOverlayStyle computedOverlayStyle = ScrollbarOverlayStyleDefault; Color backgroundColor = documentBackgroundColor(); if (backgroundColor.isValid()) { @@ -367,12 +465,12 @@ void FrameView::recalculateScrollbarOverlayStyle() // heuristic. double hue, saturation, lightness; backgroundColor.getHSL(hue, saturation, lightness); - if (lightness <= .5 && backgroundColor.alpha() > 0) - overlayStyle = ScrollbarOverlayStyleLight; + if (lightness <= .5 && backgroundColor.isVisible()) + computedOverlayStyle = ScrollbarOverlayStyleLight; } - if (oldOverlayStyle != overlayStyle) - setScrollbarOverlayStyle(overlayStyle); + if (oldOverlayStyle != computedOverlayStyle) + setScrollbarOverlayStyle(computedOverlayStyle); } void FrameView::clear() @@ -386,11 +484,20 @@ void FrameView::clear() #if PLATFORM(IOS) // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load. // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw. - if (TileCache* tileCache = this->tileCache()) - tileCache->setTilingMode(TileCache::Disabled); + if (LegacyTileCache* tileCache = legacyTileCache()) + tileCache->setTilingMode(LegacyTileCache::Disabled); #endif } +#if PLATFORM(IOS) +void FrameView::didReplaceMultipartContent() +{ + // Re-enable tile updates that were disabled in clear(). + if (LegacyTileCache* tileCache = legacyTileCache()) + tileCache->setTilingMode(LegacyTileCache::Normal); +} +#endif + bool FrameView::didFirstLayout() const { return !m_firstLayout; @@ -399,63 +506,50 @@ bool FrameView::didFirstLayout() const void FrameView::invalidateRect(const IntRect& rect) { if (!parent()) { - if (HostWindow* window = hostWindow()) - window->invalidateContentsAndRootView(rect, false /*immediate*/); + if (auto* page = frame().page()) + page->chrome().invalidateContentsAndRootView(rect); return; } - RenderWidget* renderer = frame().ownerRenderer(); + auto* renderer = frame().ownerRenderer(); if (!renderer) return; IntRect repaintRect = rect; - repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(), - renderer->borderTop() + renderer->paddingTop()); + repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop()); renderer->repaintRectangle(repaintRect); } void FrameView::setFrameRect(const IntRect& newRect) { + Ref protectedThis(*this); IntRect oldRect = frameRect(); if (newRect == oldRect) return; -#if ENABLE(TEXT_AUTOSIZING) - // Autosized font sizes depend on the width of the viewing area. - if (newRect.width() != oldRect.width()) { - Page* page = frame().page(); - if (frame().isMainFrame() && page->settings().textAutosizingEnabled()) { - for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) - frame().document()->textAutosizer()->recalculateMultipliers(); - } - } -#endif - ScrollView::setFrameRect(newRect); updateScrollableAreaSet(); -#if USE(ACCELERATED_COMPOSITING) if (RenderView* renderView = this->renderView()) { if (renderView->usesCompositing()) renderView->compositor().frameViewDidChangeSize(); } -#endif - if (!frameFlatteningEnabled()) - sendResizeEventIfNeeded(); + if (frame().isMainFrame()) + frame().mainFrame().pageOverlayController().didChangeViewSize(); + + viewportContentsChanged(); } -#if ENABLE(REQUEST_ANIMATION_FRAME) bool FrameView::scheduleAnimation() { - if (HostWindow* window = hostWindow()) { - window->scheduleAnimation(); - return true; - } - return false; + auto* page = frame().page(); + if (!page) + return false; + page->chrome().scheduleAnimation(); + return true; } -#endif void FrameView::setMarginWidth(LayoutUnit w) { @@ -512,42 +606,67 @@ void FrameView::updateCanHaveScrollbars() setCanHaveScrollbars(true); } -PassRefPtr FrameView::createScrollbar(ScrollbarOrientation orientation) +Ref FrameView::createScrollbar(ScrollbarOrientation orientation) { - if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame()) - return ScrollView::createScrollbar(orientation); - // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles). Document* doc = frame().document(); // Try the element first as a scrollbar source. - Element* body = doc ? doc->body() : 0; + HTMLElement* body = doc ? doc->bodyOrFrameset() : nullptr; if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR)) - return RenderScrollbar::createCustomScrollbar(this, orientation, body); + return RenderScrollbar::createCustomScrollbar(*this, orientation, body); // If the didn't have a custom style, then the root element might. - Element* docElement = doc ? doc->documentElement() : 0; + Element* docElement = doc ? doc->documentElement() : nullptr; if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR)) - return RenderScrollbar::createCustomScrollbar(this, orientation, docElement); + return RenderScrollbar::createCustomScrollbar(*this, orientation, docElement); // If we have an owning iframe/frame element, then it can set the custom scrollbar also. RenderWidget* frameRenderer = frame().ownerRenderer(); if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR)) - return RenderScrollbar::createCustomScrollbar(this, orientation, 0, &frame()); + return RenderScrollbar::createCustomScrollbar(*this, orientation, nullptr, &frame()); // Nobody set a custom style, so we just use a native scrollbar. return ScrollView::createScrollbar(orientation); } +void FrameView::didRestoreFromPageCache() +{ + // When restoring from page cache, the main frame stays in place while subframes get swapped in. + // We update the scrollable area set to ensure that scrolling data structures get invalidated. + updateScrollableAreaSet(); +} + +void FrameView::willDestroyRenderTree() +{ + detachCustomScrollbars(); + m_layoutRoot = nullptr; +} + +void FrameView::didDestroyRenderTree() +{ + ASSERT(!m_layoutRoot); + ASSERT(m_widgetsInRenderTree.isEmpty()); + + // If the render tree is destroyed below FrameView::updateEmbeddedObjects(), there will still be a null sentinel in the set. + // Everything else should have removed itself as the tree was felled. + ASSERT(!m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty() || (m_embeddedObjectsToUpdate->size() == 1 && m_embeddedObjectsToUpdate->first() == nullptr)); + + ASSERT(!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()); + ASSERT(!m_slowRepaintObjects || m_slowRepaintObjects->isEmpty()); + + ASSERT(!frame().animation().hasAnimations()); +} + void FrameView::setContentsSize(const IntSize& size) { if (size == contentsSize()) return; - m_deferSetNeedsLayouts++; + m_deferSetNeedsLayoutCount++; ScrollView::setContentsSize(size); - ScrollView::contentsResized(); + contentsResized(); Page* page = frame().page(); if (!page) @@ -555,12 +674,17 @@ void FrameView::setContentsSize(const IntSize& size) updateScrollableAreaSet(); - page->chrome().contentsSizeChanged(&frame(), size); // Notify only. + page->chrome().contentsSizeChanged(frame(), size); // Notify only. + + if (frame().isMainFrame()) { + frame().mainFrame().pageOverlayController().didChangeDocumentSize(); + PageCache::singleton().markPagesForContentsSizeChanged(*page); + } - ASSERT(m_deferSetNeedsLayouts); - m_deferSetNeedsLayouts--; + ASSERT(m_deferSetNeedsLayoutCount); + m_deferSetNeedsLayoutCount--; - if (!m_deferSetNeedsLayouts) + if (!m_deferSetNeedsLayoutCount) m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen. } @@ -575,11 +699,13 @@ void FrameView::adjustViewSize() const IntRect rect = renderView->documentRect(); const IntSize& size = rect.size(); ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize()); - + + LOG_WITH_STREAM(Layout, stream << "FrameView " << this << " adjustViewSize: unscaled document rect changed to " << renderView->unscaledDocumentRect() << " (scaled to " << size << ")"); + setContentsSize(size); } -void FrameView::applyOverflowToViewport(RenderElement* o, ScrollbarMode& hMode, ScrollbarMode& vMode) +void FrameView::applyOverflowToViewport(const RenderElement& renderer, ScrollbarMode& hMode, ScrollbarMode& vMode) { // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats // overflow:hidden and overflow:scroll on as applying to the document's @@ -592,18 +718,17 @@ void FrameView::applyOverflowToViewport(RenderElement* o, ScrollbarMode& hMode, bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight()); - EOverflow overflowX = o->style().overflowX(); - EOverflow overflowY = o->style().overflowY(); + EOverflow overflowX = renderer.style().overflowX(); + EOverflow overflowY = renderer.style().overflowY(); -#if ENABLE(SVG) - if (o->isSVGRoot()) { - // overflow is ignored in stand-alone SVG documents. - if (!toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) - return; - overflowX = OHIDDEN; - overflowY = OHIDDEN; + if (is(renderer)) { + // FIXME: evaluate if we can allow overflow for these cases too. + // Overflow is always hidden when stand-alone SVG documents are embedded. + if (downcast(renderer).isEmbeddedThroughFrameContainingSVGDocument()) { + overflowX = OHIDDEN; + overflowY = OHIDDEN; + } } -#endif switch (overflowX) { case OHIDDEN: @@ -640,41 +765,38 @@ void FrameView::applyOverflowToViewport(RenderElement* o, ScrollbarMode& hMode, // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort(). ; } - - m_viewportRenderer = o; } void FrameView::applyPaginationToViewport() { - Document* document = frame().document(); - auto documentElement = document->documentElement(); - RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr; - RenderElement* documentOrBodyRenderer = documentRenderer; - auto body = document->body(); - if (body && body->renderer()) { - if (body->hasTagName(bodyTag)) - documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && documentElement->hasTagName(htmlTag) ? body->renderer() : documentRenderer; + auto* document = frame().document(); + auto* documentElement = document ? document->documentElement() : nullptr; + if (!documentElement || !documentElement->renderer()) { + setPagination(Pagination()); + return; } - Pagination pagination; + auto& documentRenderer = *documentElement->renderer(); + auto* documentOrBodyRenderer = &documentRenderer; - if (!documentOrBodyRenderer) { - setPagination(pagination); - return; + auto* body = document->body(); + if (body && body->renderer()) { + documentOrBodyRenderer = documentRenderer.style().overflowX() == OVISIBLE && is(*documentElement) ? + body->renderer() : &documentRenderer; } + Pagination pagination; EOverflow overflowY = documentOrBodyRenderer->style().overflowY(); if (overflowY == OPAGEDX || overflowY == OPAGEDY) { pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style()); pagination.gap = static_cast(documentOrBodyRenderer->style().columnGap()); } - setPagination(pagination); } void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy) { - m_viewportRenderer = 0; + m_viewportRendererType = ViewportRendererType::None; const HTMLFrameOwnerElement* owner = frame().ownerElement(); if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) { @@ -685,51 +807,75 @@ void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, Scrollbar if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) { hMode = ScrollbarAuto; - // Seamless documents begin with heights of 0; we special case that here - // to correctly render documents that don't need scrollbars. - IntSize fullVisibleSize = visibleContentRectIncludingScrollbars(LegacyIOSDocumentVisibleRect).size(); - bool isSeamlessDocument = frame().document() && frame().document()->shouldDisplaySeamlesslyWithParent(); - vMode = (isSeamlessDocument && !fullVisibleSize.height()) ? ScrollbarAlwaysOff : ScrollbarAuto; + vMode = ScrollbarAuto; } else { hMode = ScrollbarAlwaysOff; vMode = ScrollbarAlwaysOff; } - if (!m_layoutRoot) { - Document* document = frame().document(); - auto documentElement = document->documentElement(); - RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr; - auto body = document->body(); - if (body && body->renderer()) { - if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) { - vMode = ScrollbarAlwaysOff; - hMode = ScrollbarAlwaysOff; - } else if (body->hasTagName(bodyTag)) { - // It's sufficient to just check the X overflow, - // since it's illegal to have visible in only one direction. - RenderElement* o = rootRenderer->style().overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer; - applyOverflowToViewport(o, hMode, vMode); + if (m_layoutRoot) + return; + + auto* document = frame().document(); + if (!document) + return; + + auto* documentElement = document->documentElement(); + if (!documentElement) + return; + + auto* bodyOrFrameset = document->bodyOrFrameset(); + auto* rootRenderer = documentElement->renderer(); + if (!bodyOrFrameset || !bodyOrFrameset->renderer()) { + if (rootRenderer) { + applyOverflowToViewport(*rootRenderer, hMode, vMode); + m_viewportRendererType = ViewportRendererType::Document; + } + return; + } + + if (is(*bodyOrFrameset) && !frameFlatteningEnabled()) { + vMode = ScrollbarAlwaysOff; + hMode = ScrollbarAlwaysOff; + return; + } + + if (is(*bodyOrFrameset) && rootRenderer) { + // It's sufficient to just check the X overflow, + // since it's illegal to have visible in only one direction. + if (rootRenderer->style().overflowX() == OVISIBLE && is(documentElement)) { + auto* bodyRenderer = bodyOrFrameset->renderer(); + if (bodyRenderer) { + applyOverflowToViewport(*bodyRenderer, hMode, vMode); + m_viewportRendererType = ViewportRendererType::Body; } - } else if (rootRenderer) - applyOverflowToViewport(rootRenderer, hMode, vMode); - } + } else { + applyOverflowToViewport(*rootRenderer, hMode, vMode); + m_viewportRendererType = ViewportRendererType::Document; + } + } } -#if USE(ACCELERATED_COMPOSITING) -void FrameView::updateCompositingLayersAfterStyleChange() +void FrameView::willRecalcStyle() { RenderView* renderView = this->renderView(); if (!renderView) return; + renderView->compositor().willRecalcStyle(); +} + +bool FrameView::updateCompositingLayersAfterStyleChange() +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return false; + // If we expect to update compositing after an incipient layout, don't do so here. if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout()) - return; + return false; - RenderLayerCompositor& compositor = renderView->compositor(); - // This call will make sure the cached hasAcceleratedCompositing is updated from the pref - compositor.cacheAcceleratedCompositingFlags(); - compositor.updateCompositingLayers(CompositingUpdateAfterStyleChange); + return renderView->compositor().didRecalcStyleWithNoPendingLayout(); } void FrameView::updateCompositingLayersAfterLayout() @@ -755,32 +901,11 @@ void FrameView::clearBackingStores() compositor.clearBackingForAllLayers(); } -void FrameView::restoreBackingStores() -{ - RenderView* renderView = this->renderView(); - if (!renderView) - return; - - RenderLayerCompositor& compositor = renderView->compositor(); - compositor.enableCompositingMode(true); - compositor.updateCompositingLayers(CompositingUpdateAfterLayout); -} - -bool FrameView::usesCompositedScrolling() const -{ - RenderView* renderView = this->renderView(); - if (!renderView) - return false; - if (frame().settings().compositedScrollingForFramesEnabled()) - return renderView->compositor().inForcedCompositingMode(); - return false; -} - GraphicsLayer* FrameView::layerForScrolling() const { RenderView* renderView = this->renderView(); if (!renderView) - return 0; + return nullptr; return renderView->compositor().scrollLayer(); } @@ -788,7 +913,7 @@ GraphicsLayer* FrameView::layerForHorizontalScrollbar() const { RenderView* renderView = this->renderView(); if (!renderView) - return 0; + return nullptr; return renderView->compositor().layerForHorizontalScrollbar(); } @@ -796,7 +921,7 @@ GraphicsLayer* FrameView::layerForVerticalScrollbar() const { RenderView* renderView = this->renderView(); if (!renderView) - return 0; + return nullptr; return renderView->compositor().layerForVerticalScrollbar(); } @@ -804,7 +929,7 @@ GraphicsLayer* FrameView::layerForScrollCorner() const { RenderView* renderView = this->renderView(); if (!renderView) - return 0; + return nullptr; return renderView->compositor().layerForScrollCorner(); } @@ -812,11 +937,11 @@ TiledBacking* FrameView::tiledBacking() const { RenderView* renderView = this->renderView(); if (!renderView) - return 0; + return nullptr; RenderLayerBacking* backing = renderView->layer()->backing(); if (!backing) - return 0; + return nullptr; return backing->graphicsLayer()->tiledBacking(); } @@ -831,7 +956,16 @@ uint64_t FrameView::scrollLayerID() const if (!backing) return 0; - return backing->scrollLayerID(); + return backing->scrollingNodeIDForRole(Scrolling); +} + +ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return nullptr; + + return renderView->compositor().scrollableAreaForScrollLayerID(nodeID); } #if ENABLE(RUBBER_BANDING) @@ -839,7 +973,7 @@ GraphicsLayer* FrameView::layerForOverhangAreas() const { RenderView* renderView = this->renderView(); if (!renderView) - return 0; + return nullptr; return renderView->compositor().layerForOverhangAreas(); } @@ -847,7 +981,7 @@ GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const { RenderView* renderView = this->renderView(); if (!renderView) - return 0; + return nullptr; return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer); } @@ -856,14 +990,56 @@ GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) co { RenderView* renderView = this->renderView(); if (!renderView) - return 0; + return nullptr; return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer); } #endif // ENABLE(RUBBER_BANDING) -bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush) +#if ENABLE(CSS_SCROLL_SNAP) +void FrameView::updateSnapOffsets() +{ + if (!frame().document()) + return; + + // FIXME: Should we allow specifying snap points through tags too? + HTMLElement* body = frame().document()->bodyOrFrameset(); + if (!renderView() || !body || !body->renderer()) + return; + + updateSnapOffsetsForScrollableArea(*this, *body, *renderView(), body->renderer()->style()); +} + +bool FrameView::isScrollSnapInProgress() const +{ + if (scrollbarsSuppressed()) + return false; + + // If the scrolling thread updates the scroll position for this FrameView, then we should return + // ScrollingCoordinator::isScrollSnapInProgress(). + if (Page* page = frame().page()) { + if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) { + if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(*this)) + return scrollingCoordinator->isScrollSnapInProgress(); + } + } + + // If the main thread updates the scroll position for this FrameView, we should return + // ScrollAnimator::isScrollSnapInProgress(). + if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) + return scrollAnimator->isScrollSnapInProgress(); + + return false; +} + +void FrameView::updateScrollingCoordinatorScrollSnapProperties() const +{ + renderView()->compositor().updateScrollSnapPropertiesWithFrameView(*this); +} +#endif + +bool FrameView::flushCompositingStateForThisFrame(const Frame& rootFrameForFlush) { RenderView* renderView = this->renderView(); if (!renderView) @@ -877,12 +1053,11 @@ bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush) return false; #if PLATFORM(IOS) - if (TileCache* tileCache = this->tileCache()) + if (LegacyTileCache* tileCache = legacyTileCache()) tileCache->doPendingRepaints(); #endif - renderView->compositor().flushPendingLayerChanges(rootFrameForFlush == &frame()); - + renderView->compositor().flushPendingLayerChanges(&rootFrameForFlush == m_frame.ptr()); return true; } @@ -896,22 +1071,22 @@ GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platform { // To find the Widget that corresponds with platformWidget we have to do a linear // search of our child widgets. - Widget* foundWidget = nullptr; + const Widget* foundWidget = nullptr; for (auto& widget : children()) { if (widget->platformWidget() != platformWidget) continue; - foundWidget = widget.get(); + foundWidget = widget.ptr(); break; } if (!foundWidget) return nullptr; - auto* renderWidget = RenderWidget::find(foundWidget); + auto* renderWidget = RenderWidget::find(*foundWidget); if (!renderWidget) return nullptr; - RenderLayer* widgetLayer = renderWidget->layer(); + auto* widgetLayer = renderWidget->layer(); if (!widgetLayer || !widgetLayer->isComposited()) return nullptr; @@ -925,7 +1100,36 @@ void FrameView::scheduleLayerFlushAllowingThrottling() return; view->compositor().scheduleLayerFlush(true /* canThrottle */); } -#endif // USE(ACCELERATED_COMPOSITING) + +LayoutRect FrameView::fixedScrollableAreaBoundsInflatedForScrolling(const LayoutRect& uninflatedBounds) const +{ + LayoutPoint scrollPosition; + LayoutSize topLeftExpansion; + LayoutSize bottomRightExpansion; + + if (frame().settings().visualViewportEnabled()) { + // FIXME: this is wrong under zooming; uninflatedBounds is scaled but the scroll positions are not. + scrollPosition = layoutViewportRect().location(); + topLeftExpansion = scrollPosition - unscaledMinimumScrollPosition(); + bottomRightExpansion = unscaledMaximumScrollPosition() - scrollPosition; + } else { + scrollPosition = scrollPositionRespectingCustomFixedPosition(); + topLeftExpansion = scrollPosition - minimumScrollPosition(); + bottomRightExpansion = maximumScrollPosition() - scrollPosition; + } + + return LayoutRect(uninflatedBounds.location() - topLeftExpansion, uninflatedBounds.size() + topLeftExpansion + bottomRightExpansion); +} + +LayoutPoint FrameView::scrollPositionRespectingCustomFixedPosition() const +{ +#if PLATFORM(IOS) + if (!frame().settings().visualViewportEnabled()) + return useCustomFixedPositionLayoutRect() ? customFixedPositionLayoutRect().location() : scrollPosition(); +#endif + + return scrollPositionForFixedPosition(); +} void FrameView::setHeaderHeight(int headerHeight) { @@ -947,103 +1151,101 @@ void FrameView::setFooterHeight(int footerHeight) renderView->setNeedsLayout(); } -bool FrameView::hasCompositedContent() const -{ -#if USE(ACCELERATED_COMPOSITING) - if (RenderView* renderView = this->renderView()) - return renderView->compositor().inCompositingMode(); -#endif - return false; -} - -bool FrameView::hasCompositedContentIncludingDescendants() const +float FrameView::topContentInset(TopContentInsetType contentInsetTypeToReturn) const { -#if USE(ACCELERATED_COMPOSITING) - for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { - RenderView* renderView = frame->contentRenderer(); - if (RenderLayerCompositor* compositor = renderView ? &renderView->compositor() : 0) { - if (compositor->inCompositingMode()) - return true; + if (platformWidget() && contentInsetTypeToReturn == TopContentInsetType::WebCoreOrPlatformContentInset) + return platformTopContentInset(); - if (!RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) - break; - } - } -#endif - return false; + if (!frame().isMainFrame()) + return 0; + + Page* page = frame().page(); + return page ? page->topContentInset() : 0; } - -bool FrameView::hasCompositingAncestor() const + +void FrameView::topContentInsetDidChange(float newTopContentInset) { -#if USE(ACCELERATED_COMPOSITING) - for (Frame* frame = this->frame().tree().parent(); frame; frame = frame->tree().parent()) { - if (FrameView* view = frame->view()) { - if (view->hasCompositedContent()) - return true; - } - } -#endif + RenderView* renderView = this->renderView(); + if (!renderView) + return; + + if (platformWidget()) + platformSetTopContentInset(newTopContentInset); + + layout(); + + updateScrollbars(scrollPosition()); + if (renderView->usesCompositing()) + renderView->compositor().frameViewDidChangeSize(); + + if (TiledBacking* tiledBacking = this->tiledBacking()) + tiledBacking->setTopContentInset(newTopContentInset); +} + +void FrameView::topContentDirectionDidChange() +{ + m_needsDeferredScrollbarsUpdate = true; +} + +void FrameView::handleDeferredScrollbarsUpdateAfterDirectionChange() +{ + if (!m_needsDeferredScrollbarsUpdate) + return; + + m_needsDeferredScrollbarsUpdate = false; + + ASSERT(m_layoutPhase == InPostLayerPositionsUpdatedAfterLayout); + updateScrollbars(scrollPosition()); + positionScrollbarLayers(); +} + +bool FrameView::hasCompositedContent() const +{ + if (RenderView* renderView = this->renderView()) + return renderView->compositor().inCompositingMode(); return false; } // Sometimes (for plug-ins) we need to eagerly go into compositing mode. void FrameView::enterCompositingMode() { -#if USE(ACCELERATED_COMPOSITING) if (RenderView* renderView = this->renderView()) { renderView->compositor().enableCompositingMode(); if (!needsLayout()) renderView->compositor().scheduleCompositingLayerUpdate(); } -#endif } bool FrameView::isEnclosedInCompositingLayer() const { -#if USE(ACCELERATED_COMPOSITING) auto frameOwnerRenderer = frame().ownerRenderer(); if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint()) return true; if (FrameView* parentView = parentFrameView()) return parentView->isEnclosedInCompositingLayer(); -#endif return false; } bool FrameView::flushCompositingStateIncludingSubframes() { -#if USE(ACCELERATED_COMPOSITING) - bool allFramesFlushed = flushCompositingStateForThisFrame(&frame()); - - for (Frame* child = frame().tree().firstChild(); child; child = child->tree().traverseNext(&frame())) { - bool flushed = child->view()->flushCompositingStateForThisFrame(&frame()); + InspectorInstrumentation::willComposite(frame()); + + bool allFramesFlushed = flushCompositingStateForThisFrame(frame()); + + for (Frame* child = frame().tree().firstRenderedChild(); child; child = child->tree().traverseNextRendered(m_frame.ptr())) { + if (!child->view()) + continue; + bool flushed = child->view()->flushCompositingStateForThisFrame(frame()); allFramesFlushed &= flushed; } return allFramesFlushed; -#else // USE(ACCELERATED_COMPOSITING) - return true; -#endif } bool FrameView::isSoftwareRenderable() const { -#if USE(ACCELERATED_COMPOSITING) RenderView* renderView = this->renderView(); return !renderView || !renderView->compositor().has3DContent(); -#else - return true; -#endif -} - -void FrameView::didMoveOnscreen() -{ - contentAreaDidShow(); -} - -void FrameView::willMoveOffscreen() -{ - contentAreaDidHide(); } void FrameView::setIsInWindow(bool isInWindow) @@ -1052,14 +1254,8 @@ void FrameView::setIsInWindow(bool isInWindow) renderView->setIsInWindow(isInWindow); } -RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const -{ - return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot; -} - inline void FrameView::forceLayoutParentViewIfNeeded() { -#if ENABLE(SVG) RenderWidget* ownerRenderer = frame().ownerRenderer(); if (!ownerRenderer) return; @@ -1068,50 +1264,59 @@ inline void FrameView::forceLayoutParentViewIfNeeded() if (!contentBox) return; - RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox); - if (svgRoot->everHadLayout() && !svgRoot->needsLayout()) + auto& svgRoot = downcast(*contentBox); + if (svgRoot.everHadLayout() && !svgRoot.needsLayout()) return; + LOG(Layout, "FrameView %p forceLayoutParentViewIfNeeded scheduling layout on parent FrameView %p", this, &ownerRenderer->view().frameView()); + // If the embedded SVG document appears the first time, the ownerRenderer has already finished // layout without knowing about the existence of the embedded SVG document, because RenderReplaced - // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before + // embeddedContentBox() returns nullptr, as long as the embedded document isn't loaded yet. Before // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via