void RenderMathMLRow::computeLineVerticalStretch(LayoutUnit& ascent, LayoutUnit& descent) { for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { if (is<RenderMathMLBlock>(child)) { auto* renderOperator = downcast<RenderMathMLBlock>(child)->unembellishedOperator(); if (renderOperator && renderOperator->hasOperatorFlag(MathMLOperatorDictionary::Stretchy)) continue; } child->layoutIfNeeded(); LayoutUnit childHeightAboveBaseline = ascentForChild(*child); LayoutUnit childDepthBelowBaseline = child->logicalHeight() - childHeightAboveBaseline; ascent = std::max(ascent, childHeightAboveBaseline); descent = std::max(descent, childDepthBelowBaseline); } // We ensure a minimal stretch size. if (ascent + descent <= 0) { ascent = style().fontSize(); descent = 0; } }
void RenderMathMLSubSup::layout() { RenderMathMLBlock::layout(); RenderMathMLBlock* baseWrapper = toRenderMathMLBlock(firstChild()); if (!baseWrapper || !m_scripts) return; RenderBox* base = baseWrapper->firstChildBox(); if (!base) return; // Our layout rules include: Don't let the superscript go below the "axis" (half x-height above the // baseline), or the subscript above the axis. Also, don't let the superscript's top edge be // below the base's top edge, or the subscript's bottom edge above the base's bottom edge. // // FIXME: Check any subscriptshift or superscriptshift attributes, and maybe use more sophisticated // heuristics from TeX or elsewhere. See https://bugs.webkit.org/show_bug.cgi?id=79274#c5. LayoutUnit baseHeight = base->logicalHeight(); LayoutUnit baseBaseline = base->firstLineBoxBaseline(); if (baseBaseline == -1) baseBaseline = baseHeight; LayoutUnit axis = style()->fontMetrics().xHeight() / 2; int fontSize = style()->fontSize(); ASSERT(baseWrapper->style()->hasOneRef()); bool needsSecondLayout = false; if (RenderBox* superscript = m_kind == Sub ? 0 : m_scripts->lastChildBox()) { LayoutUnit superscriptHeight = superscript->logicalHeight(); LayoutUnit superscriptBaseline = superscript->firstLineBoxBaseline(); if (superscriptBaseline == -1) superscriptBaseline = superscriptHeight; LayoutUnit minBaseline = max<LayoutUnit>(fontSize / 3 + 1 + superscriptBaseline, superscriptHeight + axis); Length newPadding = Length(max<LayoutUnit>(minBaseline - baseBaseline, 0), Fixed); if (newPadding != baseWrapper->style()->paddingTop()) { baseWrapper->style()->setPaddingTop(newPadding); needsSecondLayout = true; } } if (RenderBox* subscript = m_kind == Super ? 0 : m_scripts->firstChildBox()) { LayoutUnit subscriptHeight = subscript->logicalHeight(); LayoutUnit subscriptBaseline = subscript->firstLineBoxBaseline(); if (subscriptBaseline == -1) subscriptBaseline = subscriptHeight; LayoutUnit baseExtendUnderBaseline = baseHeight - baseBaseline; LayoutUnit subscriptUnderItsBaseline = subscriptHeight - subscriptBaseline; LayoutUnit minExtendUnderBaseline = max<LayoutUnit>(fontSize / 5 + 1 + subscriptUnderItsBaseline, subscriptHeight - axis); Length newPadding = Length(max<LayoutUnit>(minExtendUnderBaseline - baseExtendUnderBaseline, 0), Fixed); if (newPadding != baseWrapper->style()->paddingBottom()) { baseWrapper->style()->setPaddingBottom(newPadding); needsSecondLayout = true; } } if (!needsSecondLayout) return; setNeedsLayout(true, MarkOnlyThis); baseWrapper->setChildNeedsLayout(true, MarkOnlyThis); RenderMathMLBlock::layout(); }
void RenderTextControlSingleLine::centerRenderer(RenderBox& renderer) const { LayoutUnit logicalHeightDiff = renderer.logicalHeight() - contentLogicalHeight(); float center = logicalHeightDiff / 2; renderer.setLogicalTop(renderer.logicalTop() - LayoutUnit(round(center))); }
void RenderTextControlSingleLine::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; // FIXME: We should remove the height-related hacks in layout() and // styleDidChange(). We need them because // - Center the inner elements vertically if the input height is taller than // the intrinsic height of the inner elements. // - Shrink the inner elment heights if the input height is samller than the // intrinsic heights of the inner elements. // We don't honor paddings and borders for textfields without decorations // and type=search if the text height is taller than the contentHeight() // because of compability. RenderTextControlInnerBlock* innerTextRenderer = innerTextElement()->renderer(); RenderBox* innerBlockRenderer = innerBlockElement() ? innerBlockElement()->renderBox() : 0; // To ensure consistency between layouts, we need to reset any conditionally overriden height. if (innerTextRenderer && !innerTextRenderer->style().logicalHeight().isAuto()) { innerTextRenderer->style().setLogicalHeight(Length(Auto)); setNeedsLayoutOnAncestors(innerTextRenderer, this); } if (innerBlockRenderer && !innerBlockRenderer->style().logicalHeight().isAuto()) { innerBlockRenderer->style().setLogicalHeight(Length(Auto)); setNeedsLayoutOnAncestors(innerBlockRenderer, this); } RenderBlockFlow::layoutBlock(false); HTMLElement* container = containerElement(); RenderBox* containerRenderer = container ? container->renderBox() : 0; // Set the text block height LayoutUnit desiredLogicalHeight = textBlockLogicalHeight(); LayoutUnit logicalHeightLimit = computeLogicalHeightLimit(); if (innerTextRenderer && innerTextRenderer->logicalHeight() > logicalHeightLimit) { if (desiredLogicalHeight != innerTextRenderer->logicalHeight()) setNeedsLayout(MarkOnlyThis); m_desiredInnerTextLogicalHeight = desiredLogicalHeight; innerTextRenderer->style().setLogicalHeight(Length(desiredLogicalHeight, Fixed)); innerTextRenderer->setNeedsLayout(MarkOnlyThis); if (innerBlockRenderer) { innerBlockRenderer->style().setLogicalHeight(Length(desiredLogicalHeight, Fixed)); innerBlockRenderer->setNeedsLayout(MarkOnlyThis); } } // The container might be taller because of decoration elements. if (containerRenderer) { containerRenderer->layoutIfNeeded(); LayoutUnit containerLogicalHeight = containerRenderer->logicalHeight(); if (containerLogicalHeight > logicalHeightLimit) { containerRenderer->style().setLogicalHeight(Length(logicalHeightLimit, Fixed)); setNeedsLayout(MarkOnlyThis); } else if (containerRenderer->logicalHeight() < contentLogicalHeight()) { containerRenderer->style().setLogicalHeight(Length(contentLogicalHeight(), Fixed)); setNeedsLayout(MarkOnlyThis); } else containerRenderer->style().setLogicalHeight(Length(containerLogicalHeight, Fixed)); } // If we need another layout pass, we have changed one of children's height so we need to relayout them. if (needsLayout()) RenderBlockFlow::layoutBlock(true); // Center the child block in the block progression direction (vertical centering for horizontal text fields). if (!container && innerTextRenderer && innerTextRenderer->height() != contentLogicalHeight()) centerRenderer(*innerTextRenderer); else centerContainerIfNeeded(containerRenderer); // Ignores the paddings for the inner spin button. if (RenderBox* innerSpinBox = innerSpinButtonElement() ? innerSpinButtonElement()->renderBox() : 0) { RenderBox* parentBox = innerSpinBox->parentBox(); if (containerRenderer && !containerRenderer->style().isLeftToRightDirection()) innerSpinBox->setLogicalLocation(LayoutPoint(-paddingLogicalLeft(), -paddingBefore())); else innerSpinBox->setLogicalLocation(LayoutPoint(parentBox->logicalWidth() - innerSpinBox->logicalWidth() + paddingLogicalRight(), -paddingBefore())); innerSpinBox->setLogicalHeight(logicalHeight() - borderBefore() - borderAfter()); } HTMLElement* placeholderElement = inputElement().placeholderElement(); if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) { LayoutSize innerTextSize; if (innerTextRenderer) innerTextSize = innerTextRenderer->size(); placeholderBox->style().setWidth(Length(innerTextSize.width() - placeholderBox->horizontalBorderAndPaddingExtent(), Fixed)); placeholderBox->style().setHeight(Length(innerTextSize.height() - placeholderBox->verticalBorderAndPaddingExtent(), Fixed)); bool neededLayout = placeholderBox->needsLayout(); bool placeholderBoxHadLayout = placeholderBox->everHadLayout(); placeholderBox->layoutIfNeeded(); LayoutPoint textOffset; if (innerTextRenderer) textOffset = innerTextRenderer->location(); if (innerBlockElement() && innerBlockElement()->renderBox()) textOffset += toLayoutSize(innerBlockElement()->renderBox()->location()); if (containerRenderer) textOffset += toLayoutSize(containerRenderer->location()); placeholderBox->setLocation(textOffset); if (!placeholderBoxHadLayout && placeholderBox->checkForRepaintDuringLayout()) { // This assumes a shadow tree without floats. If floats are added, the // logic should be shared with RenderBlock::layoutBlockChild. placeholderBox->repaint(); } // The placeholder gets layout last, after the parent text control and its other children, // so in order to get the correct overflow from the placeholder we need to recompute it now. if (neededLayout) computeOverflow(clientLogicalBottom()); } #if PLATFORM(IOS) // FIXME: We should not be adjusting styles during layout. <rdar://problem/7675493> if (inputElement().isSearchField()) RenderThemeIOS::adjustRoundBorderRadius(style(), *this); #endif }
void RenderTextControlSingleLine::layout() { SubtreeLayoutScope layoutScope(this); // FIXME: We should remove the height-related hacks in layout() and // styleDidChange(). We need them because // - Center the inner elements vertically if the input height is taller than // the intrinsic height of the inner elements. // - Shrink the inner elment heights if the input height is samller than the // intrinsic heights of the inner elements. // We don't honor paddings and borders for textfields without decorations // and type=search if the text height is taller than the contentHeight() // because of compability. RenderBox* innerTextRenderer = innerTextElement()->renderBox(); RenderBox* viewPortRenderer = editingViewPortElement() ? editingViewPortElement()->renderBox() : 0; // To ensure consistency between layouts, we need to reset any conditionally overriden height. if (innerTextRenderer && !innerTextRenderer->style()->logicalHeight().isAuto()) { innerTextRenderer->style()->setLogicalHeight(Length(Auto)); layoutScope.setNeedsLayout(innerTextRenderer); } if (viewPortRenderer && !viewPortRenderer->style()->logicalHeight().isAuto()) { viewPortRenderer->style()->setLogicalHeight(Length(Auto)); layoutScope.setNeedsLayout(viewPortRenderer); } RenderBlockFlow::layoutBlock(false); Element* container = containerElement(); RenderBox* containerRenderer = container ? container->renderBox() : 0; // Set the text block height LayoutUnit desiredLogicalHeight = textBlockLogicalHeight(); LayoutUnit logicalHeightLimit = computeLogicalHeightLimit(); if (innerTextRenderer && innerTextRenderer->logicalHeight() > logicalHeightLimit) { if (desiredLogicalHeight != innerTextRenderer->logicalHeight()) layoutScope.setNeedsLayout(this); m_desiredInnerTextLogicalHeight = desiredLogicalHeight; innerTextRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed)); layoutScope.setNeedsLayout(innerTextRenderer); if (viewPortRenderer) { viewPortRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed)); layoutScope.setNeedsLayout(viewPortRenderer); } } // The container might be taller because of decoration elements. if (containerRenderer) { containerRenderer->layoutIfNeeded(); LayoutUnit containerLogicalHeight = containerRenderer->logicalHeight(); if (containerLogicalHeight > logicalHeightLimit) { containerRenderer->style()->setLogicalHeight(Length(logicalHeightLimit, Fixed)); layoutScope.setNeedsLayout(this); } else if (containerRenderer->logicalHeight() < contentLogicalHeight()) { containerRenderer->style()->setLogicalHeight(Length(contentLogicalHeight(), Fixed)); layoutScope.setNeedsLayout(this); } else containerRenderer->style()->setLogicalHeight(Length(containerLogicalHeight, Fixed)); } // If we need another layout pass, we have changed one of children's height so we need to relayout them. if (needsLayout()) RenderBlockFlow::layoutBlock(true); // Center the child block in the block progression direction (vertical centering for horizontal text fields). if (!container && innerTextRenderer && innerTextRenderer->height() != contentLogicalHeight()) { LayoutUnit logicalHeightDiff = innerTextRenderer->logicalHeight() - contentLogicalHeight(); innerTextRenderer->setLogicalTop(innerTextRenderer->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2))); } else centerContainerIfNeeded(containerRenderer); HTMLElement* placeholderElement = inputElement()->placeholderElement(); if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) { LayoutSize innerTextSize; if (innerTextRenderer) innerTextSize = innerTextRenderer->size(); placeholderBox->style()->setWidth(Length(innerTextSize.width() - placeholderBox->borderAndPaddingWidth(), Fixed)); placeholderBox->style()->setHeight(Length(innerTextSize.height() - placeholderBox->borderAndPaddingHeight(), Fixed)); bool neededLayout = placeholderBox->needsLayout(); bool placeholderBoxHadLayout = placeholderBox->everHadLayout(); placeholderBox->layoutIfNeeded(); LayoutPoint textOffset; if (innerTextRenderer) textOffset = innerTextRenderer->location(); if (editingViewPortElement() && editingViewPortElement()->renderBox()) textOffset += toLayoutSize(editingViewPortElement()->renderBox()->location()); if (containerRenderer) textOffset += toLayoutSize(containerRenderer->location()); placeholderBox->setLocation(textOffset); if (!placeholderBoxHadLayout && placeholderBox->checkForRepaintDuringLayout()) { // This assumes a shadow tree without floats. If floats are added, the // logic should be shared with RenderBlockFlow::layoutBlockChild. placeholderBox->repaint(); } // The placeholder gets layout last, after the parent text control and its other children, // so in order to get the correct overflow from the placeholder we need to recompute it now. if (neededLayout) computeOverflow(clientLogicalBottom()); } }
void RenderMathMLRow::layoutRowItems(LayoutUnit& ascent, LayoutUnit& descent) { // We first stretch the vertical operators. // For inline formulas, we can then calculate the logical width. LayoutUnit width = borderAndPaddingStart(); for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { if (child->isOutOfFlowPositioned()) continue; if (is<RenderMathMLBlock>(child)) { auto renderOperator = downcast<RenderMathMLBlock>(child)->unembellishedOperator(); if (renderOperator && renderOperator->hasOperatorFlag(MathMLOperatorDictionary::Stretchy) && renderOperator->isVertical()) renderOperator->stretchTo(ascent, descent); } child->layoutIfNeeded(); width += child->marginStart() + child->logicalWidth() + child->marginEnd(); } width += borderEnd() + paddingEnd(); // FIXME: RenderMathMLRoot classes should also recalculate the exact logical width instead of using the preferred width. // See http://webkit.org/b/153987 if ((!isRenderMathMLMath() || style().display() == INLINE) && !isRenderMathMLRoot()) setLogicalWidth(width); LayoutUnit verticalOffset = borderTop() + paddingTop(); LayoutUnit maxAscent = 0, maxDescent = 0; // Used baseline alignment. LayoutUnit horizontalOffset = borderAndPaddingStart(); bool shouldFlipHorizontal = !style().isLeftToRightDirection(); for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { if (child->isOutOfFlowPositioned()) { child->containingBlock()->insertPositionedObject(*child); continue; } LayoutUnit childHorizontalExtent = child->logicalWidth(); LayoutUnit ascent = ascentForChild(*child); LayoutUnit descent = child->verticalMarginExtent() + child->logicalHeight() - ascent; maxAscent = std::max(maxAscent, ascent); maxDescent = std::max(maxDescent, descent); LayoutUnit childVerticalMarginBoxExtent = maxAscent + maxDescent; horizontalOffset += child->marginStart(); setLogicalHeight(std::max(logicalHeight(), verticalOffset + borderBottom() + paddingBottom() + childVerticalMarginBoxExtent + horizontalScrollbarHeight())); LayoutPoint childLocation(shouldFlipHorizontal ? logicalWidth() - horizontalOffset - childHorizontalExtent : horizontalOffset, verticalOffset + child->marginTop()); child->setLocation(childLocation); horizontalOffset += childHorizontalExtent + child->marginEnd(); } LayoutUnit centerBlockOffset = 0; // FIXME: Remove the FLEX when it is not required by the css. if (style().display() == BLOCK || style().display() == FLEX) centerBlockOffset = std::max<LayoutUnit>(0, (logicalWidth() - (horizontalOffset + borderEnd() + paddingEnd())) / 2); if (shouldFlipHorizontal && centerBlockOffset > 0) centerBlockOffset = -centerBlockOffset; for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { LayoutUnit ascent = ascentForChild(*child); LayoutUnit startOffset = maxAscent - ascent; child->setLocation(child->location() + LayoutPoint(centerBlockOffset, startOffset)); } ascent = maxAscent; descent = maxDescent; }
void RenderMathMLScripts::layout() { RenderMathMLBlock::layout(); if (!m_baseWrapper) return; RenderBox* base = m_baseWrapper->firstChildBox(); if (!base) return; // Our layout rules include: Don't let the superscript go below the "axis" (half x-height above the // baseline), or the subscript above the axis. Also, don't let the superscript's top edge be // below the base's top edge, or the subscript's bottom edge above the base's bottom edge. LayoutUnit baseHeight = base->logicalHeight(); LayoutUnit baseBaseline = base->firstLineBaseline().valueOr(baseHeight); LayoutUnit axis = style().fontMetrics().xHeight() / 2; int fontSize = style().fontSize(); ASSERT(m_baseWrapper->style().hasOneRef()); bool needsSecondLayout = false; LayoutUnit topPadding = 0; LayoutUnit bottomPadding = 0; Element* scriptElement = element(); LayoutUnit superscriptShiftValue = 0; LayoutUnit subscriptShiftValue = 0; if (m_kind == Sub || m_kind == SubSup || m_kind == Multiscripts) parseMathMLLength(scriptElement->fastGetAttribute(MathMLNames::subscriptshiftAttr), subscriptShiftValue, &style(), false); if (m_kind == Super || m_kind == SubSup || m_kind == Multiscripts) parseMathMLLength(scriptElement->fastGetAttribute(MathMLNames::superscriptshiftAttr), superscriptShiftValue, &style(), false); bool isPostScript = true; RenderMathMLBlock* subSupPair = downcast<RenderMathMLBlock>(m_baseWrapper->nextSibling()); for (; subSupPair; subSupPair = downcast<RenderMathMLBlock>(subSupPair->nextSibling())) { // We skip the base and <mprescripts/> elements. if (isPrescript(*subSupPair)) { if (!isPostScript) break; isPostScript = false; continue; } if (RenderBox* superscript = m_kind == Sub ? 0 : subSupPair->lastChildBox()) { LayoutUnit superscriptHeight = superscript->logicalHeight(); LayoutUnit superscriptBaseline = superscript->firstLineBaseline().valueOr(superscriptHeight); LayoutUnit minBaseline = std::max<LayoutUnit>(fontSize / 3 + 1 + superscriptBaseline, superscriptHeight + axis + superscriptShiftValue); topPadding = std::max<LayoutUnit>(topPadding, minBaseline - baseBaseline); } if (RenderBox* subscript = m_kind == Super ? 0 : subSupPair->firstChildBox()) { LayoutUnit subscriptHeight = subscript->logicalHeight(); LayoutUnit subscriptBaseline = subscript->firstLineBaseline().valueOr(subscriptHeight); LayoutUnit baseExtendUnderBaseline = baseHeight - baseBaseline; LayoutUnit subscriptUnderItsBaseline = subscriptHeight - subscriptBaseline; LayoutUnit minExtendUnderBaseline = std::max<LayoutUnit>(fontSize / 5 + 1 + subscriptUnderItsBaseline, subscriptHeight + subscriptShiftValue - axis); bottomPadding = std::max<LayoutUnit>(bottomPadding, minExtendUnderBaseline - baseExtendUnderBaseline); } } Length newPadding(topPadding, Fixed); if (newPadding != m_baseWrapper->style().paddingTop()) { m_baseWrapper->style().setPaddingTop(newPadding); needsSecondLayout = true; } newPadding = Length(bottomPadding, Fixed); if (newPadding != m_baseWrapper->style().paddingBottom()) { m_baseWrapper->style().setPaddingBottom(newPadding); needsSecondLayout = true; } if (!needsSecondLayout) return; setNeedsLayout(MarkOnlyThis); m_baseWrapper->setChildNeedsLayout(MarkOnlyThis); RenderMathMLBlock::layout(); }