diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/rendering/RenderView.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/WebCore/rendering/RenderView.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderView.cpp | 972 |
1 files changed, 409 insertions, 563 deletions
diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp index 433630039..2968bf21d 100644 --- a/Source/WebCore/rendering/RenderView.cpp +++ b/Source/WebCore/rendering/RenderView.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "RenderView.h" +#include "ColumnInfo.h" #include "Document.h" #include "Element.h" #include "FloatQuad.h" @@ -34,105 +35,42 @@ #include "HTMLIFrameElement.h" #include "HitTestResult.h" #include "ImageQualityController.h" -#include "NodeTraversal.h" #include "Page.h" #include "RenderGeometryMap.h" #include "RenderIterator.h" #include "RenderLayer.h" #include "RenderLayerBacking.h" -#include "RenderLayerCompositor.h" -#include "RenderMultiColumnFlowThread.h" -#include "RenderMultiColumnSet.h" -#include "RenderMultiColumnSpannerPlaceholder.h" #include "RenderNamedFlowThread.h" #include "RenderSelectionInfo.h" #include "RenderWidget.h" -#include "ScrollbarTheme.h" -#include "Settings.h" #include "StyleInheritedData.h" #include "TransformState.h" #include <wtf/StackStats.h> -namespace WebCore { - -struct FrameFlatteningLayoutDisallower { - FrameFlatteningLayoutDisallower(FrameView& frameView) - : m_frameView(frameView) - , m_disallowLayout(frameView.frame().settings().frameFlatteningEnabled()) - { - if (m_disallowLayout) - m_frameView.startDisallowingLayout(); - } - - ~FrameFlatteningLayoutDisallower() - { - if (m_disallowLayout) - m_frameView.endDisallowingLayout(); - } - -private: - FrameView& m_frameView; - bool m_disallowLayout { false }; -}; - -struct SelectionIterator { - SelectionIterator(RenderObject* start) - : m_current(start) - { - checkForSpanner(); - } - - RenderObject* current() const - { - return m_current; - } - - RenderObject* next() - { - RenderObject* currentSpan = m_spannerStack.isEmpty() ? nullptr : m_spannerStack.last()->spanner(); - m_current = m_current->nextInPreOrder(currentSpan); - checkForSpanner(); - if (!m_current && currentSpan) { - RenderObject* placeholder = m_spannerStack.last(); - m_spannerStack.removeLast(); - m_current = placeholder->nextInPreOrder(); - checkForSpanner(); - } - return m_current; - } - -private: - void checkForSpanner() - { - if (!is<RenderMultiColumnSpannerPlaceholder>(m_current)) - return; - auto& placeholder = downcast<RenderMultiColumnSpannerPlaceholder>(*m_current); - m_spannerStack.append(&placeholder); - m_current = placeholder.spanner(); - } +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerCompositor.h" +#endif - RenderObject* m_current { nullptr }; - Vector<RenderMultiColumnSpannerPlaceholder*> m_spannerStack; -}; +namespace WebCore { -RenderView::RenderView(Document& document, Ref<RenderStyle>&& style) - : RenderBlockFlow(document, WTFMove(style)) +RenderView::RenderView(Document& document, PassRef<RenderStyle> style) + : RenderBlockFlow(document, std::move(style)) , m_frameView(*document.view()) - , m_selectionUnsplitStart(nullptr) - , m_selectionUnsplitEnd(nullptr) - , m_selectionUnsplitStartPos(-1) - , m_selectionUnsplitEndPos(-1) - , m_lazyRepaintTimer(*this, &RenderView::lazyRepaintTimerFired) + , m_selectionStart(0) + , m_selectionEnd(0) + , m_selectionStartPos(-1) + , m_selectionEndPos(-1) + , m_rendererCount(0) + , m_maximalOutlineSize(0) , m_pageLogicalHeight(0) , m_pageLogicalHeightChanged(false) , m_layoutState(nullptr) , m_layoutStateDisableCount(0) - , m_renderQuoteHead(nullptr) + , m_renderQuoteHead(0) , m_renderCounterCount(0) , m_selectionWasCaret(false) +#if ENABLE(CSS_FILTERS) , m_hasSoftwareFilters(false) -#if ENABLE(SERVICE_CONTROLS) - , m_selectionRectGatherer(*this) #endif { setIsRenderView(); @@ -155,38 +93,6 @@ RenderView::~RenderView() { } -void RenderView::scheduleLazyRepaint(RenderBox& renderer) -{ - if (renderer.renderBoxNeedsLazyRepaint()) - return; - renderer.setRenderBoxNeedsLazyRepaint(true); - m_renderersNeedingLazyRepaint.add(&renderer); - if (!m_lazyRepaintTimer.isActive()) - m_lazyRepaintTimer.startOneShot(0); -} - -void RenderView::unscheduleLazyRepaint(RenderBox& renderer) -{ - if (!renderer.renderBoxNeedsLazyRepaint()) - return; - renderer.setRenderBoxNeedsLazyRepaint(false); - m_renderersNeedingLazyRepaint.remove(&renderer); - if (m_renderersNeedingLazyRepaint.isEmpty()) - m_lazyRepaintTimer.stop(); -} - -void RenderView::lazyRepaintTimerFired() -{ - bool shouldRepaint = !document().inPageCache(); - - for (auto& renderer : m_renderersNeedingLazyRepaint) { - if (shouldRepaint) - renderer->repaint(); - renderer->setRenderBoxNeedsLazyRepaint(false); - } - m_renderersNeedingLazyRepaint.clear(); -} - bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result) { return hitTest(request, result.hitTestLocation(), result); @@ -194,27 +100,21 @@ bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result) bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result) { - document().updateLayout(); - - FrameFlatteningLayoutDisallower disallower(frameView()); + if (layer()->hitTest(request, location, result)) + return true; - bool resultLayer = layer()->hitTest(request, location, result); - - // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls, - // so we need to test ScrollView scrollbars separately here. In case of using overlay scrollbars, the layer hit test - // will always work so we need to check the ScrollView scrollbars in that case too. - if (!resultLayer || ScrollbarTheme::theme().usesOverlayScrollbars()) { - // FIXME: Consider if this test should be done unconditionally. - if (request.allowsFrameScrollbars()) { - IntPoint windowPoint = frameView().contentsToWindow(location.roundedPoint()); - if (Scrollbar* frameScrollbar = frameView().scrollbarAtPoint(windowPoint)) { - result.setScrollbar(frameScrollbar); - return true; - } + // FIXME: Consider if this test should be done unconditionally. + if (request.allowsFrameScrollbars()) { + // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls, + // so we need to test ScrollView scrollbars separately here. + Scrollbar* frameScrollbar = frameView().scrollbarAtPoint(location.roundedPoint()); + if (frameScrollbar) { + result.setScrollbar(frameScrollbar); + return true; } } - return resultLayer; + return false; } void RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit, LogicalExtentComputedValues& computedValues) const @@ -230,11 +130,9 @@ void RenderView::updateLogicalWidth() LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType) const { - // Make sure block progression pagination for percentages uses the column extent and - // not the view's extent. See https://bugs.webkit.org/show_bug.cgi?id=135204. - if (multiColumnFlowThread() && multiColumnFlowThread()->firstMultiColumnSet()) - return multiColumnFlowThread()->firstMultiColumnSet()->computedColumnHeight(); - + // If we have columns, then the available logical height is reduced to the column height. + if (hasColumns()) + return columnInfo()->columnHeight(); #if PLATFORM(IOS) // Workaround for <rdar://problem/7166808>. if (document().isPluginDocument() && frameView().useFixedLayout()) @@ -270,14 +168,67 @@ void RenderView::checkLayoutState(const LayoutState& state) } #endif -void RenderView::initializeLayoutState(LayoutState& state) +static RenderBox* enclosingSeamlessRenderer(Document& document) +{ + Element* ownerElement = document.seamlessParentIFrame(); + if (!ownerElement) + return 0; + return ownerElement->renderBox(); +} + +void RenderView::addChild(RenderObject* newChild, RenderObject* beforeChild) +{ + // Seamless iframes are considered part of an enclosing render flow thread from the parent document. This is necessary for them to look + // up regions in the parent document during layout. + if (newChild && !newChild->isRenderFlowThread()) { + RenderBox* seamlessBox = enclosingSeamlessRenderer(document()); + if (seamlessBox && seamlessBox->flowThreadContainingBlock()) + newChild->setFlowThreadState(seamlessBox->flowThreadState()); + } + RenderBlockFlow::addChild(newChild, beforeChild); +} + +bool RenderView::initializeLayoutState(LayoutState& state) { + bool isSeamlessAncestorInFlowThread = false; + // FIXME: May be better to push a clip and avoid issuing offscreen repaints. state.m_clipped = false; - - state.m_pageLogicalHeight = m_pageLogicalHeight; - state.m_pageLogicalHeightChanged = m_pageLogicalHeightChanged; + + // Check the writing mode of the seamless ancestor. It has to match our document's writing mode, or we won't inherit any + // pagination information. + RenderBox* seamlessAncestor = enclosingSeamlessRenderer(document()); + LayoutState* seamlessLayoutState = seamlessAncestor ? seamlessAncestor->view().layoutState() : 0; + bool shouldInheritPagination = seamlessLayoutState && !m_pageLogicalHeight && seamlessAncestor->style().writingMode() == style().writingMode(); + + state.m_pageLogicalHeight = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeight : m_pageLogicalHeight; + state.m_pageLogicalHeightChanged = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeightChanged : m_pageLogicalHeightChanged; state.m_isPaginated = state.m_pageLogicalHeight; + if (state.m_isPaginated && shouldInheritPagination) { + // Set up the correct pagination offset. We can use a negative offset in order to push the top of the RenderView into its correct place + // on a page. We can take the iframe's offset from the logical top of the first page and make the negative into the pagination offset within the child + // view. + bool isFlipped = seamlessAncestor->style().isFlippedBlocksWritingMode(); + LayoutSize layoutOffset = seamlessLayoutState->layoutOffset(); + LayoutSize iFrameOffset(layoutOffset.width() + seamlessAncestor->x() + (!isFlipped ? seamlessAncestor->borderLeft() + seamlessAncestor->paddingLeft() : + seamlessAncestor->borderRight() + seamlessAncestor->paddingRight()), + layoutOffset.height() + seamlessAncestor->y() + (!isFlipped ? seamlessAncestor->borderTop() + seamlessAncestor->paddingTop() : + seamlessAncestor->borderBottom() + seamlessAncestor->paddingBottom())); + + LayoutSize offsetDelta = seamlessLayoutState->m_pageOffset - iFrameOffset; + state.m_pageOffset = offsetDelta; + + // Set the current render flow thread to point to our ancestor. This will allow the seamless document to locate the correct + // regions when doing a layout. + if (seamlessAncestor->flowThreadContainingBlock()) { + flowThreadController().setCurrentRenderFlowThread(seamlessAncestor->view().flowThreadController().currentRenderFlowThread()); + isSeamlessAncestorInFlowThread = true; + } + } + + // FIXME: We need to make line grids and exclusions work with seamless iframes as well here. Basically all layout state information needs + // to propagate here and not just pagination information. + return isSeamlessAncestorInFlowThread; } // The algorithm below assumes this is a full layout. In case there are previously computed values for regions, supplemental steps are taken @@ -357,10 +308,16 @@ void RenderView::layout() for (auto& box : childrenOfType<RenderBox>(*this)) { if (box.hasRelativeLogicalHeight() - || box.style().logicalHeight().isPercentOrCalculated() - || box.style().logicalMinHeight().isPercentOrCalculated() - || box.style().logicalMaxHeight().isPercentOrCalculated() + || box.hasViewportPercentageLogicalHeight() + || box.style().logicalHeight().isPercent() + || box.style().logicalMinHeight().isPercent() + || box.style().logicalMaxHeight().isPercent() + || box.style().logicalHeight().isViewportPercentage() + || box.style().logicalMinHeight().isViewportPercentage() + || box.style().logicalMaxHeight().isViewportPercentage() +#if ENABLE(SVG) || box.isSVGRoot() +#endif ) box.setChildNeedsLayout(MarkOnlyThis); } @@ -371,7 +328,7 @@ void RenderView::layout() return; m_layoutState = std::make_unique<LayoutState>(); - initializeLayoutState(*m_layoutState); + bool isSeamlessAncestorInFlowThread = initializeLayoutState(*m_layoutState); m_pageLogicalHeightChanged = false; @@ -387,6 +344,9 @@ void RenderView::layout() #endif m_layoutState = nullptr; clearNeedsLayout(); + + if (isSeamlessAncestorInFlowThread) + flowThreadController().setCurrentRenderFlowThread(0); } LayoutUnit RenderView::pageOrViewLogicalHeight() const @@ -394,7 +354,7 @@ LayoutUnit RenderView::pageOrViewLogicalHeight() const if (document().printing()) return pageLogicalHeight(); - if (multiColumnFlowThread() && !style().hasInlineColumnAxis()) { + if (hasColumns() && !style().hasInlineColumnAxis()) { if (int pageLength = frameView().pagination().pageLength) return pageLength; } @@ -430,49 +390,68 @@ LayoutUnit RenderView::clientLogicalHeightForFixedPosition() const return clientLogicalHeight(); } +#if PLATFORM(IOS) +static inline LayoutSize fixedPositionOffset(const FrameView& frameView) +{ + return frameView.useCustomFixedPositionLayoutRect() ? (frameView.customFixedPositionLayoutRect().location() - LayoutPoint()) : frameView.scrollOffset(); +} +#endif + void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const { - // If a container was specified, and was not nullptr or the RenderView, + // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == (mode & IsFixed)); - if (!repaintContainer && mode & UseTransforms && shouldUseTransformFromContainer(nullptr)) { + if (!repaintContainer && mode & UseTransforms && shouldUseTransformFromContainer(0)) { TransformationMatrix t; - getTransformFromContainer(nullptr, LayoutSize(), t); + getTransformFromContainer(0, LayoutSize(), t); transformState.applyTransform(t); } if (mode & IsFixed) - transformState.move(toLayoutSize(frameView().scrollPositionRespectingCustomFixedPosition())); +#if PLATFORM(IOS) + transformState.move(fixedPositionOffset(m_frameView)); +#else + transformState.move(frameView().scrollOffsetForFixedPosition()); +#endif } const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const { - // If a container was specified, and was not nullptr or the RenderView, + // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this); - LayoutPoint scrollPosition = frameView().scrollPositionRespectingCustomFixedPosition(); +#if PLATFORM(IOS) + LayoutSize scrollOffset = fixedPositionOffset(frameView()); +#else + LayoutSize scrollOffset = frameView().scrollOffsetForFixedPosition(); +#endif - if (!ancestorToStopAt && shouldUseTransformFromContainer(nullptr)) { + if (!ancestorToStopAt && shouldUseTransformFromContainer(0)) { TransformationMatrix t; - getTransformFromContainer(nullptr, LayoutSize(), t); - geometryMap.pushView(this, toLayoutSize(scrollPosition), &t); + getTransformFromContainer(0, LayoutSize(), t); + geometryMap.pushView(this, scrollOffset, &t); } else - geometryMap.pushView(this, toLayoutSize(scrollPosition)); + geometryMap.pushView(this, scrollOffset); - return nullptr; + return 0; } void RenderView::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const { if (mode & IsFixed) - transformState.move(toLayoutSize(frameView().scrollPositionRespectingCustomFixedPosition())); +#if PLATFORM(IOS) + transformState.move(fixedPositionOffset(frameView())); +#else + transformState.move(frameView().scrollOffsetForFixedPosition()); +#endif - if (mode & UseTransforms && shouldUseTransformFromContainer(nullptr)) { + if (mode & UseTransforms && shouldUseTransformFromContainer(0)) { TransformationMatrix t; - getTransformFromContainer(nullptr, LayoutSize(), t); + getTransformFromContainer(0, LayoutSize(), t); transformState.applyTransform(t); } } @@ -492,6 +471,11 @@ void RenderView::computeColumnCountAndWidth() setComputedColumnCountAndWidth(1, columnWidth); } +ColumnInfo::PaginationUnit RenderView::paginationUnit() const +{ + return frameView().pagination().behavesLikeColumns ? ColumnInfo::Column : ColumnInfo::Page; +} + void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // If we ever require layout but receive a paint anyway, something has gone horribly wrong. @@ -501,11 +485,16 @@ void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) // This avoids painting garbage between columns if there is a column gap. if (frameView().pagination().mode != Pagination::Unpaginated && paintInfo.shouldPaintWithinRoot(*this)) - paintInfo.context().fillRect(paintInfo.rect, frameView().baseBackgroundColor()); + paintInfo.context->fillRect(paintInfo.rect, frameView().baseBackgroundColor(), ColorSpaceDeviceRGB); paintObject(paintInfo, paintOffset); } +static inline bool isComposited(RenderElement* object) +{ + return object->hasLayer() && toRenderLayerModelObject(object)->layer()->isComposited(); +} + static inline bool rendererObscuresBackground(RenderElement* rootObject) { if (!rootObject) @@ -517,15 +506,12 @@ static inline bool rendererObscuresBackground(RenderElement* rootObject) || style.hasTransform()) return false; - if (rootObject->isComposited()) + if (isComposited(rootObject)) return false; if (rootObject->rendererForRootBackground().style().backgroundClip() == TextFillBox) return false; - if (style.hasBorderRadius()) - return false; - return true; } @@ -539,19 +525,22 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) // layers with reflections, or transformed layers. // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside // a transform, transparency layer, etc. - for (HTMLFrameOwnerElement* element = document().ownerElement(); element && element->renderer(); element = element->document().ownerElement()) { - RenderLayer* layer = element->renderer()->enclosingLayer(); + Element* elt; + for (elt = document().ownerElement(); elt && elt->renderer(); elt = elt->document().ownerElement()) { + RenderLayer* layer = elt->renderer()->enclosingLayer(); if (layer->cannotBlitToWindow()) { frameView().setCannotBlitToWindow(); break; } +#if USE(ACCELERATED_COMPOSITING) if (RenderLayer* compositingLayer = layer->enclosingCompositingLayerForRepaint()) { if (!compositingLayer->backing()->paintsIntoWindow()) { frameView().setCannotBlitToWindow(); break; } } +#endif } if (document().ownerElement()) @@ -563,41 +552,40 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) bool rootFillsViewport = false; bool rootObscuresBackground = false; Element* documentElement = document().documentElement(); - if (RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr) { + if (RenderElement* rootRenderer = documentElement ? documentElement->renderer() : 0) { // The document element's renderer is currently forced to be a block, but may not always be. - RenderBox* rootBox = is<RenderBox>(*rootRenderer) ? downcast<RenderBox>(rootRenderer) : nullptr; + RenderBox* rootBox = rootRenderer->isBox() ? toRenderBox(rootRenderer) : 0; rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height(); rootObscuresBackground = rendererObscuresBackground(rootRenderer); } - bool backgroundShouldExtendBeyondPage = frameView().frame().settings().backgroundShouldExtendBeyondPage(); - compositor().setRootExtendedBackgroundColor(backgroundShouldExtendBeyondPage ? frameView().documentBackgroundColor() : Color()); + bool hasTiledMargin = false; +#if USE(ACCELERATED_COMPOSITING) + hasTiledMargin = compositor().mainFrameBackingIsTiledWithMargin(); +#endif Page* page = document().page(); float pageScaleFactor = page ? page->pageScaleFactor() : 1; // If painting will entirely fill the view, no need to fill the background. - if (rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1) + if (!hasTiledMargin && rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1) return; // This code typically only executes if the root element's visibility has been set to hidden, // if there is a transform on the <html>, or if there is a page scale factor less than 1. - // Only fill with a background color (typically white) if we're the root document, + // Only fill with the base background color (typically white) if we're the root document, // since iframes/frames with no background in the child document should show the parent's background. - // We use the base background color unless the backgroundShouldExtendBeyondPage setting is set, - // in which case we use the document's background color. if (frameView().isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. frameView().setCannotBlitToWindow(); // The parent must show behind the child. else { - Color documentBackgroundColor = frameView().documentBackgroundColor(); - Color backgroundColor = (backgroundShouldExtendBeyondPage && documentBackgroundColor.isValid()) ? documentBackgroundColor : frameView().baseBackgroundColor(); + Color backgroundColor = hasTiledMargin ? frameView().documentBackgroundColor() : frameView().baseBackgroundColor(); if (backgroundColor.alpha()) { - CompositeOperator previousOperator = paintInfo.context().compositeOperation(); - paintInfo.context().setCompositeOperation(CompositeCopy); - paintInfo.context().fillRect(paintInfo.rect, backgroundColor); - paintInfo.context().setCompositeOperation(previousOperator); + CompositeOperator previousOperator = paintInfo.context->compositeOperation(); + paintInfo.context->setCompositeOperation(CompositeCopy); + paintInfo.context->fillRect(paintInfo.rect, backgroundColor, style().colorSpace()); + paintInfo.context->setCompositeOperation(previousOperator); } else - paintInfo.context().clearRect(paintInfo.rect); + paintInfo.context->clearRect(paintInfo.rect); } } @@ -608,43 +596,46 @@ bool RenderView::shouldRepaint(const LayoutRect& rect) const void RenderView::repaintRootContents() { +#if USE(ACCELERATED_COMPOSITING) if (layer()->isComposited()) { layer()->setBackingNeedsRepaint(GraphicsLayer::DoNotClipToLayer); return; } +#endif repaint(); } -void RenderView::repaintViewRectangle(const LayoutRect& repaintRect) const +void RenderView::repaintViewRectangle(const LayoutRect& repaintRect, bool immediate) const { + // FIXME: Get rid of the 'immediate' argument. It only works on Mac WK1 and should never be used. if (!shouldRepaint(repaintRect)) return; - // FIXME: enclosingRect is needed as long as we integral snap ScrollView/FrameView/RenderWidget size/position. - IntRect enclosingRect = enclosingIntRect(repaintRect); if (auto ownerElement = document().ownerElement()) { - RenderBox* ownerBox = ownerElement->renderBox(); - if (!ownerBox) + if (!ownerElement->renderer()) return; + auto& ownerBox = toRenderBox(*ownerElement->renderer()); LayoutRect viewRect = this->viewRect(); #if PLATFORM(IOS) // Don't clip using the visible rect since clipping is handled at a higher level on iPhone. - LayoutRect adjustedRect = enclosingRect; + LayoutRect adjustedRect = repaintRect; #else - LayoutRect adjustedRect = intersection(enclosingRect, viewRect); + LayoutRect adjustedRect = intersection(repaintRect, viewRect); #endif adjustedRect.moveBy(-viewRect.location()); - adjustedRect.moveBy(ownerBox->contentBoxRect().location()); - ownerBox->repaintRectangle(adjustedRect); + adjustedRect.moveBy(ownerBox.contentBoxRect().location()); + ownerBox.repaintRectangle(adjustedRect, immediate); return; } + IntRect pixelSnappedRect = pixelSnappedIntRect(repaintRect); - frameView().addTrackedRepaintRect(snapRectToDevicePixels(repaintRect, document().deviceScaleFactor())); - if (!m_accumulatedRepaintRegion) { - frameView().repaintContentRectangle(enclosingRect); + frameView().addTrackedRepaintRect(pixelSnappedRect); + + if (!m_accumulatedRepaintRegion || immediate) { + frameView().repaintContentRectangle(pixelSnappedRect, immediate); return; } - m_accumulatedRepaintRegion->unite(enclosingRect); + m_accumulatedRepaintRegion->unite(pixelSnappedRect); // Region will get slow if it gets too complex. Merge all rects so far to bounds if this happens. // FIXME: Maybe there should be a region type that does this automatically. @@ -659,17 +650,34 @@ void RenderView::flushAccumulatedRepaintRegion() const ASSERT(m_accumulatedRepaintRegion); auto repaintRects = m_accumulatedRepaintRegion->rects(); for (auto& rect : repaintRects) - frameView().repaintContentRectangle(rect); + frameView().repaintContentRectangle(rect, false); m_accumulatedRepaintRegion = nullptr; } +void RenderView::repaintRectangleInViewAndCompositedLayers(const LayoutRect& ur, bool immediate) +{ + if (!shouldRepaint(ur)) + return; + + repaintViewRectangle(ur, immediate); + +#if USE(ACCELERATED_COMPOSITING) + RenderLayerCompositor& compositor = this->compositor(); + if (compositor.inCompositingMode()) { + IntRect repaintRect = pixelSnappedIntRect(ur); + compositor.repaintCompositedLayers(&repaintRect); + } +#endif +} + void RenderView::repaintViewAndCompositedLayers() { repaintRootContents(); - +#if USE(ACCELERATED_COMPOSITING) RenderLayerCompositor& compositor = this->compositor(); if (compositor.inCompositingMode()) compositor.repaintCompositedLayers(); +#endif } LayoutRect RenderView::visualOverflowRect() const @@ -680,45 +688,40 @@ LayoutRect RenderView::visualOverflowRect() const return RenderBlockFlow::visualOverflowRect(); } -LayoutRect RenderView::computeRectForRepaint(const LayoutRect& rect, const RenderLayerModelObject* repaintContainer, bool fixed) const +void RenderView::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const { - // If a container was specified, and was not nullptr or the RenderView, + // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); if (printing()) - return rect; - - LayoutRect adjustedRect = rect; + return; + if (style().isFlippedBlocksWritingMode()) { // We have to flip by hand since the view's logical height has not been determined. We // can use the viewport width and height. if (style().isHorizontalWritingMode()) - adjustedRect.setY(viewHeight() - adjustedRect.maxY()); + rect.setY(viewHeight() - rect.maxY()); else - adjustedRect.setX(viewWidth() - adjustedRect.maxX()); + rect.setX(viewWidth() - rect.maxX()); } - if (fixed) - adjustedRect.moveBy(frameView().scrollPositionRespectingCustomFixedPosition()); - + if (fixed) { +#if PLATFORM(IOS) + rect.move(fixedPositionOffset(frameView())); +#else + rect.move(frameView().scrollOffsetForFixedPosition()); +#endif + } + // Apply our transform if we have one (because of full page zooming). if (!repaintContainer && layer() && layer()->transform()) - adjustedRect = LayoutRect(layer()->transform()->mapRect(snapRectToDevicePixels(adjustedRect, document().deviceScaleFactor()))); - return adjustedRect; -} - -bool RenderView::isScrollableOrRubberbandableBox() const -{ - // The main frame might be allowed to rubber-band even if there is no content to scroll to. This is unique to - // the main frame; subframes and overflow areas have to have content that can be scrolled to in order to rubber-band. - FrameView::Scrollability defineScrollable = frame().ownerElement() ? FrameView::Scrollability::Scrollable : FrameView::Scrollability::ScrollableOrRubberbandable; - return frameView().isScrollable(defineScrollable); + rect = layer()->transform()->mapRect(rect); } void RenderView::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const { - rects.append(snappedIntRect(accumulatedOffset, layer()->size())); + rects.append(pixelSnappedIntRect(accumulatedOffset, layer()->size())); } void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const @@ -731,7 +734,7 @@ void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const static RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) { if (!object) - return nullptr; + return 0; RenderObject* child = object->childAt(offset); return child ? child : object->nextInPreOrderAfterChildren(); @@ -739,41 +742,26 @@ static RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset IntRect RenderView::selectionBounds(bool clipToVisibleContent) const { - LayoutRect selRect = subtreeSelectionBounds(*this, clipToVisibleContent); - - if (hasRenderNamedFlowThreads()) { - for (auto* namedFlowThread : *m_flowThreadController->renderNamedFlowThreadList()) { - LayoutRect currRect = subtreeSelectionBounds(*namedFlowThread, clipToVisibleContent); - selRect.unite(currRect); - } - } - - return snappedIntRect(selRect); -} - -LayoutRect RenderView::subtreeSelectionBounds(const SelectionSubtreeRoot& root, bool clipToVisibleContent) const -{ - typedef HashMap<RenderObject*, std::unique_ptr<RenderSelectionInfo>> SelectionMap; + typedef HashMap<RenderObject*, OwnPtr<RenderSelectionInfo>> SelectionMap; SelectionMap selectedObjects; - RenderObject* os = root.selectionData().selectionStart(); - RenderObject* stop = rendererAfterPosition(root.selectionData().selectionEnd(), root.selectionData().selectionEndPos()); - SelectionIterator selectionIterator(os); + RenderObject* os = m_selectionStart; + RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); while (os && os != stop) { - if ((os->canBeSelectionLeaf() || os == root.selectionData().selectionStart() || os == root.selectionData().selectionEnd()) && os->selectionState() != SelectionNone) { + if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. - selectedObjects.set(os, std::make_unique<RenderSelectionInfo>(*os, clipToVisibleContent)); + selectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, clipToVisibleContent))); RenderBlock* cb = os->containingBlock(); - while (cb && !is<RenderView>(*cb)) { - std::unique_ptr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).iterator->value; + while (cb && !cb->isRenderView()) { + OwnPtr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).iterator->value; if (blockInfo) break; - blockInfo = std::make_unique<RenderSelectionInfo>(*cb, clipToVisibleContent); + blockInfo = adoptPtr(new RenderSelectionInfo(cb, clipToVisibleContent)); cb = cb->containingBlock(); } } - os = selectionIterator.next(); + os = os->nextInPreOrder(); } // Now create a single bounding box rect that encloses the whole selection. @@ -789,211 +777,149 @@ LayoutRect RenderView::subtreeSelectionBounds(const SelectionSubtreeRoot& root, } selRect.unite(currRect); } - return selRect; + return pixelSnappedIntRect(selRect); } void RenderView::repaintSelection() const { - repaintSubtreeSelection(*this); - - if (hasRenderNamedFlowThreads()) { - for (auto* namedFlowThread : *m_flowThreadController->renderNamedFlowThreadList()) - repaintSubtreeSelection(*namedFlowThread); - } -} - -void RenderView::repaintSubtreeSelection(const SelectionSubtreeRoot& root) const -{ HashSet<RenderBlock*> processedBlocks; - RenderObject* end = rendererAfterPosition(root.selectionData().selectionEnd(), root.selectionData().selectionEndPos()); - SelectionIterator selectionIterator(root.selectionData().selectionStart()); - for (RenderObject* o = selectionIterator.current(); o && o != end; o = selectionIterator.next()) { - if (!o->canBeSelectionLeaf() && o != root.selectionData().selectionStart() && o != root.selectionData().selectionEnd()) + RenderObject* end = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); + for (RenderObject* o = m_selectionStart; o && o != end; o = o->nextInPreOrder()) { + if (!o->canBeSelectionLeaf() && o != m_selectionStart && o != m_selectionEnd) continue; if (o->selectionState() == SelectionNone) continue; - RenderSelectionInfo(*o, true).repaint(); + RenderSelectionInfo(o, true).repaint(); // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. - for (RenderBlock* block = o->containingBlock(); block && !is<RenderView>(*block); block = block->containingBlock()) { + for (RenderBlock* block = o->containingBlock(); block && !block->isRenderView(); block = block->containingBlock()) { if (!processedBlocks.add(block).isNewEntry) break; - RenderSelectionInfo(*block, true).repaint(); + RenderSelectionInfo(block, true).repaint(); } } } -void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) +#if USE(ACCELERATED_COMPOSITING) +// Compositing layer dimensions take outline size into account, so we have to recompute layer +// bounds when it changes. +// FIXME: This is ugly; it would be nice to have a better way to do this. +void RenderView::setMaximalOutlineSize(int o) { - // Make sure both our start and end objects are defined. - // Check www.msnbc.com and try clicking around to find the case where this happened. - if ((start && !end) || (end && !start)) - return; - - bool caretChanged = m_selectionWasCaret != frame().selection().isCaret(); - m_selectionWasCaret = frame().selection().isCaret(); - // Just return if the selection hasn't changed. - if (m_selectionUnsplitStart == start && m_selectionUnsplitStartPos == startPos - && m_selectionUnsplitEnd == end && m_selectionUnsplitEndPos == endPos && !caretChanged) { - return; - } + if (o != m_maximalOutlineSize) { + m_maximalOutlineSize = o; -#if ENABLE(SERVICE_CONTROLS) - // Clear the current rects and create a notifier for the new rects we are about to gather. - // The Notifier updates the Editor when it goes out of scope and is destroyed. - std::unique_ptr<SelectionRectGatherer::Notifier> rectNotifier = m_selectionRectGatherer.clearAndCreateNotifier(); -#endif // ENABLE(SERVICE_CONTROLS) - // Set global positions for new selection. - m_selectionUnsplitStart = start; - m_selectionUnsplitStartPos = startPos; - m_selectionUnsplitEnd = end; - m_selectionUnsplitEndPos = endPos; - - // If there is no RenderNamedFlowThreads we follow the regular selection. - if (!hasRenderNamedFlowThreads()) { - RenderSubtreesMap singleSubtreeMap; - singleSubtreeMap.set(this, SelectionSubtreeData(start, startPos, end, endPos)); - updateSelectionForSubtrees(singleSubtreeMap, blockRepaintMode); - return; + // maximalOutlineSize affects compositing layer dimensions. + compositor().setCompositingLayersNeedRebuild(); // FIXME: this really just needs to be a geometry update. } - - splitSelectionBetweenSubtrees(start, startPos, end, endPos, blockRepaintMode); } +#endif -void RenderView::splitSelectionBetweenSubtrees(const RenderObject* start, int startPos, const RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) -{ - // Compute the visible selection end points for each of the subtrees. - RenderSubtreesMap renderSubtreesMap; - - SelectionSubtreeData initialSelection; - renderSubtreesMap.set(this, initialSelection); - for (auto* namedFlowThread : *flowThreadController().renderNamedFlowThreadList()) - renderSubtreesMap.set(namedFlowThread, initialSelection); - - if (start && end) { - Node* startNode = start->node(); - Node* endNode = end->node(); - ASSERT(endNode); - Node* stopNode = NodeTraversal::nextSkippingChildren(*endNode); - - for (Node* node = startNode; node != stopNode; node = NodeTraversal::next(*node)) { - RenderObject* renderer = node->renderer(); - if (!renderer) - continue; - - SelectionSubtreeRoot& root = renderer->selectionRoot(); - SelectionSubtreeData selectionData = renderSubtreesMap.get(&root); - if (selectionData.selectionClear()) { - selectionData.setSelectionStart(node->renderer()); - selectionData.setSelectionStartPos(node == startNode ? startPos : 0); - } - - selectionData.setSelectionEnd(node->renderer()); - if (node == endNode) - selectionData.setSelectionEndPos(endPos); - else - selectionData.setSelectionEndPos(node->offsetInCharacters() ? node->maxCharacterOffset() : node->countChildNodes()); - - renderSubtreesMap.set(&root, selectionData); +// When exploring the RenderTree looking for the nodes involved in the Selection, sometimes it's +// required to change the traversing direction because the "start" position is below the "end" one. +static inline RenderObject* getNextOrPrevRenderObjectBasedOnDirection(const RenderObject* o, const RenderObject* stop, bool& continueExploring, bool& exploringBackwards) +{ + RenderObject* next; + if (exploringBackwards) { + next = o->previousInPreOrder(); + continueExploring = next && !(next)->isRenderView(); + } else { + next = o->nextInPreOrder(); + continueExploring = next && next != stop; + exploringBackwards = !next && (next != stop); + if (exploringBackwards) { + next = stop->previousInPreOrder(); + continueExploring = next && !next->isRenderView(); } } - - updateSelectionForSubtrees(renderSubtreesMap, blockRepaintMode); -} - -void RenderView::updateSelectionForSubtrees(RenderSubtreesMap& renderSubtreesMap, SelectionRepaintMode blockRepaintMode) -{ - SubtreeOldSelectionDataMap oldSelectionDataMap; - for (auto& subtreeSelectionInfo : renderSubtreesMap) { - SelectionSubtreeRoot& root = *subtreeSelectionInfo.key; - std::unique_ptr<OldSelectionData> oldSelectionData = std::make_unique<OldSelectionData>(); - - clearSubtreeSelection(root, blockRepaintMode, *oldSelectionData); - oldSelectionDataMap.set(&root, WTFMove(oldSelectionData)); - - root.setSelectionData(subtreeSelectionInfo.value); - if (hasRenderNamedFlowThreads()) - root.adjustForVisibleSelection(document()); - } - // Update selection status for the objects inside the selection subtrees. - // This needs to be done after the previous loop updated the selectionStart/End - // parameters of all subtrees because we're going to be climbing up the containing - // block chain and we might end up in a different selection subtree. - for (const auto* subtreeSelectionRoot : renderSubtreesMap.keys()) { - OldSelectionData& oldSelectionData = *oldSelectionDataMap.get(subtreeSelectionRoot); - applySubtreeSelection(*subtreeSelectionRoot, blockRepaintMode, oldSelectionData); - } + return next; } -static inline bool isValidObjectForNewSelection(const SelectionSubtreeRoot& root, const RenderObject& object) +void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) { - return (object.canBeSelectionLeaf() || &object == root.selectionData().selectionStart() || &object == root.selectionData().selectionEnd()) && object.selectionState() != RenderObject::SelectionNone && object.containingBlock(); -} + // Make sure both our start and end objects are defined. + // Check www.msnbc.com and try clicking around to find the case where this happened. + if ((start && !end) || (end && !start)) + return; + + bool caretChanged = m_selectionWasCaret != view().frame().selection().isCaret(); + m_selectionWasCaret = view().frame().selection().isCaret(); + // Just return if the selection hasn't changed. + if (m_selectionStart == start && m_selectionStartPos == startPos && + m_selectionEnd == end && m_selectionEndPos == endPos && !caretChanged) + return; -void RenderView::clearSubtreeSelection(const SelectionSubtreeRoot& root, SelectionRepaintMode blockRepaintMode, OldSelectionData& oldSelectionData) const -{ // Record the old selected objects. These will be used later // when we compare against the new selected objects. - oldSelectionData.selectionStartPos = root.selectionData().selectionStartPos(); - oldSelectionData.selectionEndPos = root.selectionData().selectionEndPos(); - + int oldStartPos = m_selectionStartPos; + int oldEndPos = m_selectionEndPos; + + // Objects each have a single selection rect to examine. + typedef HashMap<RenderObject*, OwnPtr<RenderSelectionInfo>> SelectedObjectMap; + SelectedObjectMap oldSelectedObjects; + SelectedObjectMap newSelectedObjects; + // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks. // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise // the union of those rects might remain the same even when changes have occurred. + typedef HashMap<RenderBlock*, OwnPtr<RenderBlockSelectionInfo>> SelectedBlockMap; + SelectedBlockMap oldSelectedBlocks; + SelectedBlockMap newSelectedBlocks; - RenderObject* os = root.selectionData().selectionStart(); - RenderObject* stop = rendererAfterPosition(root.selectionData().selectionEnd(), root.selectionData().selectionEndPos()); - SelectionIterator selectionIterator(os); - while (os && os != stop) { - if (isValidObjectForNewSelection(root, *os)) { + RenderObject* os = m_selectionStart; + RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); + bool exploringBackwards = false; + bool continueExploring = os && (os != stop); + while (continueExploring) { + if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. - oldSelectionData.selectedObjects.set(os, std::make_unique<RenderSelectionInfo>(*os, true)); + oldSelectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, true))); if (blockRepaintMode == RepaintNewXOROld) { RenderBlock* cb = os->containingBlock(); - while (cb && !is<RenderView>(*cb)) { - std::unique_ptr<RenderBlockSelectionInfo>& blockInfo = oldSelectionData.selectedBlocks.add(cb, nullptr).iterator->value; + while (cb && !cb->isRenderView()) { + OwnPtr<RenderBlockSelectionInfo>& blockInfo = oldSelectedBlocks.add(cb, nullptr).iterator->value; if (blockInfo) break; - blockInfo = std::make_unique<RenderBlockSelectionInfo>(*cb); + blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); cb = cb->containingBlock(); } } } - os = selectionIterator.next(); + os = getNextOrPrevRenderObjectBasedOnDirection(os, stop, continueExploring, exploringBackwards); } - for (auto* selectedObject : oldSelectionData.selectedObjects.keys()) - selectedObject->setSelectionStateIfNeeded(SelectionNone); -} + // Now clear the selection. + SelectedObjectMap::iterator oldObjectsEnd = oldSelectedObjects.end(); + for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) + i->key->setSelectionStateIfNeeded(SelectionNone); -void RenderView::applySubtreeSelection(const SelectionSubtreeRoot& root, SelectionRepaintMode blockRepaintMode, const OldSelectionData& oldSelectionData) -{ - // Update the selection status of all objects between selectionStart and selectionEnd - if (root.selectionData().selectionStart() && root.selectionData().selectionStart() == root.selectionData().selectionEnd()) - root.selectionData().selectionStart()->setSelectionStateIfNeeded(SelectionBoth); + // set selection start and end + m_selectionStart = start; + m_selectionStartPos = startPos; + m_selectionEnd = end; + m_selectionEndPos = endPos; + + // Update the selection status of all objects between m_selectionStart and m_selectionEnd + if (start && start == end) + start->setSelectionStateIfNeeded(SelectionBoth); else { - if (root.selectionData().selectionStart()) - root.selectionData().selectionStart()->setSelectionStateIfNeeded(SelectionStart); - if (root.selectionData().selectionEnd()) - root.selectionData().selectionEnd()->setSelectionStateIfNeeded(SelectionEnd); + if (start) + start->setSelectionStateIfNeeded(SelectionStart); + if (end) + end->setSelectionStateIfNeeded(SelectionEnd); } - RenderObject* selectionStart = root.selectionData().selectionStart(); - RenderObject* selectionEnd = rendererAfterPosition(root.selectionData().selectionEnd(), root.selectionData().selectionEndPos()); - SelectionIterator selectionIterator(selectionStart); - for (RenderObject* currentRenderer = selectionStart; currentRenderer && currentRenderer != selectionEnd; currentRenderer = selectionIterator.next()) { - if (currentRenderer == root.selectionData().selectionStart() || currentRenderer == root.selectionData().selectionEnd()) - continue; - if (!currentRenderer->canBeSelectionLeaf()) - continue; - // FIXME: Move this logic to SelectionIterator::next() - if (¤tRenderer->selectionRoot() != &root) - continue; - currentRenderer->setSelectionStateIfNeeded(SelectionInside); + RenderObject* o = start; + stop = rendererAfterPosition(end, endPos); + + while (o && o != stop) { + if (o != start && o != end && o->canBeSelectionLeaf()) + o->setSelectionStateIfNeeded(SelectionInside); + o = o->nextInPreOrder(); } if (blockRepaintMode != RepaintNothing) @@ -1001,48 +927,36 @@ void RenderView::applySubtreeSelection(const SelectionSubtreeRoot& root, Selecti // Now that the selection state has been updated for the new objects, walk them again and // put them in the new objects list. - SelectedObjectMap newSelectedObjects; - SelectedBlockMap newSelectedBlocks; - selectionIterator = SelectionIterator(selectionStart); - for (RenderObject* currentRenderer = selectionStart; currentRenderer && currentRenderer != selectionEnd; currentRenderer = selectionIterator.next()) { - if (isValidObjectForNewSelection(root, *currentRenderer)) { - std::unique_ptr<RenderSelectionInfo> selectionInfo = std::make_unique<RenderSelectionInfo>(*currentRenderer, true); - -#if ENABLE(SERVICE_CONTROLS) - for (auto& rect : selectionInfo->collectedSelectionRects()) - m_selectionRectGatherer.addRect(selectionInfo->repaintContainer(), rect); - if (!currentRenderer->isTextOrLineBreak()) - m_selectionRectGatherer.setTextOnly(false); -#endif - - newSelectedObjects.set(currentRenderer, WTFMove(selectionInfo)); - - RenderBlock* containingBlock = currentRenderer->containingBlock(); - while (containingBlock && !is<RenderView>(*containingBlock)) { - std::unique_ptr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(containingBlock, nullptr).iterator->value; + o = start; + exploringBackwards = false; + continueExploring = o && (o != stop); + while (continueExploring) { + if ((o->canBeSelectionLeaf() || o == start || o == end) && o->selectionState() != SelectionNone) { + newSelectedObjects.set(o, adoptPtr(new RenderSelectionInfo(o, true))); + RenderBlock* cb = o->containingBlock(); + while (cb && !cb->isRenderView()) { + OwnPtr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(cb, nullptr).iterator->value; if (blockInfo) break; - blockInfo = std::make_unique<RenderBlockSelectionInfo>(*containingBlock); - containingBlock = containingBlock->containingBlock(); - -#if ENABLE(SERVICE_CONTROLS) - m_selectionRectGatherer.addGapRects(blockInfo->repaintContainer(), blockInfo->rects()); -#endif + blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); + cb = cb->containingBlock(); } } + + o = getNextOrPrevRenderObjectBasedOnDirection(o, stop, continueExploring, exploringBackwards); } if (blockRepaintMode == RepaintNothing) return; // Have any of the old selected objects changed compared to the new selection? - for (const auto& selectedObjectInfo : oldSelectionData.selectedObjects) { - RenderObject* obj = selectedObjectInfo.key; + for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) { + RenderObject* obj = i->key; RenderSelectionInfo* newInfo = newSelectedObjects.get(obj); - RenderSelectionInfo* oldInfo = selectedObjectInfo.value.get(); - if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() - || (root.selectionData().selectionStart() == obj && oldSelectionData.selectionStartPos != root.selectionData().selectionStartPos()) - || (root.selectionData().selectionEnd() == obj && oldSelectionData.selectionEndPos != root.selectionData().selectionEndPos())) { + RenderSelectionInfo* oldInfo = i->value.get(); + if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() || + (m_selectionStart == obj && oldStartPos != m_selectionStartPos) || + (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) { oldInfo->repaint(); if (newInfo) { newInfo->repaint(); @@ -1052,14 +966,16 @@ void RenderView::applySubtreeSelection(const SelectionSubtreeRoot& root, Selecti } // Any new objects that remain were not found in the old objects dict, and so they need to be updated. - for (const auto& selectedObjectInfo : newSelectedObjects) - selectedObjectInfo.value->repaint(); + SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end(); + for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) + i->value->repaint(); // Have any of the old blocks changed? - for (const auto& selectedBlockInfo : oldSelectionData.selectedBlocks) { - const RenderBlock* block = selectedBlockInfo.key; + SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end(); + for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) { + RenderBlock* block = i->key; RenderBlockSelectionInfo* newInfo = newSelectedBlocks.get(block); - RenderBlockSelectionInfo* oldInfo = selectedBlockInfo.value.get(); + RenderBlockSelectionInfo* oldInfo = i->value.get(); if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) { oldInfo->repaint(); if (newInfo) { @@ -1070,16 +986,17 @@ void RenderView::applySubtreeSelection(const SelectionSubtreeRoot& root, Selecti } // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated. - for (const auto& selectedBlockInfo : newSelectedBlocks) - selectedBlockInfo.value->repaint(); + SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end(); + for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) + i->value->repaint(); } void RenderView::getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const { - startRenderer = m_selectionUnsplitStart; - startOffset = m_selectionUnsplitStartPos; - endRenderer = m_selectionUnsplitEnd; - endOffset = m_selectionUnsplitEndPos; + startRenderer = m_selectionStart; + startOffset = m_selectionStartPos; + endRenderer = m_selectionEnd; + endOffset = m_selectionEndPos; } void RenderView::clearSelection() @@ -1088,6 +1005,12 @@ void RenderView::clearSelection() setSelection(nullptr, -1, nullptr, -1, RepaintNewMinusOld); } +void RenderView::selectionStartEnd(int& startPos, int& endPos) const +{ + startPos = m_selectionStartPos; + endPos = m_selectionEndPos; +} + bool RenderView::printing() const { return document().printing(); @@ -1111,31 +1034,30 @@ IntRect RenderView::unscaledDocumentRect() const { LayoutRect overflowRect(layoutOverflowRect()); flipForWritingMode(overflowRect); - return snappedIntRect(overflowRect); + return pixelSnappedIntRect(overflowRect); } bool RenderView::rootBackgroundIsEntirelyFixed() const { - RenderElement* rootObject = document().documentElement() ? document().documentElement()->renderer() : nullptr; + RenderElement* rootObject = document().documentElement() ? document().documentElement()->renderer() : 0; if (!rootObject) return false; return rootObject->rendererForRootBackground().hasEntirelyFixedBackground(); } - -LayoutRect RenderView::unextendedBackgroundRect() const -{ - // FIXME: What is this? Need to patch for new columns? - return unscaledDocumentRect(); -} - -LayoutRect RenderView::backgroundRect() const + +LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const { - // FIXME: New columns care about this? - if (frameView().hasExtendedBackgroundRectForPainting()) - return frameView().extendedBackgroundRectForPainting(); + if (!hasColumns()) + return frameView().hasExtendedBackground() ? frameView().extendedBackgroundRect() : unscaledDocumentRect(); - return unextendedBackgroundRect(); + ColumnInfo* columnInfo = this->columnInfo(); + LayoutRect backgroundRect(0, 0, columnInfo->desiredColumnWidth(), columnInfo->columnHeight() * columnInfo->columnCount()); + if (!isHorizontalWritingMode()) + backgroundRect = backgroundRect.transposedRect(); + backgroundRenderer->flipForWritingMode(backgroundRect); + + return backgroundRect; } IntRect RenderView::documentRect() const @@ -1182,24 +1104,24 @@ void RenderView::pushLayoutState(RenderObject& root) ASSERT(m_layoutStateDisableCount == 0); ASSERT(m_layoutState == 0); - m_layoutState = std::make_unique<LayoutState>(root); pushLayoutStateForCurrentFlowThread(root); + m_layoutState = std::make_unique<LayoutState>(root); } bool RenderView::shouldDisableLayoutStateForSubtree(RenderObject* renderer) const { RenderObject* o = renderer; while (o) { - if (o->hasTransform() || o->hasReflection()) + if (o->hasColumns() || o->hasTransform() || o->hasReflection()) return true; o = o->container(); } return false; } -IntSize RenderView::viewportSizeForCSSViewportUnits() const +IntSize RenderView::viewportSize() const { - return frameView().viewportSizeForCSSViewportUnits(); + return frameView().visibleContentRectIncludingScrollbars(ScrollableArea::LegacyIOSDocumentVisibleRect).size(); } void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) @@ -1207,9 +1129,6 @@ void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& p if (result.innerNode()) return; - if (multiColumnFlowThread() && multiColumnFlowThread()->firstMultiColumnSet()) - return multiColumnFlowThread()->firstMultiColumnSet()->updateHitTestResult(result, point); - Node* node = document().documentElement(); if (node) { result.setInnerNode(node); @@ -1241,13 +1160,14 @@ void RenderView::setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bo } // Prefer the widest object that tries to move the pagination point - LayoutRect boundingBox = forRenderer->borderBoundingBox(); + IntRect boundingBox = forRenderer->borderBoundingBox(); if (boundingBox.width() > m_legacyPrinting.m_truncatorWidth) { m_legacyPrinting.m_truncatorWidth = boundingBox.width(); m_legacyPrinting.m_bestTruncatedAt = y; } } +#if USE(ACCELERATED_COMPOSITING) bool RenderView::usesCompositing() const { return m_compositor && m_compositor->inCompositingMode(); @@ -1256,15 +1176,20 @@ bool RenderView::usesCompositing() const RenderLayerCompositor& RenderView::compositor() { if (!m_compositor) - m_compositor = std::make_unique<RenderLayerCompositor>(*this); + m_compositor = adoptPtr(new RenderLayerCompositor(*this)); return *m_compositor; } +#endif void RenderView::setIsInWindow(bool isInWindow) { +#if USE(ACCELERATED_COMPOSITING) if (m_compositor) m_compositor->setIsInWindow(isInWindow); +#else + UNUSED_PARAM(isInWindow); +#endif } void RenderView::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) @@ -1272,8 +1197,6 @@ void RenderView::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl RenderBlockFlow::styleDidChange(diff, oldStyle); if (hasRenderNamedFlowThreads()) flowThreadController().styleDidChange(); - - frameView().styleDidChange(); } bool RenderView::hasRenderNamedFlowThreads() const @@ -1289,22 +1212,38 @@ bool RenderView::checkTwoPassLayoutForAutoHeightRegions() const FlowThreadController& RenderView::flowThreadController() { if (!m_flowThreadController) - m_flowThreadController = std::make_unique<FlowThreadController>(this); + m_flowThreadController = FlowThreadController::create(this); return *m_flowThreadController; } +#if PLATFORM(IOS) +static bool isFixedPositionInViewport(const RenderObject& renderer, const RenderObject* container) +{ + return (renderer.style().position() == FixedPosition) && renderer.container() == container; +} + +bool RenderView::hasCustomFixedPosition(const RenderObject& renderer, ContainingBlockCheck checkContainer) const +{ + if (!frameView().useCustomFixedPositionLayoutRect()) + return false; + + if (checkContainer == CheckContainingBlock) + return isFixedPositionInViewport(renderer, this); + + return renderer.style().position() == FixedPosition; +} +#endif + void RenderView::pushLayoutStateForCurrentFlowThread(const RenderObject& object) { if (!m_flowThreadController) return; - RenderFlowThread* currentFlowThread = object.flowThreadContainingBlock(); + RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); if (!currentFlowThread) return; - m_layoutState->setCurrentRenderFlowThread(currentFlowThread); - currentFlowThread->pushFlowThreadLayoutState(object); } @@ -1313,68 +1252,25 @@ void RenderView::popLayoutStateForCurrentFlowThread() if (!m_flowThreadController) return; - RenderFlowThread* currentFlowThread = m_layoutState->currentRenderFlowThread(); + RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); if (!currentFlowThread) return; currentFlowThread->popFlowThreadLayoutState(); } -ImageQualityController& RenderView::imageQualityController() -{ - if (!m_imageQualityController) - m_imageQualityController = std::make_unique<ImageQualityController>(*this); - return *m_imageQualityController; -} - -void RenderView::registerForVisibleInViewportCallback(RenderElement& renderer) -{ - ASSERT(!m_visibleInViewportRenderers.contains(&renderer)); - m_visibleInViewportRenderers.add(&renderer); -} - -void RenderView::unregisterForVisibleInViewportCallback(RenderElement& renderer) -{ - ASSERT(m_visibleInViewportRenderers.contains(&renderer)); - m_visibleInViewportRenderers.remove(&renderer); -} - -void RenderView::updateVisibleViewportRect(const IntRect& visibleRect) -{ - resumePausedImageAnimationsIfNeeded(visibleRect); - - for (auto* renderer : m_visibleInViewportRenderers) - renderer->visibleInViewportStateChanged(visibleRect.intersects(enclosingIntRect(renderer->absoluteClippedOverflowRect())) ? RenderElement::VisibleInViewport : RenderElement::NotVisibleInViewport); -} - -void RenderView::addRendererWithPausedImageAnimations(RenderElement& renderer) -{ - if (renderer.hasPausedImageAnimations()) { - ASSERT(m_renderersWithPausedImageAnimation.contains(&renderer)); - return; - } - renderer.setHasPausedImageAnimations(true); - m_renderersWithPausedImageAnimation.add(&renderer); -} - -void RenderView::removeRendererWithPausedImageAnimations(RenderElement& renderer) +IntervalArena* RenderView::intervalArena() { - ASSERT(renderer.hasPausedImageAnimations()); - ASSERT(m_renderersWithPausedImageAnimation.contains(&renderer)); - - renderer.setHasPausedImageAnimations(false); - m_renderersWithPausedImageAnimation.remove(&renderer); + if (!m_intervalArena) + m_intervalArena = IntervalArena::create(); + return m_intervalArena.get(); } -void RenderView::resumePausedImageAnimationsIfNeeded(IntRect visibleRect) +ImageQualityController& RenderView::imageQualityController() { - Vector<RenderElement*, 10> toRemove; - for (auto* renderer : m_renderersWithPausedImageAnimation) { - if (renderer->repaintForPausedImageAnimationsIfNeeded(visibleRect)) - toRemove.append(renderer); - } - for (auto& renderer : toRemove) - removeRendererWithPausedImageAnimations(*renderer); + if (!m_imageQualityController) + m_imageQualityController = ImageQualityController::create(*this); + return *m_imageQualityController; } RenderView::RepaintRegionAccumulator::RepaintRegionAccumulator(RenderView* view) @@ -1396,54 +1292,4 @@ RenderView::RepaintRegionAccumulator::~RepaintRegionAccumulator() m_rootView->flushAccumulatedRepaintRegion(); } -unsigned RenderView::pageNumberForBlockProgressionOffset(int offset) const -{ - int columnNumber = 0; - const Pagination& pagination = frameView().frame().page()->pagination(); - if (pagination.mode == Pagination::Unpaginated) - return columnNumber; - - bool progressionIsInline = false; - bool progressionIsReversed = false; - - if (multiColumnFlowThread()) { - progressionIsInline = multiColumnFlowThread()->progressionIsInline(); - progressionIsReversed = multiColumnFlowThread()->progressionIsReversed(); - } else - return columnNumber; - - if (!progressionIsInline) { - if (!progressionIsReversed) - columnNumber = (pagination.pageLength + pagination.gap - offset) / (pagination.pageLength + pagination.gap); - else - columnNumber = offset / (pagination.pageLength + pagination.gap); - } - - return columnNumber; -} - -unsigned RenderView::pageCount() const -{ - const Pagination& pagination = frameView().frame().page()->pagination(); - if (pagination.mode == Pagination::Unpaginated) - return 0; - - if (multiColumnFlowThread() && multiColumnFlowThread()->firstMultiColumnSet()) - return multiColumnFlowThread()->firstMultiColumnSet()->columnCount(); - - return 0; -} - -#if ENABLE(CSS_SCROLL_SNAP) -void RenderView::registerBoxWithScrollSnapCoordinates(const RenderBox& box) -{ - m_boxesWithScrollSnapCoordinates.add(&box); -} - -void RenderView::unregisterBoxWithScrollSnapCoordinates(const RenderBox& box) -{ - m_boxesWithScrollSnapCoordinates.remove(&box); -} -#endif - } // namespace WebCore |