void RenderBlockFlow::invalidatePaintForOverflow() { // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either. LayoutUnit paintInvalidationLogicalLeft = logicalLeftVisualOverflow(); LayoutUnit paintInvalidationLogicalRight = logicalRightVisualOverflow(); if (hasOverflowClip()) { // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow. // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit. // layoutInlineChildren should be patched to compute the entire paint invalidation rect. paintInvalidationLogicalLeft = std::min(paintInvalidationLogicalLeft, logicalLeftLayoutOverflow()); paintInvalidationLogicalRight = std::max(paintInvalidationLogicalRight, logicalRightLayoutOverflow()); } LayoutRect paintInvalidationRect = LayoutRect(paintInvalidationLogicalLeft, m_paintInvalidationLogicalTop, paintInvalidationLogicalRight - paintInvalidationLogicalLeft, m_paintInvalidationLogicalBottom - m_paintInvalidationLogicalTop); if (hasOverflowClip()) { // Adjust the paint invalidation rect for scroll offset paintInvalidationRect.move(-scrolledContentOffset()); // Don't allow this rect to spill out of our overflow box. paintInvalidationRect.intersect(LayoutRect(LayoutPoint(), size())); } // Make sure the rect is still non-empty after intersecting for overflow above if (!paintInvalidationRect.isEmpty()) { // Hits in media/event-attributes.html DisableCompositingQueryAsserts disabler; invalidatePaintRectangle(paintInvalidationRect); // We need to do a partial paint invalidation of our content. } m_paintInvalidationLogicalTop = 0; m_paintInvalidationLogicalBottom = 0; }
LayoutRect LayoutMultiColumnSet::overflowRectForFlowThreadPortion(const LayoutRect& flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const { if (hasOverflowClip()) return flowThreadPortionRect; LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect(); // Only clip along the flow thread axis. LayoutRect clipRect; if (m_flowThread->isHorizontalWritingMode()) { LayoutUnit minY = isFirstPortion ? flowThreadOverflow.y() : flowThreadPortionRect.y(); LayoutUnit maxY = isLastPortion ? std::max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) : flowThreadPortionRect.maxY(); LayoutUnit minX = std::min(flowThreadPortionRect.x(), flowThreadOverflow.x()); LayoutUnit maxX = std::max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()); clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); } else { LayoutUnit minX = isFirstPortion ? flowThreadOverflow.x() : flowThreadPortionRect.x(); LayoutUnit maxX = isLastPortion ? std::max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) : flowThreadPortionRect.maxX(); LayoutUnit minY = std::min(flowThreadPortionRect.y(), (flowThreadOverflow.y())); LayoutUnit maxY = std::max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY())); clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); } return clipRect; }
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const { RenderRegion* startRegion = 0; RenderRegion* endRegion = 0; m_flowThread->getRegionRangeForBox(box, startRegion, endRegion); LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect); if (flowThread()->isHorizontalWritingMode()) { if (this != startRegion) mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y())); if (this != endRegion) mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height()))); } else { if (this != startRegion) mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x())); if (this != endRegion) mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width()))); } bool isLastRegionWithRegionFragmentBreak = (isLastRegion() && (style().regionFragment() == BreakRegionFragment)); if (hasOverflowClip() || isLastRegionWithRegionFragmentBreak) mappedRect.intersect(flowThreadPortionRect()); return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect); }
LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flowThreadPortionRect, bool isFirstPortion, bool isLastPortion, OverflowType overflowType) { ASSERT(isValid()); bool isLastRegionWithRegionFragmentBreak = (isLastPortion && (style().regionFragment() == BreakRegionFragment)); if (hasOverflowClip() || isLastRegionWithRegionFragmentBreak) return flowThreadPortionRect; LayoutRect flowThreadOverflow = overflowType == VisualOverflow ? visualOverflowRectForBox(m_flowThread) : layoutOverflowRectForBox(m_flowThread); // We are interested about the outline size only when computing the visual overflow. LayoutUnit outlineSize = overflowType == VisualOverflow ? LayoutUnit(maximalOutlineSize(PaintPhaseOutline)) : LayoutUnit(); LayoutRect clipRect; if (m_flowThread->isHorizontalWritingMode()) { LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize) : flowThreadPortionRect.y(); LayoutUnit maxY = isLastPortion ? std::max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY(); bool clipX = style().overflowX() != OVISIBLE; LayoutUnit minX = clipX ? flowThreadPortionRect.x() : std::min(flowThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize); LayoutUnit maxX = clipX ? flowThreadPortionRect.maxX() : std::max(flowThreadPortionRect.maxX(), (flowThreadOverflow.maxX() + outlineSize)); clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); } else { LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize) : flowThreadPortionRect.x(); LayoutUnit maxX = isLastPortion ? std::max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX(); bool clipY = style().overflowY() != OVISIBLE; LayoutUnit minY = clipY ? flowThreadPortionRect.y() : std::min(flowThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize)); LayoutUnit maxY = clipY ? flowThreadPortionRect.maxY() : std::max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize)); clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); } return clipRect; }
void LayoutListBox::scrollToRect(const LayoutRect& rect) { if (hasOverflowClip()) { ASSERT(layer()); ASSERT(layer()->getScrollableArea()); layer()->getScrollableArea()->scrollIntoView( rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); } }
void RenderMultiColumnSet::addOverflowFromChildren() { unsigned colCount = actualColumnCount(); if (!colCount) return; LayoutRect lastRect = columnRectAt(colCount - 1); addLayoutOverflow(lastRect); if (!hasOverflowClip()) addVisualOverflow(lastRect); }
void LayoutMultiColumnSet::addOverflowFromChildren() { LayoutRect overflowRect; for (const auto& group : m_fragmentainerGroups) { LayoutRect rect = group.calculateOverflow(); rect.move(group.offsetFromColumnSet()); overflowRect.unite(rect); } addLayoutOverflow(overflowRect); if (!hasOverflowClip()) addVisualOverflow(overflowRect); }
void LayoutTextControl::hitInnerEditorElement(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) { HTMLElement* innerEditor = innerEditorElement(); if (!innerEditor->layoutObject()) return; LayoutPoint adjustedLocation = accumulatedOffset + location(); LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation + innerEditor->layoutBox()->location()); if (hasOverflowClip()) localPoint += scrolledContentOffset(); result.setNodeAndPosition(innerEditor, localPoint); }
void RenderMultiColumnSet::addOverflowFromChildren() { // FIXME: Need to do much better here. unsigned colCount = columnCount(); if (!colCount) return; LayoutRect lastRect = columnRectAt(colCount - 1); addLayoutOverflow(lastRect); if (!hasOverflowClip()) addVisualOverflow(lastRect); }
bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* inlineFlowBox) const { if (bleedAvoidance != BackgroundBleedNone) return false; if (style()->hasAppearance()) return false; const ShadowList* shadowList = style()->boxShadow(); if (!shadowList) return false; bool hasOneNormalBoxShadow = false; size_t shadowCount = shadowList->shadows().size(); for (size_t i = 0; i < shadowCount; ++i) { const ShadowData& currentShadow = shadowList->shadows()[i]; if (currentShadow.style() != Normal) continue; if (hasOneNormalBoxShadow) return false; hasOneNormalBoxShadow = true; if (currentShadow.spread()) return false; } if (!hasOneNormalBoxShadow) return false; Color backgroundColor = resolveColor(CSSPropertyBackgroundColor); if (backgroundColor.hasAlpha()) return false; const FillLayer* lastBackgroundLayer = &style()->backgroundLayers(); for (const FillLayer* next = lastBackgroundLayer->next(); next; next = lastBackgroundLayer->next()) lastBackgroundLayer = next; if (lastBackgroundLayer->clip() != BorderFillBox) return false; if (lastBackgroundLayer->image() && style()->hasBorderRadius()) return false; if (inlineFlowBox && !inlineFlowBox->boxShadowCanBeAppliedToBackground(*lastBackgroundLayer)) return false; if (hasOverflowClip() && lastBackgroundLayer->attachment() == LocalBackgroundAttachment) return false; return true; }
void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit) { ASSERT(needsLayout()); if (!relayoutChildren && simplifiedLayout()) return; // FIXME: Much of this method is boiler plate that matches RenderBox::layoutBlock and Render*FlexibleBox::layoutBlock. // It would be nice to refactor some of the duplicate code. LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); if (inRenderFlowThread()) { // Regions changing widths can force us to relayout our children. if (logicalWidthChangedInRegions()) relayoutChildren = true; } computeInitialRegionRangeForBlock(); LayoutSize previousSize = size(); setLogicalHeight(0); computeLogicalWidth(); m_overflow.clear(); layoutGridItems(); LayoutUnit oldClientAfterEdge = clientLogicalBottom(); computeLogicalHeight(); if (size() != previousSize) relayoutChildren = true; layoutPositionedObjects(relayoutChildren || isRoot()); computeRegionRangeForBlock(); computeOverflow(oldClientAfterEdge); statePusher.pop(); updateLayerTransform(); // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. if (hasOverflowClip()) layer()->updateScrollInfoAfterLayout(); repainter.repaintAfterLayout(); setNeedsLayout(false); }
void RenderTextControl::hitInnerEditorElement(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) { HTMLElement* innerEditor = innerEditorElement(); if (!innerEditor->renderer()) return; LayoutPoint adjustedLocation = accumulatedOffset + location(); LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation + innerEditor->renderBox()->location()); if (hasOverflowClip()) localPoint += scrolledContentOffset(); result.setInnerNode(innerEditor); result.setInnerNonSharedNode(innerEditor); result.setLocalPoint(localPoint); }
bool RenderRegion::shouldClipFlowThreadContent() const { return hasOverflowClip(); }