summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderView.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/rendering/RenderView.cpp
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-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.cpp972
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 (&currentRenderer->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