summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/RenderView.cpp')
-rw-r--r--Source/WebCore/rendering/RenderView.cpp344
1 files changed, 284 insertions, 60 deletions
diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp
index bdb9c8069..251659fc1 100644
--- a/Source/WebCore/rendering/RenderView.cpp
+++ b/Source/WebCore/rendering/RenderView.cpp
@@ -27,19 +27,23 @@
#include "FloatQuad.h"
#include "FlowThreadController.h"
#include "Frame.h"
+#include "FrameSelection.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "HTMLFrameOwnerElement.h"
+#include "HTMLIFrameElement.h"
#include "HitTestResult.h"
#include "Page.h"
#include "RenderGeometryMap.h"
#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
#include "RenderNamedFlowThread.h"
#include "RenderSelectionInfo.h"
#include "RenderWidget.h"
#include "RenderWidgetProtector.h"
#include "StyleInheritedData.h"
#include "TransformState.h"
+#include <wtf/StackStats.h>
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerCompositor.h"
@@ -51,9 +55,9 @@
namespace WebCore {
-RenderView::RenderView(Node* node, FrameView* view)
- : RenderBlock(node)
- , m_frameView(view)
+RenderView::RenderView(Document* document)
+ : RenderBlock(document)
+ , m_frameView(document->view())
, m_selectionStart(0)
, m_selectionEnd(0)
, m_selectionStartPos(-1)
@@ -65,12 +69,8 @@ RenderView::RenderView(Node* node, FrameView* view)
, m_layoutStateDisableCount(0)
, m_renderQuoteHead(0)
, m_renderCounterCount(0)
- , m_layoutPhase(RenderViewNormalLayout)
+ , m_selectionWasCaret(false)
{
- // Clear our anonymous bit, set because RenderObject assumes
- // any renderer with document as the node is anonymous.
- setIsAnonymous(false);
-
// init RenderObject attributes
setInline(false);
@@ -79,7 +79,7 @@ RenderView::RenderView(Node* node, FrameView* view)
setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
- setPositioned(true); // to 0,0 :)
+ setPositionState(AbsolutePosition); // to 0,0 :)
}
RenderView::~RenderView()
@@ -93,12 +93,21 @@ bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result)
bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result)
{
- bool inside = layer()->hitTest(request, location, result);
+ if (layer()->hitTest(request, location, result))
+ return true;
- // Next set up the correct :hover/:active state along the new chain.
- document()->updateHoverActiveState(request, result);
+ // FIXME: Consider if this test should be done unconditionally.
+ if (request.allowsFrameScrollbars() && m_frameView) {
+ // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls,
+ // so we need to test ScrollView scrollbars separately here.
+ Scrollbar* frameScrollbar = m_frameView->scrollbarAtPoint(location.roundedPoint());
+ if (frameScrollbar) {
+ result.setScrollbar(frameScrollbar);
+ return true;
+ }
+ }
- return inside;
+ return false;
}
void RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit, LogicalExtentComputedValues& computedValues) const
@@ -112,19 +121,12 @@ void RenderView::updateLogicalWidth()
setLogicalWidth(viewLogicalWidth());
}
-void RenderView::computePreferredLogicalWidths()
-{
- ASSERT(preferredLogicalWidthsDirty());
-
- RenderBlock::computePreferredLogicalWidths();
-}
-
-LayoutUnit RenderView::availableLogicalHeight() const
+LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType heightType) const
{
// If we have columns, then the available logical height is reduced to the column height.
if (hasColumns())
return columnInfo()->columnHeight();
- return RenderBlock::availableLogicalHeight();
+ return RenderBlock::availableLogicalHeight(heightType);
}
bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const
@@ -154,6 +156,110 @@ void RenderView::checkLayoutState(const LayoutState& state)
}
#endif
+static RenderBox* enclosingSeamlessRenderer(Document* doc)
+{
+ if (!doc)
+ return 0;
+ Element* ownerElement = doc->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());
+ }
+ RenderBlock::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;
+
+ // 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
+// to ensure the results are the same as those obtained from a full layout (i.e. the auto-height regions from all the flows are marked as needing
+// layout).
+// 1. The flows are laid out from the outer flow to the inner flow. This successfully computes the outer non-auto-height regions size so the
+// inner flows have the necessary information to correctly fragment the content.
+// 2. The flows are laid out from the inner flow to the outer flow. After an inner flow is laid out it goes into the constrained layout phase
+// and marks the auto-height regions they need layout. This means the outer flows will relayout if they depend on regions with auto-height regions
+// belonging to inner flows. This step will correctly set the computedAutoHeight for the auto-height regions. It's possible for non-auto-height
+// regions to relayout if they depend on auto-height regions. This will invalidate the inner flow threads and mark them as needing layout.
+// 3. The last step is to do one last layout if there are pathological dependencies between non-auto-height regions and auto-height regions
+// as detected in the previous step.
+void RenderView::layoutContentInAutoLogicalHeightRegions(const LayoutState& state)
+{
+ // We need to invalidate all the flows with auto-height regions if one such flow needs layout.
+ // If none is found we do a layout a check back again afterwards.
+ if (!flowThreadController()->updateFlowThreadsNeedingLayout()) {
+ // Do a first layout of the content. In some cases more layouts are not needed (e.g. only flows with non-auto-height regions have changed).
+ layoutContent(state);
+
+ // If we find no named flow needing a two step layout after the first layout, exit early.
+ // Otherwise, initiate the two step layout algorithm and recompute all the flows.
+ if (!flowThreadController()->updateFlowThreadsNeedingTwoStepLayout())
+ return;
+ }
+
+ // Layout to recompute all the named flows with auto-height regions.
+ layoutContent(state);
+
+ // Propagate the computed auto-height values upwards.
+ // Non-auto-height regions may invalidate the flow thread because they depended on auto-height regions, but that's ok.
+ flowThreadController()->updateFlowThreadsIntoConstrainedPhase();
+
+ // Do one last layout that should update the auto-height regions found in the main flow
+ // and solve pathological dependencies between regions (e.g. a non-auto-height region depending
+ // on an auto-height one).
+ if (needsLayout())
+ layoutContent(state);
+}
+
void RenderView::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
@@ -168,10 +274,17 @@ void RenderView::layout()
if (relayoutChildren) {
setChildNeedsLayout(true, MarkOnlyThis);
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight())
+ if ((child->isBox() && (toRenderBox(child)->hasRelativeLogicalHeight() || toRenderBox(child)->hasViewportPercentageLogicalHeight()))
|| child->style()->logicalHeight().isPercent()
|| child->style()->logicalMinHeight().isPercent()
- || child->style()->logicalMaxHeight().isPercent())
+ || child->style()->logicalMaxHeight().isPercent()
+ || child->style()->logicalHeight().isViewportPercentage()
+ || child->style()->logicalMinHeight().isViewportPercentage()
+ || child->style()->logicalMaxHeight().isViewportPercentage()
+#if ENABLE(SVG)
+ || child->isSVGRoot()
+#endif
+ )
child->setChildNeedsLayout(true, MarkOnlyThis);
}
}
@@ -181,33 +294,37 @@ void RenderView::layout()
return;
LayoutState state;
- // 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;
- state.m_isPaginated = state.m_pageLogicalHeight;
+ bool isSeamlessAncestorInFlowThread = initializeLayoutState(state);
+
m_pageLogicalHeightChanged = false;
m_layoutState = &state;
- m_layoutPhase = RenderViewNormalLayout;
- bool needsTwoPassLayoutForAutoLogicalHeightRegions = hasRenderNamedFlowThreads() && flowThreadController()->hasAutoLogicalHeightRegions();
-
- if (needsTwoPassLayoutForAutoLogicalHeightRegions)
- flowThreadController()->resetRegionsOverrideLogicalContentHeight();
-
- layoutContent(state);
-
- if (needsTwoPassLayoutForAutoLogicalHeightRegions) {
- m_layoutPhase = ConstrainedFlowThreadsLayoutInAutoLogicalHeightRegions;
- flowThreadController()->markAutoLogicalHeightRegionsForLayout();
+ if (checkTwoPassLayoutForAutoHeightRegions())
+ layoutContentInAutoLogicalHeightRegions(state);
+ else
layoutContent(state);
- }
#ifndef NDEBUG
checkLayoutState(state);
#endif
m_layoutState = 0;
setNeedsLayout(false);
+
+ if (isSeamlessAncestorInFlowThread)
+ flowThreadController()->setCurrentRenderFlowThread(0);
+}
+
+LayoutUnit RenderView::pageOrViewLogicalHeight() const
+{
+ if (document()->printing())
+ return pageLogicalHeight();
+
+ if (hasColumns() && !style()->hasInlineColumnAxis()) {
+ if (int pageLength = frameView()->pagination().pageLength)
+ return pageLength;
+ }
+
+ return viewLogicalHeight();
}
void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
@@ -294,7 +411,7 @@ void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset);
// This avoids painting garbage between columns if there is a column gap.
- if (m_frameView && m_frameView->pagination().mode != Pagination::Unpaginated)
+ if (m_frameView && m_frameView->pagination().mode != Pagination::Unpaginated && paintInfo.shouldPaintWithinRoot(this))
paintInfo.context->fillRect(paintInfo.rect, m_frameView->baseBackgroundColor(), ColorSpaceDeviceRGB);
paintObject(paintInfo, paintOffset);
@@ -328,6 +445,9 @@ static inline bool rendererObscuresBackground(RenderObject* rootObject)
void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&)
{
+ if (!paintInfo.shouldPaintWithinRoot(this))
+ return;
+
// Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit
// when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers,
// layers with reflections, or transformed layers.
@@ -354,6 +474,9 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&)
if (document()->ownerElement() || !view())
return;
+ if (paintInfo.skipRootBackground())
+ return;
+
bool rootFillsViewport = false;
bool rootObscuresBackground = false;
Node* documentElement = document()->documentElement();
@@ -452,6 +575,14 @@ void RenderView::repaintViewAndCompositedLayers()
#endif
}
+LayoutRect RenderView::visualOverflowRect() const
+{
+ if (m_frameView->paintsEntireContents())
+ return layoutOverflowRect();
+
+ return RenderBlock::visualOverflowRect();
+}
+
void RenderView::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
{
// If a container was specified, and was not 0 or the RenderView,
@@ -533,7 +664,7 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const
// RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates.
LayoutRect currRect = info->rect();
if (RenderLayerModelObject* repaintContainer = info->repaintContainer()) {
- FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect), SnapOffsetForTransforms);
+ FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect));
currRect = absQuad.enclosingBoundingBox();
}
selRect.unite(currRect);
@@ -541,6 +672,30 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const
return pixelSnappedIntRect(selRect);
}
+void RenderView::repaintSelection() const
+{
+ document()->updateStyleIfNeeded();
+
+ HashSet<RenderBlock*> processedBlocks;
+
+ 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();
+
+ // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
+ for (RenderBlock* block = o->containingBlock(); block && !block->isRenderView(); block = block->containingBlock()) {
+ if (!processedBlocks.add(block).isNewEntry)
+ break;
+ RenderSelectionInfo(block, true).repaint();
+ }
+ }
+}
+
#if USE(ACCELERATED_COMPOSITING)
// Compositing layer dimensions take outline size into account, so we have to recompute layer
// bounds when it changes.
@@ -563,9 +718,14 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e
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)
+ m_selectionEnd == end && m_selectionEndPos == endPos && !caretChanged)
+ return;
+
+ if ((start && end) && (start->flowThreadContainingBlock() != end->flowThreadContainingBlock()))
return;
// Record the old selected objects. These will be used later
@@ -819,6 +979,16 @@ IntRect RenderView::unscaledDocumentRect() const
return pixelSnappedIntRect(overflowRect);
}
+bool RenderView::rootBackgroundIsEntirelyFixed() const
+{
+ RenderObject* rootObject = document()->documentElement() ? document()->documentElement()->renderer() : 0;
+ if (!rootObject)
+ return false;
+
+ RenderObject* rootRenderer = rootObject->rendererForRootBackground();
+ return rootRenderer->hasEntirelyFixedBackground();
+}
+
LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const
{
if (!hasColumns())
@@ -864,12 +1034,6 @@ int RenderView::viewWidth() const
int RenderView::viewLogicalHeight() const
{
int height = style()->isHorizontalWritingMode() ? viewHeight() : viewWidth();
-
- if (hasColumns() && !style()->hasInlineColumnAxis()) {
- if (int pageLength = m_frameView->pagination().pageLength)
- height = pageLength;
- }
-
return height;
}
@@ -884,6 +1048,7 @@ void RenderView::pushLayoutState(RenderObject* root)
ASSERT(m_layoutStateDisableCount == 0);
ASSERT(m_layoutState == 0);
+ pushLayoutStateForCurrentFlowThread(root);
m_layoutState = new (renderArena()) LayoutState(root);
}
@@ -956,19 +1121,11 @@ RenderLayerCompositor* RenderView::compositor()
}
#endif
-void RenderView::didMoveOnscreen()
-{
-#if USE(ACCELERATED_COMPOSITING)
- if (m_compositor)
- m_compositor->didMoveOnscreen();
-#endif
-}
-
-void RenderView::willMoveOffscreen()
+void RenderView::setIsInWindow(bool isInWindow)
{
#if USE(ACCELERATED_COMPOSITING)
if (m_compositor)
- m_compositor->willMoveOffscreen();
+ m_compositor->setIsInWindow(isInWindow);
#endif
}
@@ -993,6 +1150,11 @@ bool RenderView::hasRenderNamedFlowThreads() const
return m_flowThreadController && m_flowThreadController->hasRenderNamedFlowThreads();
}
+bool RenderView::checkTwoPassLayoutForAutoHeightRegions() const
+{
+ return hasRenderNamedFlowThreads() && m_flowThreadController->hasFlowThreadsWithAutoLogicalHeightRegions();
+}
+
FlowThreadController* RenderView::flowThreadController()
{
if (!m_flowThreadController)
@@ -1001,6 +1163,30 @@ FlowThreadController* RenderView::flowThreadController()
return m_flowThreadController.get();
}
+void RenderView::pushLayoutStateForCurrentFlowThread(const RenderObject* object)
+{
+ if (!m_flowThreadController)
+ return;
+
+ RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread();
+ if (!currentFlowThread)
+ return;
+
+ currentFlowThread->pushFlowThreadLayoutState(object);
+}
+
+void RenderView::popLayoutStateForCurrentFlowThread()
+{
+ if (!m_flowThreadController)
+ return;
+
+ RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread();
+ if (!currentFlowThread)
+ return;
+
+ currentFlowThread->popFlowThreadLayoutState();
+}
+
RenderBlock::IntervalArena* RenderView::intervalArena()
{
if (!m_intervalArena)
@@ -1008,4 +1194,42 @@ RenderBlock::IntervalArena* RenderView::intervalArena()
return m_intervalArena.get();
}
+FragmentationDisabler::FragmentationDisabler(RenderObject* root)
+{
+ RenderView* renderView = root->view();
+ ASSERT(renderView);
+
+ LayoutState* layoutState = renderView->layoutState();
+
+ m_root = root;
+ m_fragmenting = layoutState && layoutState->isPaginated();
+ m_flowThreadState = m_root->flowThreadState();
+#ifndef NDEBUG
+ m_layoutState = layoutState;
+#endif
+
+ if (layoutState)
+ layoutState->m_isPaginated = false;
+
+ if (m_flowThreadState != RenderObject::NotInsideFlowThread)
+ m_root->setFlowThreadStateIncludingDescendants(RenderObject::NotInsideFlowThread);
+}
+
+FragmentationDisabler::~FragmentationDisabler()
+{
+ RenderView* renderView = m_root->view();
+ ASSERT(renderView);
+
+ LayoutState* layoutState = renderView->layoutState();
+#ifndef NDEBUG
+ ASSERT(m_layoutState == layoutState);
+#endif
+
+ if (layoutState)
+ layoutState->m_isPaginated = m_fragmenting;
+
+ if (m_flowThreadState != RenderObject::NotInsideFlowThread)
+ m_root->setFlowThreadStateIncludingDescendants(m_flowThreadState);
+}
+
} // namespace WebCore