void RenderMathMLPadded::layoutBlock(bool relayoutChildren, LayoutUnit) { ASSERT(needsLayout()); if (!relayoutChildren && simplifiedLayout()) return; // We first layout our children as a normal <mrow> element. LayoutUnit contentAscent, contentDescent, contentWidth; contentAscent = contentDescent = 0; RenderMathMLRow::computeLineVerticalStretch(contentAscent, contentDescent); RenderMathMLRow::layoutRowItems(contentAscent, contentDescent); contentWidth = logicalWidth(); // We parse the mpadded attributes using the content metrics as the default value. LayoutUnit width = contentWidth; LayoutUnit ascent = contentAscent; LayoutUnit descent = contentDescent; LayoutUnit lspace = 0; LayoutUnit voffset = 0; resolveAttributes(width, ascent, descent, lspace, voffset); // Align children on the new baseline and shift them by (lspace, -voffset) LayoutPoint contentLocation(lspace, ascent - contentAscent - voffset); for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) child->setLocation(child->location() + contentLocation); // Set the final metrics. setLogicalWidth(width); m_ascent = ascent; setLogicalHeight(ascent + descent); clearNeedsLayout(); }
void RenderMathMLFraction::layoutBlock(bool relayoutChildren, LayoutUnit) { ASSERT(needsLayout()); if (!relayoutChildren && simplifiedLayout()) return; if (!isValid()) { setLogicalWidth(0); setLogicalHeight(0); clearNeedsLayout(); return; } numerator().layoutIfNeeded(); denominator().layoutIfNeeded(); setLogicalWidth(std::max(numerator().logicalWidth(), denominator().logicalWidth())); updateLineThickness(); LayoutUnit verticalOffset = 0; // This is the top of the renderer. LayoutPoint numeratorLocation(horizontalOffset(numerator(), element().numeratorAlignment()), verticalOffset); numerator().setLocation(numeratorLocation); LayoutUnit numeratorAscent = ascentForChild(numerator()); LayoutUnit numeratorDescent = numerator().logicalHeight() - numeratorAscent; LayoutUnit denominatorAscent = ascentForChild(denominator()); LayoutUnit denominatorDescent = denominator().logicalHeight() - denominatorAscent; if (isStack()) { LayoutUnit gapMin, topShiftUp, bottomShiftDown; getStackParameters(gapMin, topShiftUp, bottomShiftDown); LayoutUnit gap = topShiftUp - numeratorDescent + bottomShiftDown - denominatorAscent; if (gap < gapMin) { // If the gap is not large enough, we increase the shifts by the same value. LayoutUnit delta = (gapMin - gap) / 2; topShiftUp += delta; bottomShiftDown += delta; } verticalOffset += numeratorAscent + topShiftUp; // This is the middle of the stack gap. m_ascent = verticalOffset + mathAxisHeight(); verticalOffset += bottomShiftDown - denominatorAscent; } else { LayoutUnit numeratorGapMin, denominatorGapMin, numeratorMinShiftUp, denominatorMinShiftDown; getFractionParameters(numeratorGapMin, denominatorGapMin, numeratorMinShiftUp, denominatorMinShiftDown); verticalOffset += std::max(numerator().logicalHeight() + numeratorGapMin + m_lineThickness / 2, numeratorAscent + numeratorMinShiftUp); // This is the middle of the fraction bar. m_ascent = verticalOffset + mathAxisHeight(); verticalOffset += std::max(m_lineThickness / 2 + denominatorGapMin, denominatorMinShiftDown - denominatorAscent); } LayoutPoint denominatorLocation(horizontalOffset(denominator(), element().denominatorAlignment()), verticalOffset); denominator().setLocation(denominatorLocation); verticalOffset = std::max(verticalOffset + denominator().logicalHeight(), m_ascent + denominatorDescent); // This is the bottom of our renderer. setLogicalHeight(verticalOffset); clearNeedsLayout(); }
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 RenderBlockFlow::layoutBlock(bool relayoutChildren) { ASSERT(needsLayout()); ASSERT(isInlineBlock() || !isInline()); if (!relayoutChildren && simplifiedLayout()) return; SubtreeLayoutScope layoutScope(*this); layoutBlockFlow(relayoutChildren, layoutScope); updateLayerTransformAfterLayout(); // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. updateScrollInfoAfterLayout(); if (m_paintInvalidationLogicalTop != m_paintInvalidationLogicalBottom) setShouldInvalidateOverflowForPaint(true); clearNeedsLayout(); }
void RenderSVGText::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; ASSERT(needsLayout()); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(*this)); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { m_localTransform = textElement().animatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } if (!everHadLayout()) { // When laying out initially, collect all layout attributes, build the character data map, // and propogate resulting SVGLayoutAttributes to all RenderSVGInlineText children in the subtree. ASSERT(m_layoutAttributes.isEmpty()); collectLayoutAttributes(this, m_layoutAttributes); updateFontInAllDescendants(this); m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsTextMetricsUpdate = false; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } else if (m_needsPositioningValuesUpdate) { // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually // update the on-screen font objects as well in all descendants. if (m_needsTextMetricsUpdate) { updateFontInAllDescendants(this); m_needsTextMetricsUpdate = false; } m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(*this).isLayoutSizeChanged()) { // If the root layout size changed (eg. window size changes) or the transform to the root // context has changed then recompute the on-screen font size. updateFontInAllDescendants(this, &m_layoutAttributesBuilder); ASSERT(!m_needsReordering); ASSERT(!m_needsPositioningValuesUpdate); m_needsTextMetricsUpdate = false; updateCachedBoundariesInParents = true; } checkLayoutAttributesConsistency(this, m_layoutAttributes); // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text. // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions. ASSERT(!isInline()); ASSERT(!simplifiedLayout()); ASSERT(!scrollsOverflow()); ASSERT(!hasControlClip()); ASSERT(!multiColumnFlowThread()); ASSERT(!positionedObjects()); ASSERT(!m_overflow); ASSERT(!isAnonymousBlock()); if (!firstChild()) setChildrenInline(true); // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); LayoutUnit repaintLogicalTop = 0; LayoutUnit repaintLogicalBottom = 0; rebuildFloatingObjectSetFromIntrudingFloats(); layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom); if (m_needsReordering) m_needsReordering = false; if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox(); // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(*this); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) RenderSVGBlock::setNeedsBoundariesUpdate(); repainter.repaintAfterLayout(); clearNeedsLayout(); }
void RenderSVGText::layout() { ASSERT(needsLayout()); LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { SVGTextElement* text = static_cast<SVGTextElement*>(node()); m_localTransform = text->animatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } // If the root layout size changed (eg. window size changes) or the positioning values change, recompute the on-screen font size. if (m_needsPositioningValuesUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) { recursiveUpdateScaledFont(this); m_needsPositioningValuesUpdate = true; updateCachedBoundariesInParents = true; } if (m_needsPositioningValuesUpdate) { // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details). SVGTextLayoutAttributesBuilder layoutAttributesBuilder; layoutAttributesBuilder.buildLayoutAttributesForTextSubtree(this); m_needsReordering = true; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text. // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions. ASSERT(!isInline()); ASSERT(!simplifiedLayout()); ASSERT(!scrollsOverflow()); ASSERT(!hasControlClip()); ASSERT(!hasColumns()); ASSERT(!positionedObjects()); ASSERT(!m_overflow); ASSERT(!isAnonymousBlock()); if (!firstChild()) setChildrenInline(true); // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); forceLayoutInlineChildren(); if (m_needsReordering) m_needsReordering = false; if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox(); // Invalidate all resources of this client if our layout changed. if (m_everHadLayout && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) RenderSVGBlock::setNeedsBoundariesUpdate(); repainter.repaintAfterLayout(); setNeedsLayout(false); }
void RenderMathMLRoot::layoutBlock(bool relayoutChildren, LayoutUnit) { ASSERT(needsLayout()); if (!relayoutChildren && simplifiedLayout()) return; updateStyle(); m_radicalOperatorTop = 0; m_baseWidth = 0; if (!isValid()) { setLogicalWidth(0); setLogicalHeight(0); clearNeedsLayout(); return; } // We layout the children, determine the vertical metrics of the base and set the logical width. // Note: Per the MathML specification, the children of <msqrt> are wrapped in an inferred <mrow>, which is the desired base. LayoutUnit baseAscent, baseDescent; recomputeLogicalWidth(); if (m_kind == SquareRoot) { baseAscent = baseDescent; RenderMathMLRow::computeLineVerticalStretch(baseAscent, baseDescent); RenderMathMLRow::layoutRowItems(baseAscent, baseDescent); m_baseWidth = logicalWidth(); } else { getBase().layoutIfNeeded(); m_baseWidth = getBase().logicalWidth(); baseAscent = ascentForChild(getBase()); baseDescent = getBase().logicalHeight() - baseAscent; getIndex().layoutIfNeeded(); } // Stretch the radical operator to cover the base height. // We can then determine the metrics of the radical operator + the base. m_radicalOperator.stretchTo(style(), baseAscent + baseDescent); LayoutUnit radicalOperatorHeight = m_radicalOperator.ascent() + m_radicalOperator.descent(); LayoutUnit indexBottomRaise = m_degreeBottomRaisePercent * radicalOperatorHeight; LayoutUnit radicalAscent = baseAscent + m_verticalGap + m_ruleThickness + m_extraAscender; LayoutUnit radicalDescent = std::max<LayoutUnit>(baseDescent, radicalOperatorHeight + m_extraAscender - radicalAscent); LayoutUnit descent = radicalDescent; LayoutUnit ascent = radicalAscent; // We set the logical width. if (m_kind == SquareRoot) setLogicalWidth(m_radicalOperator.width() + m_baseWidth); else { ASSERT(m_kind == RootWithIndex); setLogicalWidth(m_kernBeforeDegree + getIndex().logicalWidth() + m_kernAfterDegree + m_radicalOperator.width() + m_baseWidth); } // For <mroot>, we update the metrics to take into account the index. LayoutUnit indexAscent, indexDescent; if (m_kind == RootWithIndex) { indexAscent = ascentForChild(getIndex()); indexDescent = getIndex().logicalHeight() - indexAscent; ascent = std::max<LayoutUnit>(radicalAscent, indexBottomRaise + indexDescent + indexAscent - descent); } // We set the final position of children. m_radicalOperatorTop = ascent - radicalAscent + m_extraAscender; LayoutUnit horizontalOffset = m_radicalOperator.width(); if (m_kind == RootWithIndex) horizontalOffset += m_kernBeforeDegree + getIndex().logicalWidth() + m_kernAfterDegree; LayoutPoint baseLocation(mirrorIfNeeded(horizontalOffset, m_baseWidth), ascent - baseAscent); if (m_kind == SquareRoot) { for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) child->setLocation(child->location() + baseLocation); } else { ASSERT(m_kind == RootWithIndex); getBase().setLocation(baseLocation); LayoutPoint indexLocation(mirrorIfNeeded(m_kernBeforeDegree, getIndex()), ascent + descent - indexBottomRaise - indexDescent - indexAscent); getIndex().setLocation(indexLocation); } setLogicalHeight(ascent + descent); clearNeedsLayout(); }
void LayoutSVGText::layout() { ASSERT(needsLayout()); LayoutAnalyzer::Scope analyzer(*this); subtreeStyleDidChange(); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { m_localTransform = toSVGTextElement(node())->calculateAnimatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } if (!everHadLayout()) { // When laying out initially, collect all layout attributes, build the character data map, // and propogate resulting SVGLayoutAttributes to all LayoutSVGInlineText children in the subtree. ASSERT(m_layoutAttributes.isEmpty()); collectLayoutAttributes(this, m_layoutAttributes); updateFontInAllDescendants(this); m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsTextMetricsUpdate = false; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } else if (m_needsPositioningValuesUpdate) { // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually // update the on-screen font objects as well in all descendants. if (m_needsTextMetricsUpdate) { updateFontInAllDescendants(this); m_needsTextMetricsUpdate = false; } m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } else if (m_needsTextMetricsUpdate || SVGLayoutSupport::findTreeRootObject(this)->isLayoutSizeChanged()) { // If the root layout size changed (eg. window size changes) or the transform to the root // context has changed then recompute the on-screen font size. updateFontInAllDescendants(this, &m_layoutAttributesBuilder); ASSERT(!m_needsReordering); ASSERT(!m_needsPositioningValuesUpdate); m_needsTextMetricsUpdate = false; updateCachedBoundariesInParents = true; } checkLayoutAttributesConsistency(this, m_layoutAttributes); // Reduced version of LayoutBlock::layoutBlock(), which only takes care of SVG text. // All if branches that could cause early exit in LayoutBlocks layoutBlock() method are turned into assertions. ASSERT(!isInline()); ASSERT(!simplifiedLayout()); ASSERT(!scrollsOverflow()); ASSERT(!hasControlClip()); ASSERT(!positionedObjects()); ASSERT(!isAnonymousBlock()); if (!firstChild()) setChildrenInline(true); // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); rebuildFloatsFromIntruding(); LayoutUnit beforeEdge = borderBefore() + paddingBefore(); LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); setLogicalHeight(beforeEdge); LayoutState state(*this, locationOffset()); LayoutUnit paintInvalidationLogicalTop = 0; LayoutUnit paintInvalidationLogicalBottom = 0; layoutInlineChildren(true, paintInvalidationLogicalTop, paintInvalidationLogicalBottom, afterEdge); if (m_needsReordering) m_needsReordering = false; // If we don't have any line boxes, then make sure the frame rect is still cleared. if (!firstLineBox()) setFrameRect(LayoutRect()); m_overflow.clear(); addVisualEffectOverflow(); if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox(); // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) LayoutSVGBlock::setNeedsBoundariesUpdate(); clearNeedsLayout(); }