/* * Copyright (C) 1998, 1999 Torben Weis * 1999 Lars Knoll * 1999 Antti Koivisto * 2000 Dirk Mueller * Copyright (C) 2004, 2005, 2006, 2007, 2008 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. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "config.h" #include "FrameView.h" #include "AXObjectCache.h" #include "BackForwardController.h" #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" #include "DocumentMarkerController.h" #include "EventHandler.h" #include "FloatRect.h" #include "FocusController.h" #include "FontCache.h" #include "Frame.h" #include "FrameActionScheduler.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" #include "FrameTree.h" #include "GraphicsContext.h" #include "HTMLDocument.h" #include "HTMLFrameElement.h" #include "HTMLFrameSetElement.h" #include "HTMLNames.h" #include "HTMLPlugInImageElement.h" #include "InspectorClient.h" #include "InspectorController.h" #include "InspectorInstrumentation.h" #include "OverflowEvent.h" #include "RenderArena.h" #include "RenderEmbeddedObject.h" #include "RenderFullScreen.h" #include "RenderIFrame.h" #include "RenderLayer.h" #include "RenderPart.h" #include "RenderScrollbar.h" #include "RenderScrollbarPart.h" #include "RenderTheme.h" #include "RenderView.h" #include "ScrollAnimator.h" #include "ScrollingCoordinator.h" #include "Settings.h" #include "StyleResolver.h" #include "TextResourceDecoder.h" #include "TextStream.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 #if USE(TILED_BACKING_STORE) #include "TiledBackingStore.h" #endif #if ENABLE(TEXT_AUTOSIZING) #include "TextAutosizer.h" #endif namespace WebCore { using namespace HTMLNames; double FrameView::sCurrentPaintTimeStamp = 0.0; // REPAINT_THROTTLING now chooses default values for throttling parameters. // Should be removed when applications start using runtime configuration. #if ENABLE(REPAINT_THROTTLING) // Normal delay double FrameView::s_normalDeferredRepaintDelay = 0.016; // Negative value would mean that first few repaints happen without a delay double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0; // The delay grows on each repaint to this maximum value double FrameView::s_maxDeferredRepaintDelayDuringLoading = 2.5; // On each repaint the delay increses by this amount double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0.5; #else // FIXME: Repaint throttling could be good to have on all platform. // The balance between CPU use and repaint frequency will need some tuning for desktop. // More hooks may be needed to reset the delay on things like GIF and CSS animations. double FrameView::s_normalDeferredRepaintDelay = 0; double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0; double FrameView::s_maxDeferredRepaintDelayDuringLoading = 0; double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0; #endif // The maximum number of updateWidgets iterations that should be done before returning. static const unsigned maxUpdateWidgetsIterations = 2; static inline RenderView* rootRenderer(const FrameView* view) { return view->frame() ? view->frame()->contentRenderer() : 0; } static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint) { RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags; if (didFullRepaint) flags &= ~RenderLayer::CheckForRepaint; if (isRelayoutingSubtree && layer->isPaginated()) flags |= RenderLayer::UpdatePagination; return flags; } Pagination::Mode paginationModeForRenderStyle(RenderStyle* style) { EOverflow overflow = style->overflowY(); if (overflow != OPAGEDX && overflow != OPAGEDY) return Pagination::Unpaginated; bool isHorizontalWritingMode = style->isHorizontalWritingMode(); TextDirection textDirection = style->direction(); WritingMode writingMode = style->writingMode(); // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode // is horizontal, then we use TextDirection to choose between those options. If the WritingMode // is vertical, then the direction of the verticality dictates the choice. if (overflow == OPAGEDX) { if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode) return Pagination::LeftToRightPaginated; return Pagination::RightToLeftPaginated; } // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode // is vertical, then we use TextDirection to choose between those options. if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL)) return Pagination::TopToBottomPaginated; return Pagination::BottomToTopPaginated; } FrameView::FrameView(Frame* frame) : m_frame(frame) , m_canHaveScrollbars(true) , m_slowRepaintObjectCount(0) , m_layoutTimer(this, &FrameView::layoutTimerFired) , m_layoutRoot(0) , m_inSynchronousPostLayout(false) , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) , m_isTransparent(false) , m_baseBackgroundColor(Color::white) , m_mediaType("screen") , m_actionScheduler(adoptPtr(new FrameActionScheduler)) , m_overflowStatusDirty(true) , m_viewportRenderer(0) , m_wasScrolledByUser(false) , m_inProgrammaticScroll(false) , m_safeToPropagateScrollToParent(true) , m_deferredRepaintTimer(this, &FrameView::deferredRepaintTimerFired) , m_disableRepaints(0) , m_isTrackingRepaints(false) , m_shouldUpdateWhileOffscreen(true) , m_deferSetNeedsLayouts(0) , m_setNeedsLayoutWasDeferred(false) , m_scrollCorner(0) , m_shouldAutoSize(false) , m_inAutoSize(false) , m_didRunAutosize(false) #if ENABLE(CSS_FILTERS) , m_hasSoftwareFilters(false) #endif { init(); // FIXME: Can m_frame ever be null here? if (!m_frame) return; Page* page = m_frame->page(); if (!page) return; if (m_frame == page->mainFrame()) { ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed); ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed); } } PassRefPtr FrameView::create(Frame* frame) { RefPtr view = adoptRef(new FrameView(frame)); view->show(); return view.release(); } PassRefPtr FrameView::create(Frame* frame, const IntSize& initialSize) { RefPtr view = adoptRef(new FrameView(frame)); view->Widget::setFrameRect(IntRect(view->location(), initialSize)); view->show(); return view.release(); } FrameView::~FrameView() { if (m_postLayoutTasksTimer.isActive()) { m_postLayoutTasksTimer.stop(); m_actionScheduler->clear(); } if (AXObjectCache::accessibilityEnabled() && axObjectCache()) axObjectCache()->remove(this); resetScrollbars(); // Custom scrollbars should already be destroyed at this point ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar()); ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar()); setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow. setHasVerticalScrollbar(false); ASSERT(!m_scrollCorner); ASSERT(m_actionScheduler->isEmpty()); if (m_frame) { ASSERT(m_frame->view() != this || !m_frame->contentRenderer()); RenderPart* renderer = m_frame->ownerRenderer(); if (renderer && renderer->widget() == this) renderer->setWidget(0); } } 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_delayedLayout = false; m_doFullRepaint = true; m_layoutSchedulingEnabled = true; m_inLayout = false; m_doingPreLayoutStyleUpdate = false; m_inSynchronousPostLayout = false; m_layoutCount = 0; m_nestedLayoutCount = 0; m_postLayoutTasksTimer.stop(); m_firstLayout = true; m_firstLayoutCallbackPending = false; m_wasScrolledByUser = false; m_safeToPropagateScrollToParent = true; m_lastViewportSize = IntSize(); m_lastZoomFactor = 1.0f; m_deferringRepaints = 0; m_repaintCount = 0; m_repaintRects.clear(); m_deferredRepaintDelay = s_initialDeferredRepaintDelayDuringLoading; m_deferredRepaintTimer.stop(); m_isTrackingRepaints = false; m_trackedRepaintRects.clear(); m_lastPaintTime = 0; m_paintBehavior = PaintBehaviorNormal; m_isPainting = false; m_visuallyNonEmptyCharacterCount = 0; m_visuallyNonEmptyPixelCount = 0; m_isVisuallyNonEmpty = false; m_firstVisuallyNonEmptyLayoutCallbackPending = true; m_maintainScrollPositionAnchor = 0; m_disableRepaints = 0; } bool FrameView::isFrameView() const { return true; } void FrameView::clearFrame() { m_frame = 0; } void FrameView::resetScrollbars() { // Reset the document's scrollbars back to our defaults before we yield the floor. m_firstLayout = true; setScrollbarsSuppressed(true); if (m_canHaveScrollbars) setScrollbarModes(ScrollbarAuto, ScrollbarAuto); else setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); setScrollbarsSuppressed(false); } void FrameView::resetScrollbarsAndClearContentsSize() { resetScrollbars(); setScrollbarsSuppressed(true); setContentsSize(IntSize()); setScrollbarsSuppressed(false); } void FrameView::init() { reset(); m_margins = LayoutSize(-1, -1); // undefined m_size = LayoutSize(); // Propagate the marginwidth/height and scrolling modes to the view. Element* ownerElement = m_frame ? m_frame->ownerElement() : 0; if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { HTMLFrameElementBase* frameElt = static_cast(ownerElement); if (frameElt->scrollingMode() == ScrollbarAlwaysOff) setCanHaveScrollbars(false); LayoutUnit marginWidth = frameElt->marginWidth(); LayoutUnit marginHeight = frameElt->marginHeight(); if (marginWidth != -1) setMarginWidth(marginWidth); if (marginHeight != -1) setMarginHeight(marginHeight); } } void FrameView::detachCustomScrollbars() { Scrollbar* horizontalBar = horizontalScrollbar(); if (horizontalBar && horizontalBar->isCustomScrollbar()) setHasHorizontalScrollbar(false); Scrollbar* verticalBar = verticalScrollbar(); if (verticalBar && verticalBar->isCustomScrollbar()) setHasVerticalScrollbar(false); if (m_scrollCorner) { m_scrollCorner->destroy(); m_scrollCorner = 0; } } void FrameView::recalculateScrollbarOverlayStyle() { ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle(); ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault; Color backgroundColor = documentBackgroundColor(); #if USE(ACCELERATED_COMPOSITING) if (RenderView* root = rootRenderer(this)) { RenderLayerCompositor* compositor = root->compositor(); compositor->documentBackgroundColorDidChange(); } #endif if (backgroundColor.isValid()) { // Reduce the background color from RGB to a lightness value // and determine which scrollbar style to use based on a lightness // heuristic. double hue, saturation, lightness; backgroundColor.getHSL(hue, saturation, lightness); if (lightness <= .5) overlayStyle = ScrollbarOverlayStyleLight; } if (oldOverlayStyle != overlayStyle) setScrollbarOverlayStyle(overlayStyle); } void FrameView::clear() { setCanBlitOnScroll(true); reset(); if (m_frame) { if (RenderPart* renderer = m_frame->ownerRenderer()) renderer->viewCleared(); } setScrollbarsSuppressed(true); } bool FrameView::didFirstLayout() const { return !m_firstLayout; } void FrameView::invalidateRect(const IntRect& rect) { if (!parent()) { if (hostWindow()) hostWindow()->invalidateContentsAndRootView(rect, false /*immediate*/); return; } if (!m_frame) return; RenderPart* renderer = m_frame->ownerRenderer(); if (!renderer) return; IntRect repaintRect = rect; repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop()); renderer->repaintRectangle(repaintRect); } void FrameView::setFrameRect(const IntRect& newRect) { IntRect oldRect = frameRect(); if (newRect == oldRect) return; ScrollView::setFrameRect(newRect); updateScrollableAreaSet(); #if USE(ACCELERATED_COMPOSITING) if (RenderView* root = rootRenderer(this)) { if (root->usesCompositing()) root->compositor()->frameViewDidChangeSize(); } #endif } #if ENABLE(REQUEST_ANIMATION_FRAME) bool FrameView::scheduleAnimation() { if (hostWindow()) { hostWindow()->scheduleAnimation(); return true; } return false; } #endif void FrameView::setMarginWidth(LayoutUnit w) { // make it update the rendering area when set m_margins.setWidth(w); } void FrameView::setMarginHeight(LayoutUnit h) { // make it update the rendering area when set m_margins.setHeight(h); } bool FrameView::avoidScrollbarCreation() const { ASSERT(m_frame); // with frame flattening no subframe can have scrollbars // but we also cannot turn scrollbars off as we determine // our flattening policy using that. if (!m_frame->ownerElement()) return false; if (!m_frame->settings() || m_frame->settings()->frameFlatteningEnabled()) return true; return false; } void FrameView::setCanHaveScrollbars(bool canHaveScrollbars) { m_canHaveScrollbars = canHaveScrollbars; ScrollView::setCanHaveScrollbars(canHaveScrollbars); } void FrameView::updateCanHaveScrollbars() { ScrollbarMode hMode; ScrollbarMode vMode; scrollbarModes(hMode, vMode); if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff) setCanHaveScrollbars(false); else setCanHaveScrollbars(true); } PassRefPtr FrameView::createScrollbar(ScrollbarOrientation orientation) { if (Settings* settings = m_frame->settings()) { if (!settings->allowCustomScrollbarInMainFrame() && m_frame->page() && m_frame->page()->mainFrame() == m_frame) 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 = m_frame->document(); // Try the element first as a scrollbar source. Element* body = doc ? doc->body() : 0; if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) 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; if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) return RenderScrollbar::createCustomScrollbar(this, orientation, docElement); // If we have an owning iframe/frame element, then it can set the custom scrollbar also. RenderPart* frameRenderer = m_frame->ownerRenderer(); if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) return RenderScrollbar::createCustomScrollbar(this, orientation, 0, m_frame.get()); // Nobody set a custom style, so we just use a native scrollbar. return ScrollView::createScrollbar(orientation); } void FrameView::setContentsSize(const IntSize& size) { if (size == contentsSize()) return; m_deferSetNeedsLayouts++; ScrollView::setContentsSize(size); ScrollView::contentsResized(); Page* page = frame() ? frame()->page() : 0; if (!page) return; updateScrollableAreaSet(); page->chrome()->contentsSizeChanged(frame(), size); //notify only m_deferSetNeedsLayouts--; if (!m_deferSetNeedsLayouts) m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen. } void FrameView::adjustViewSize() { RenderView* root = rootRenderer(this); if (!root) return; ASSERT(m_frame->view() == this); const IntRect rect = root->documentRect(); const IntSize& size = rect.size(); ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize()); setContentsSize(size); } void FrameView::applyOverflowToViewport(RenderObject* o, 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 // scrollbars. The CSS2.1 draft states that HTML UAs should use the or element and XML/XHTML UAs should // use the root element. // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when // there is a frameScaleFactor that is greater than one on the main frame. bool overrideHidden = m_frame->page() && m_frame->page()->mainFrame() == m_frame && m_frame->frameScaleFactor() > 1; EOverflow overflowX = o->style()->overflowX(); EOverflow overflowY = o->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; } #endif switch (overflowX) { case OHIDDEN: if (overrideHidden) hMode = ScrollbarAuto; else hMode = ScrollbarAlwaysOff; break; case OSCROLL: hMode = ScrollbarAlwaysOn; break; case OAUTO: hMode = ScrollbarAuto; break; default: // Don't set it at all. ; } switch (overflowY) { case OHIDDEN: if (overrideHidden) vMode = ScrollbarAuto; else vMode = ScrollbarAlwaysOff; break; case OSCROLL: vMode = ScrollbarAlwaysOn; break; case OAUTO: vMode = ScrollbarAuto; break; default: // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort(). ; } m_viewportRenderer = o; } void FrameView::applyPaginationToViewport() { Document* document = m_frame->document(); Node* documentElement = document->documentElement(); RenderObject* documentRenderer = documentElement ? documentElement->renderer() : 0; RenderObject* documentOrBodyRenderer = documentRenderer; Node* body = document->body(); if (body && body->renderer()) { if (body->hasTagName(bodyTag)) documentOrBodyRenderer = documentRenderer->style()->overflowX() == OVISIBLE && documentElement->hasTagName(htmlTag) ? body->renderer() : documentRenderer; } Pagination pagination; if (!documentOrBodyRenderer) { setPagination(pagination); return; } 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; const HTMLFrameOwnerElement* owner = m_frame->ownerElement(); if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) { hMode = ScrollbarAlwaysOff; vMode = ScrollbarAlwaysOff; return; } if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) { hMode = ScrollbarAuto; vMode = ScrollbarAuto; } else { hMode = ScrollbarAlwaysOff; vMode = ScrollbarAlwaysOff; } if (!m_layoutRoot) { Document* document = m_frame->document(); Node* documentElement = document->documentElement(); RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0; Node* body = document->body(); if (body && body->renderer()) { if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->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. RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer; applyOverflowToViewport(o, hMode, vMode); } } else if (rootRenderer) applyOverflowToViewport(rootRenderer, hMode, vMode); } } #if USE(ACCELERATED_COMPOSITING) void FrameView::updateCompositingLayersAfterStyleChange() { RenderView* root = rootRenderer(this); if (!root) return; // If we expect to update compositing after an incipient layout, don't do so here. if (m_doingPreLayoutStyleUpdate || layoutPending() || root->needsLayout()) return; // This call will make sure the cached hasAcceleratedCompositing is updated from the pref root->compositor()->cacheAcceleratedCompositingFlags(); root->compositor()->updateCompositingLayers(CompositingUpdateAfterStyleChange); } void FrameView::updateCompositingLayersAfterLayout() { RenderView* root = rootRenderer(this); if (!root) return; // This call will make sure the cached hasAcceleratedCompositing is updated from the pref root->compositor()->cacheAcceleratedCompositingFlags(); root->compositor()->updateCompositingLayers(CompositingUpdateAfterLayout); } void FrameView::clearBackingStores() { RenderView* root = rootRenderer(this); if (!root) return; RenderLayerCompositor* compositor = root->compositor(); ASSERT(compositor->inCompositingMode()); compositor->enableCompositingMode(false); compositor->clearBackingForAllLayers(); } void FrameView::restoreBackingStores() { RenderView* root = rootRenderer(this); if (!root) return; RenderLayerCompositor* compositor = root->compositor(); compositor->enableCompositingMode(true); compositor->updateCompositingLayers(CompositingUpdateAfterLayout); } GraphicsLayer* FrameView::layerForHorizontalScrollbar() const { RenderView* root = rootRenderer(this); if (!root) return 0; return root->compositor()->layerForHorizontalScrollbar(); } GraphicsLayer* FrameView::layerForVerticalScrollbar() const { RenderView* root = rootRenderer(this); if (!root) return 0; return root->compositor()->layerForVerticalScrollbar(); } GraphicsLayer* FrameView::layerForScrollCorner() const { RenderView* root = rootRenderer(this); if (!root) return 0; return root->compositor()->layerForScrollCorner(); } TiledBacking* FrameView::tiledBacking() { RenderView* root = rootRenderer(this); if (!root) return 0; RenderLayerBacking* backing = root->layer()->backing(); if (!backing) return 0; return backing->graphicsLayer()->tiledBacking(); } uint64_t FrameView::scrollLayerID() const { RenderView* root = rootRenderer(this); if (!root) return 0; RenderLayerBacking* backing = root->layer()->backing(); if (!backing) return 0; return backing->scrollLayerID(); } #if ENABLE(RUBBER_BANDING) GraphicsLayer* FrameView::layerForOverhangAreas() const { RenderView* root = rootRenderer(this); if (!root) return 0; return root->compositor()->layerForOverhangAreas(); } #endif bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush) { RenderView* root = rootRenderer(this); if (!root) return true; // We don't want to keep trying to update layers if we have no renderer. ASSERT(m_frame->view() == this); // If we sync compositing layers when a layout is pending, we may cause painting of compositing // layer content to occur before layout has happened, which will cause paintContents() to bail. if (needsLayout()) return false; // If we sync compositing layers and allow the repaint to be deferred, there is time for a // visible flash to occur. Instead, stop the deferred repaint timer and repaint immediately. flushDeferredRepaints(); root->compositor()->flushPendingLayerChanges(rootFrameForFlush == m_frame); return true; } void FrameView::setNeedsOneShotDrawingSynchronization() { Page* page = frame() ? frame()->page() : 0; if (page) page->chrome()->client()->setNeedsOneShotDrawingSynchronization(); } #endif // USE(ACCELERATED_COMPOSITING) bool FrameView::hasCompositedContent() const { #if USE(ACCELERATED_COMPOSITING) if (RenderView* root = rootRenderer(this)) return root->compositor()->inCompositingMode(); #endif return false; } bool FrameView::hasCompositedContentIncludingDescendants() const { #if USE(ACCELERATED_COMPOSITING) for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) { RenderView* renderView = frame->contentRenderer(); RenderLayerCompositor* compositor = renderView ? renderView->compositor() : 0; if (compositor) { if (compositor->inCompositingMode()) return true; if (!RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) break; } } #endif return false; } bool FrameView::hasCompositingAncestor() const { #if USE(ACCELERATED_COMPOSITING) for (Frame* frame = m_frame->tree()->parent(); frame; frame = frame->tree()->parent()) { if (FrameView* view = frame->view()) { if (view->hasCompositedContent()) return true; } } #endif return false; } // Sometimes (for plug-ins) we need to eagerly go into compositing mode. void FrameView::enterCompositingMode() { #if USE(ACCELERATED_COMPOSITING) if (RenderView* root = rootRenderer(this)) { root->compositor()->enableCompositingMode(); if (!needsLayout()) root->compositor()->scheduleCompositingLayerUpdate(); } #endif } bool FrameView::isEnclosedInCompositingLayer() const { #if USE(ACCELERATED_COMPOSITING) RenderObject* frameOwnerRenderer = m_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(m_frame.get()); for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->traverseNext(m_frame.get())) { bool flushed = child->view()->flushCompositingStateForThisFrame(m_frame.get()); allFramesFlushed &= flushed; } return allFramesFlushed; #else // USE(ACCELERATED_COMPOSITING) return true; #endif } bool FrameView::isSoftwareRenderable() const { #if USE(ACCELERATED_COMPOSITING) RenderView* root = rootRenderer(this); if (!root) return true; return !root->compositor()->has3DContent(); #else return true; #endif } void FrameView::didMoveOnscreen() { if (RenderView* root = rootRenderer(this)) root->didMoveOnscreen(); contentAreaDidShow(); } void FrameView::willMoveOffscreen() { if (RenderView* root = rootRenderer(this)) root->willMoveOffscreen(); contentAreaDidHide(); } RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const { return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot; } static inline void collectFrameViewChildren(FrameView* frameView, Vector >& frameViews) { const HashSet >* viewChildren = frameView->children(); ASSERT(viewChildren); const HashSet >::iterator end = viewChildren->end(); for (HashSet >::iterator current = viewChildren->begin(); current != end; ++current) { Widget* widget = (*current).get(); if (widget->isFrameView()) frameViews.append(static_cast(widget)); } } inline void FrameView::forceLayoutParentViewIfNeeded() { #if ENABLE(SVG) RenderPart* ownerRenderer = m_frame->ownerRenderer(); if (!ownerRenderer || !ownerRenderer->frame()) return; RenderBox* contentBox = embeddedContentBox(); if (!contentBox) return; RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox); if (svgRoot->everHadLayout() && !svgRoot->needsLayout()) return; // 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 // 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