diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderNamedFlowFragment.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderNamedFlowFragment.cpp | 364 |
1 files changed, 242 insertions, 122 deletions
diff --git a/Source/WebCore/rendering/RenderNamedFlowFragment.cpp b/Source/WebCore/rendering/RenderNamedFlowFragment.cpp index ef00cdf81..c191152dd 100644 --- a/Source/WebCore/rendering/RenderNamedFlowFragment.cpp +++ b/Source/WebCore/rendering/RenderNamedFlowFragment.cpp @@ -34,7 +34,9 @@ #include "PaintInfo.h" #include "RenderBoxRegionInfo.h" #include "RenderFlowThread.h" +#include "RenderIterator.h" #include "RenderNamedFlowThread.h" +#include "RenderTableCell.h" #include "RenderView.h" #include "StyleResolver.h" @@ -42,8 +44,8 @@ namespace WebCore { -RenderNamedFlowFragment::RenderNamedFlowFragment(Document& document, PassRef<RenderStyle> style) - : RenderRegion(document, std::move(style), nullptr) +RenderNamedFlowFragment::RenderNamedFlowFragment(Document& document, RenderStyle&& style) + : RenderRegion(document, WTFMove(style), nullptr) , m_hasCustomRegionStyle(false) , m_hasAutoLogicalHeight(false) , m_hasComputedAutoHeight(false) @@ -55,42 +57,42 @@ RenderNamedFlowFragment::~RenderNamedFlowFragment() { } -PassRef<RenderStyle> RenderNamedFlowFragment::createStyle(const RenderStyle& parentStyle) +RenderStyle RenderNamedFlowFragment::createStyle(const RenderStyle& parentStyle) { - auto style = RenderStyle::createAnonymousStyleWithDisplay(&parentStyle, BLOCK); + auto style = RenderStyle::createAnonymousStyleWithDisplay(parentStyle, BLOCK); - style.get().setFlowThread(parentStyle.flowThread()); - style.get().setRegionThread(parentStyle.regionThread()); - style.get().setRegionFragment(parentStyle.regionFragment()); - style.get().setOverflowX(parentStyle.overflowX()); - style.get().setOverflowY(parentStyle.overflowY()); -#if ENABLE(CSS_SHAPES) - style.get().setShapeInside(parentStyle.shapeInside()); -#endif + style.setFlowThread(parentStyle.flowThread()); + style.setRegionThread(parentStyle.regionThread()); + style.setRegionFragment(parentStyle.regionFragment()); return style; } +void RenderNamedFlowFragment::updateRegionFlags() +{ + checkRegionStyle(); + updateRegionHasAutoLogicalHeightFlag(); +} + void RenderNamedFlowFragment::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderRegion::styleDidChange(diff, oldStyle); - // If the region is not attached to any thread, there is no need to check - // whether the region has region styling since no content will be displayed - // into the region. - if (!m_flowThread) { - setHasCustomRegionStyle(false); + if (!isValid()) return; - } - updateRegionHasAutoLogicalHeightFlag(); - - checkRegionStyle(); + updateRegionFlags(); if (parent() && parent()->needsLayout()) setNeedsLayout(MarkOnlyThis); } +void RenderNamedFlowFragment::getRanges(Vector<RefPtr<Range>>& rangeObjects) const +{ + const RenderNamedFlowThread& namedFlow = view().flowThreadController().ensureRenderFlowThreadWithName(style().regionThread()); + namedFlow.getRanges(rangeObjects, this); +} + bool RenderNamedFlowFragment::shouldHaveAutoLogicalHeight() const { ASSERT(parent()); @@ -118,20 +120,18 @@ void RenderNamedFlowFragment::decrementAutoLogicalHeightCount() void RenderNamedFlowFragment::updateRegionHasAutoLogicalHeightFlag() { - ASSERT(m_flowThread); - - if (!isValid()) - return; + ASSERT(isValid()); bool didHaveAutoLogicalHeight = m_hasAutoLogicalHeight; m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); - if (m_hasAutoLogicalHeight != didHaveAutoLogicalHeight) { - if (m_hasAutoLogicalHeight) - incrementAutoLogicalHeightCount(); - else { - clearComputedAutoHeight(); - decrementAutoLogicalHeightCount(); - } + if (didHaveAutoLogicalHeight == m_hasAutoLogicalHeight) + return; + + if (m_hasAutoLogicalHeight) + incrementAutoLogicalHeightCount(); + else { + clearComputedAutoHeight(); + decrementAutoLogicalHeightCount(); } } @@ -167,7 +167,7 @@ void RenderNamedFlowFragment::updateLogicalHeight() LayoutUnit RenderNamedFlowFragment::pageLogicalHeight() const { - ASSERT(m_flowThread); + ASSERT(isValid()); if (hasComputedAutoHeight() && m_flowThread->inMeasureContentLayoutPhase()) { ASSERT(hasAutoLogicalHeight()); return computedAutoHeight(); @@ -179,13 +179,81 @@ LayoutUnit RenderNamedFlowFragment::pageLogicalHeight() const // height value for auto-height regions in the first layout phase of the parent named flow. LayoutUnit RenderNamedFlowFragment::maxPageLogicalHeight() const { - ASSERT(m_flowThread); + ASSERT(isValid()); ASSERT(hasAutoLogicalHeight() && m_flowThread->inMeasureContentLayoutPhase()); ASSERT(isAnonymous()); ASSERT(parent()); const RenderStyle& styleToUse = parent()->style(); - return styleToUse.logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogicalHeight() : toRenderBlock(parent())->computeReplacedLogicalHeightUsing(styleToUse.logicalMaxHeight()); + return styleToUse.logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogicalHeight() : downcast<RenderBlock>(*parent()).computeReplacedLogicalHeightUsing(MaxSize, styleToUse.logicalMaxHeight()); +} + +LayoutRect RenderNamedFlowFragment::flowThreadPortionRectForClipping(bool isFirstRegionInRange, bool isLastRegionInRange) const +{ + // Elements flowed into a region should not be painted past the region's content box + // if they continue to flow into another region in that direction. + // If they do not continue into another region in that direction, they should be + // painted all the way to the region's border box. + // Regions with overflow:hidden will apply clip at the border box, not the content box. + + LayoutRect clippingRect = flowThreadPortionRect(); + RenderBlockFlow& container = fragmentContainer(); + if (container.style().hasPadding()) { + if (isFirstRegionInRange) { + if (flowThread()->isHorizontalWritingMode()) { + clippingRect.move(0, -container.paddingBefore()); + clippingRect.expand(0, container.paddingBefore()); + } else { + clippingRect.move(-container.paddingBefore(), 0); + clippingRect.expand(container.paddingBefore(), 0); + } + } + + if (isLastRegionInRange) { + if (flowThread()->isHorizontalWritingMode()) + clippingRect.expand(0, container.paddingAfter()); + else + clippingRect.expand(container.paddingAfter(), 0); + } + + if (flowThread()->isHorizontalWritingMode()) { + clippingRect.move(-container.paddingStart(), 0); + clippingRect.expand(container.paddingStart() + container.paddingEnd(), 0); + } else { + clippingRect.move(0, -container.paddingStart()); + clippingRect.expand(0, container.paddingStart() + container.paddingEnd()); + } + } + + return clippingRect; +} + +RenderBlockFlow& RenderNamedFlowFragment::fragmentContainer() const +{ + ASSERT(parent()); + ASSERT(parent()->isRenderNamedFlowFragmentContainer()); + return downcast<RenderBlockFlow>(*parent()); +} + +RenderLayer& RenderNamedFlowFragment::fragmentContainerLayer() const +{ + ASSERT(fragmentContainer().layer()); + return *fragmentContainer().layer(); +} + +bool RenderNamedFlowFragment::shouldClipFlowThreadContent() const +{ + if (fragmentContainer().hasOverflowClip()) + return true; + + return isLastRegion() && (style().regionFragment() == BreakRegionFragment); +} + +LayoutSize RenderNamedFlowFragment::offsetFromContainer(RenderElement& container, const LayoutPoint&, bool*) const +{ + ASSERT_UNUSED(container, &fragmentContainer() == &container); + ASSERT_UNUSED(container, this->container() == &container); + return topLeftLocationOffset(); } void RenderNamedFlowFragment::layoutBlock(bool relayoutChildren, LayoutUnit) @@ -194,107 +262,151 @@ void RenderNamedFlowFragment::layoutBlock(bool relayoutChildren, LayoutUnit) RenderRegion::layoutBlock(relayoutChildren); if (isValid()) { - LayoutRect oldRegionRect(flowThreadPortionRect()); - if (!isHorizontalWritingMode()) - oldRegionRect = oldRegionRect.transposedRect(); - - if (m_flowThread->inOverflowLayoutPhase() || m_flowThread->inFinalLayoutPhase()) + if (m_flowThread->inOverflowLayoutPhase() || m_flowThread->inFinalLayoutPhase()) { computeOverflowFromFlowThread(); + updateOversetState(); + } if (hasAutoLogicalHeight() && m_flowThread->inMeasureContentLayoutPhase()) { m_flowThread->invalidateRegions(); clearComputedAutoHeight(); return; } + } +} - if ((oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight()) && !m_flowThread->inFinalLayoutPhase()) - // This can happen even if we are in the inConstrainedLayoutPhase and it will trigger a pathological layout of the flow thread. - m_flowThread->invalidateRegions(); +void RenderNamedFlowFragment::invalidateRegionIfNeeded() +{ + if (!isValid()) + return; + + LayoutRect oldRegionRect(flowThreadPortionRect()); + if (!isHorizontalWritingMode()) + oldRegionRect = oldRegionRect.transposedRect(); + + if ((oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight()) && !m_flowThread->inFinalLayoutPhase()) { + // This can happen even if we are in the inConstrainedLayoutPhase and it will trigger a pathological layout of the flow thread. + m_flowThread->invalidateRegions(); } } +void RenderNamedFlowFragment::setRegionOversetState(RegionOversetState state) +{ + ASSERT(generatingElement()); + + generatingElement()->setRegionOversetState(state); +} + +RegionOversetState RenderNamedFlowFragment::regionOversetState() const +{ + ASSERT(generatingElement()); + + if (!isValid()) + return RegionUndefined; + + return generatingElement()->regionOversetState(); +} + +void RenderNamedFlowFragment::updateOversetState() +{ + ASSERT(isValid()); + + RenderNamedFlowThread* flowThread = namedFlowThread(); + ASSERT(flowThread && (flowThread->inOverflowLayoutPhase() || flowThread->inFinalLayoutPhase())); + + LayoutUnit flowContentBottom = flowThread->flowContentBottom(); + bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); + + LayoutUnit flowMin = flowContentBottom - (isHorizontalWritingMode ? flowThreadPortionRect().y() : flowThreadPortionRect().x()); + LayoutUnit flowMax = flowContentBottom - (isHorizontalWritingMode ? flowThreadPortionRect().maxY() : flowThreadPortionRect().maxX()); + + RegionOversetState previousState = regionOversetState(); + RegionOversetState state = RegionFit; + if (flowMin <= 0) + state = RegionEmpty; + if (flowMax > 0 && isLastRegion()) + state = RegionOverset; + + setRegionOversetState(state); + + // Determine whether the NamedFlow object should dispatch a regionOversetChange event + if (previousState != state) + flowThread->setDispatchRegionOversetChangeEvent(true); +} + void RenderNamedFlowFragment::checkRegionStyle() { - ASSERT(m_flowThread); + ASSERT(isValid()); + bool customRegionStyle = false; // FIXME: Region styling doesn't work for pseudo elements. if (!isPseudoElement()) - customRegionStyle = view().document().ensureStyleResolver().checkRegionStyle(generatingElement()); + customRegionStyle = generatingElement()->styleResolver().checkRegionStyle(generatingElement()); setHasCustomRegionStyle(customRegionStyle); - toRenderNamedFlowThread(m_flowThread)->checkRegionsWithStyling(); + downcast<RenderNamedFlowThread>(*m_flowThread).checkRegionsWithStyling(); } -PassRefPtr<RenderStyle> RenderNamedFlowFragment::computeStyleInRegion(const RenderObject* object) +std::unique_ptr<RenderStyle> RenderNamedFlowFragment::computeStyleInRegion(RenderElement& renderer, const RenderStyle& parentStyle) const { - ASSERT(object); - ASSERT(!object->isAnonymous()); - ASSERT(object->node() && object->node()->isElementNode()); + ASSERT(!renderer.isAnonymous()); // FIXME: Region styling fails for pseudo-elements because the renderers don't have a node. - Element* element = toElement(object->node()); - RefPtr<RenderStyle> renderObjectRegionStyle = object->view().document().ensureStyleResolver().styleForElement(element, 0, DisallowStyleSharing, MatchAllRules, this); + auto renderObjectRegionStyle = renderer.element()->styleResolver().styleForElement(*renderer.element(), &parentStyle, nullptr, MatchAllRules, this).renderStyle; - return renderObjectRegionStyle.release(); + return renderObjectRegionStyle; } -void RenderNamedFlowFragment::computeChildrenStyleInRegion(const RenderElement* object) +void RenderNamedFlowFragment::computeChildrenStyleInRegion(RenderElement& renderer) { - for (RenderObject* child = object->firstChild(); child; child = child->nextSibling()) { + for (auto& child : childrenOfType<RenderElement>(renderer)) { + auto it = m_rendererRegionStyle.find(&child); - auto it = m_renderObjectRegionStyle.find(child); - - RefPtr<RenderStyle> childStyleInRegion; + std::unique_ptr<RenderStyle> childStyleInRegion; bool objectRegionStyleCached = false; - if (it != m_renderObjectRegionStyle.end()) { - childStyleInRegion = it->value.style; + if (it != m_rendererRegionStyle.end()) { + childStyleInRegion = RenderStyle::clonePtr(*it->value.style); objectRegionStyleCached = true; } else { - if (child->isAnonymous() || child->isInFlowRenderFlowThread()) - childStyleInRegion = RenderStyle::createAnonymousStyleWithDisplay(&object->style(), child->style().display()); - else if (child->isText()) - childStyleInRegion = RenderStyle::clone(&object->style()); + if (child.isAnonymous() || child.isInFlowRenderFlowThread()) + childStyleInRegion = std::make_unique<RenderStyle>(RenderStyle::createAnonymousStyleWithDisplay(renderer.style(), child.style().display())); else - childStyleInRegion = computeStyleInRegion(child); + childStyleInRegion = computeStyleInRegion(child, renderer.style()); } - setObjectStyleInRegion(child, childStyleInRegion, objectRegionStyleCached); - - if (child->isRenderElement()) - computeChildrenStyleInRegion(toRenderElement(child)); + setRendererStyleInRegion(child, WTFMove(childStyleInRegion), objectRegionStyleCached); + computeChildrenStyleInRegion(child); } } -void RenderNamedFlowFragment::setObjectStyleInRegion(RenderObject* object, PassRefPtr<RenderStyle> styleInRegion, bool objectRegionStyleCached) +void RenderNamedFlowFragment::setRendererStyleInRegion(RenderElement& renderer, std::unique_ptr<RenderStyle> styleInRegion, bool objectRegionStyleCached) { - ASSERT(object->flowThreadContainingBlock()); - - RefPtr<RenderStyle> objectOriginalStyle = &object->style(); - if (object->isRenderElement()) - toRenderElement(object)->setStyleInternal(*styleInRegion); - - if (object->isBoxModelObject() && !object->hasBoxDecorations()) { - bool hasBoxDecorations = object->isTableCell() - || object->style().hasBackground() - || object->style().hasBorder() - || object->style().hasAppearance() - || object->style().boxShadow(); - object->setHasBoxDecorations(hasBoxDecorations); + ASSERT(renderer.flowThreadContainingBlock()); + + std::unique_ptr<RenderStyle> objectOriginalStyle = RenderStyle::clonePtr(renderer.style()); + renderer.setStyleInternal(WTFMove(*styleInRegion)); + + if (is<RenderBoxModelObject>(renderer) && !renderer.hasVisibleBoxDecorations()) { + bool hasVisibleBoxDecorations = is<RenderTableCell>(renderer) + || renderer.style().hasBackground() + || renderer.style().hasVisibleBorder() + || renderer.style().hasAppearance() + || renderer.style().boxShadow(); + renderer.setHasVisibleBoxDecorations(hasVisibleBoxDecorations); } ObjectRegionStyleInfo styleInfo; - styleInfo.style = objectOriginalStyle; + styleInfo.style = WTFMove(objectOriginalStyle); styleInfo.cached = objectRegionStyleCached; - m_renderObjectRegionStyle.set(object, styleInfo); + m_rendererRegionStyle.set(&renderer, WTFMove(styleInfo)); } -void RenderNamedFlowFragment::clearObjectStyleInRegion(const RenderObject* object) +void RenderNamedFlowFragment::clearObjectStyleInRegion(const RenderElement& object) { - ASSERT(object); - m_renderObjectRegionStyle.remove(object); + m_rendererRegionStyle.remove(&object); // Clear the style for the children of this object. - for (RenderObject* child = object->firstChildSlow(); child; child = child->nextSibling()) + for (auto& child : childrenOfType<RenderElement>(object)) clearObjectStyleInRegion(child); } @@ -312,27 +424,27 @@ void RenderNamedFlowFragment::setRegionObjectsRegionStyle() // The list of content nodes contains also the nodes with display:none. if (!element->renderer()) continue; + auto& renderer = *element->renderer(); - RenderElement* object = element->renderer(); // If the content node does not flow any of its children in this region, // we do not compute any style for them in this region. - if (!flowThread()->objectInFlowRegion(object, this)) + if (!flowThread()->objectInFlowRegion(&renderer, this)) continue; // If the object has style in region, use that instead of computing a new one. - auto it = m_renderObjectRegionStyle.find(object); - RefPtr<RenderStyle> objectStyleInRegion; + auto it = m_rendererRegionStyle.find(&renderer); + std::unique_ptr<RenderStyle> objectStyleInRegion; bool objectRegionStyleCached = false; - if (it != m_renderObjectRegionStyle.end()) { - objectStyleInRegion = it->value.style; + if (it != m_rendererRegionStyle.end()) { + objectStyleInRegion = RenderStyle::clonePtr(*it->value.style); ASSERT(it->value.cached); objectRegionStyleCached = true; } else - objectStyleInRegion = computeStyleInRegion(object); + objectStyleInRegion = computeStyleInRegion(renderer, style()); - setObjectStyleInRegion(object, objectStyleInRegion, objectRegionStyleCached); + setRendererStyleInRegion(renderer, WTFMove(objectStyleInRegion), objectRegionStyleCached); - computeChildrenStyleInRegion(object); + computeChildrenStyleInRegion(renderer); } } @@ -341,36 +453,35 @@ void RenderNamedFlowFragment::restoreRegionObjectsOriginalStyle() if (!hasCustomRegionStyle()) return; - RenderObjectRegionStyleMap temp; - for (auto& objectPair : m_renderObjectRegionStyle) { - RenderObject* object = const_cast<RenderObject*>(objectPair.key); - RefPtr<RenderStyle> objectRegionStyle = &object->style(); - RefPtr<RenderStyle> objectOriginalStyle = objectPair.value.style; - if (object->isRenderElement()) - toRenderElement(object)->setStyleInternal(*objectOriginalStyle); + RendererRegionStyleMap temp; + for (auto& objectPair : m_rendererRegionStyle) { + auto* object = const_cast<RenderElement*>(objectPair.key); + std::unique_ptr<RenderStyle> objectRegionStyle = RenderStyle::clonePtr(object->style()); + std::unique_ptr<RenderStyle> objectOriginalStyle = RenderStyle::clonePtr(*objectPair.value.style); bool shouldCacheRegionStyle = objectPair.value.cached; if (!shouldCacheRegionStyle) { // Check whether we should cache the computed style in region. unsigned changedContextSensitiveProperties = ContextSensitivePropertyNone; - StyleDifference styleDiff = objectOriginalStyle->diff(objectRegionStyle.get(), changedContextSensitiveProperties); + StyleDifference styleDiff = objectOriginalStyle->diff(*objectRegionStyle, changedContextSensitiveProperties); if (styleDiff < StyleDifferenceLayoutPositionedMovementOnly) shouldCacheRegionStyle = true; } if (shouldCacheRegionStyle) { ObjectRegionStyleInfo styleInfo; - styleInfo.style = objectRegionStyle; + styleInfo.style = WTFMove(objectRegionStyle); styleInfo.cached = true; - temp.set(object, styleInfo); + temp.set(object, WTFMove(styleInfo)); } + object->setStyleInternal(WTFMove(*objectOriginalStyle)); } - m_renderObjectRegionStyle.swap(temp); + m_rendererRegionStyle.swap(temp); } RenderNamedFlowThread* RenderNamedFlowFragment::namedFlowThread() const { - return toRenderNamedFlowThread(flowThread()); + return downcast<RenderNamedFlowThread>(flowThread()); } LayoutRect RenderNamedFlowFragment::visualOverflowRect() const @@ -388,27 +499,36 @@ void RenderNamedFlowFragment::attachRegion() { RenderRegion::attachRegion(); - if (documentBeingDestroyed() || !m_flowThread) + if (renderTreeBeingDestroyed() || !isValid()) return; - // The region just got attached to the flow thread, lets check whether - // it has region styling rules associated. - checkRegionStyle(); - - if (!isValid()) - return; - - m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); - if (hasAutoLogicalHeight()) - incrementAutoLogicalHeightCount(); + updateRegionFlags(); } void RenderNamedFlowFragment::detachRegion() { - if (m_flowThread && hasAutoLogicalHeight()) + if (hasAutoLogicalHeight()) { + ASSERT(isValid()); + m_hasAutoLogicalHeight = false; + clearComputedAutoHeight(); decrementAutoLogicalHeightCount(); + } RenderRegion::detachRegion(); } +void RenderNamedFlowFragment::absoluteQuadsForBoxInRegion(Vector<FloatQuad>& quads, bool* wasFixed, const RenderBox* renderer, float localTop, float localBottom) +{ + LayoutRect layoutLocalRect(0, localTop, renderer->borderBoxRectInRegion(this).width(), localBottom - localTop); + LayoutRect fragmentRect = rectFlowPortionForBox(renderer, layoutLocalRect); + + // We want to skip the 0px height fragments for non-empty boxes that may appear in case the bottom of the box + // overlaps the bottom of a region. + if (localBottom != localTop && !fragmentRect.height()) + return; + + CurrentRenderRegionMaintainer regionMaintainer(*this); + quads.append(renderer->localToAbsoluteQuad(FloatRect(fragmentRect), UseTransforms, wasFixed)); +} + } // namespace WebCore |