void RenderMathMLSquareRoot::layout() { int maxHeight = 0; RenderObject* current = firstChild(); while (current) { if (current->isBoxModelObject()) { RenderBoxModelObject* box = toRenderBoxModelObject(current); if (box->pixelSnappedOffsetHeight() > maxHeight) maxHeight = box->pixelSnappedOffsetHeight(); box->style()->setVerticalAlign(BASELINE); } current = current->nextSibling(); } if (!maxHeight) maxHeight = style()->fontSize(); if (maxHeight > static_cast<int>(gThresholdBaseHeight * style()->fontSize())) style()->setPaddingBottom(Length(static_cast<int>(gRootBottomPadding * style()->fontSize()), Fixed)); RenderBlock::layout(); }
void RenderMathMLRoot::layout() { RenderBlock::layout(); if (!firstChild() || !lastChild()) return; int baseHeight = toRenderBoxModelObject(lastChild())->pixelSnappedOffsetHeight(); if (!baseHeight) baseHeight = style()->fontSize(); RenderObject* base = lastChild()->firstChild(); if (base) base->style()->setVerticalAlign(BASELINE); // FIXME: Can this style be modified? // Base height above which the shape of the root changes int thresholdHeight = static_cast<int>(gThresholdBaseHeightEms * style()->fontSize()); int overbarLeftPointShift = 0; // FIXME: Can style() and indexBox->style() be modified (4 times below)? if (baseHeight > thresholdHeight && thresholdHeight) { float shift = (baseHeight - thresholdHeight) / static_cast<float>(thresholdHeight); if (shift > 1.) shift = 1.0f; int frontWidth = static_cast<int>(style()->fontSize() * gFrontWidthEms); overbarLeftPointShift = static_cast<int>(gRadicalBottomPointXFront * frontWidth * shift); style()->setPaddingBottom(Length(static_cast<int>(gBigRootBottomPaddingEms * style()->fontSize()), Fixed)); } // Positioning of the index RenderObject* possibleIndex = firstChild()->firstChild(); while (possibleIndex && !possibleIndex->isBoxModelObject()) possibleIndex = possibleIndex->nextSibling(); RenderBoxModelObject* indexBox = toRenderBoxModelObject(possibleIndex); if (!indexBox) return; int shiftForIndex = indexBox->pixelSnappedOffsetWidth() + overbarLeftPointShift; int partDipHeight = static_cast<int>((1 - gRadicalDipLeftPointYPos) * baseHeight); int rootExtraTop = partDipHeight + style()->paddingBottom().value() + indexBox->pixelSnappedOffsetHeight() - (baseHeight + static_cast<int>(gRootPaddingEms * style()->fontSize())); style()->setPaddingLeft(Length(shiftForIndex, Fixed)); if (rootExtraTop > 0) style()->setPaddingTop(Length(rootExtraTop + static_cast<int>(gRootPaddingEms * style()->fontSize()), Fixed)); setNeedsLayout(true); setPreferredLogicalWidthsDirty(true, MarkOnlyThis); // FIXME: Can this really be right? RenderBlock::layout(); indexBox->style()->setBottom(Length(partDipHeight + style()->paddingBottom().value(), Fixed)); // Now that we've potentially changed its position, we need layout the index again. indexBox->setNeedsLayout(true); indexBox->layout(); }
void RenderMathMLRoot::layout() { RenderBlock::layout(); if (!firstChild() || !lastChild()) return; int maxHeight = toRenderBoxModelObject(lastChild())->offsetHeight(); RenderObject* current = lastChild()->firstChild(); if (current) current->style()->setVerticalAlign(BASELINE); if (!maxHeight) maxHeight = style()->fontSize(); // Base height above which the shape of the root changes int thresholdHeight = static_cast<int>(gThresholdBaseHeight * style()->fontSize()); int topStartShift = 0; if (maxHeight > thresholdHeight && thresholdHeight) { float shift = (maxHeight - thresholdHeight) / static_cast<float>(thresholdHeight); if (shift > 1.) shift = 1.0f; int frontWidth = static_cast<int>(style()->fontSize() * gRadicalWidth); topStartShift = static_cast<int>(gRadicalBottomPointXPos * frontWidth * shift); style()->setPaddingBottom(Length(static_cast<int>(gRootBottomPadding * style()->fontSize()), Fixed)); } // Positioning of the index RenderObject* possibleIndex = firstChild()->firstChild(); while (possibleIndex && !possibleIndex->isBoxModelObject()) possibleIndex = possibleIndex->nextSibling(); RenderBoxModelObject* indexBox = toRenderBoxModelObject(possibleIndex); if (!indexBox) return; int indexShift = indexBox->offsetWidth() + topStartShift; int radicalHeight = static_cast<int>((1 - gRadicalTopLeftPointYPos) * maxHeight); int rootMarginTop = radicalHeight + style()->paddingBottom().value() + indexBox->offsetHeight() - (maxHeight + static_cast<int>(gRootPadding * style()->fontSize())); style()->setPaddingLeft(Length(indexShift, Fixed)); if (rootMarginTop > 0) style()->setPaddingTop(Length(rootMarginTop + static_cast<int>(gRootPadding * style()->fontSize()), Fixed)); setNeedsLayout(true); setPreferredLogicalWidthsDirty(true, false); RenderBlock::layout(); indexBox->style()->setBottom(Length(radicalHeight + style()->paddingBottom().value(), Fixed)); // Now that we've potentially changed its position, we need layout the index again. indexBox->setNeedsLayout(true); indexBox->layout(); }
static inline RenderBoxModelObject& findRendererDefininingTextDecoration(InlineFlowBox* parentBox) { // Lookup first render object in parent hierarchy which has text-decoration set. RenderBoxModelObject* renderer = nullptr; while (parentBox) { renderer = &parentBox->renderer(); if (renderer->style()->textDecoration() != TextDecorationNone) break; parentBox = parentBox->parent(); } ASSERT(renderer); return *renderer; }
void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment, RenderBoxModelObject& decorationRenderer) { ASSERT(!m_paintingResource); ASSERT(m_paintingResourceMode != ApplyToDefaultMode); RenderStyle* decorationStyle = decorationRenderer.style(); ASSERT(decorationStyle); float scalingFactor = 1; Font scaledFont; RenderSVGInlineText::computeNewScaledFontForStyle(&decorationRenderer, decorationStyle, scalingFactor, scaledFont); ASSERT(scalingFactor); // The initial y value refers to overline position. float thickness = thicknessForDecoration(decoration, scaledFont); if (fragment.width <= 0 && thickness <= 0) return; FloatPoint decorationOrigin(fragment.x, fragment.y); float width = fragment.width; const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); GraphicsContextStateSaver stateSaver(*context); if (scalingFactor != 1) { width *= scalingFactor; decorationOrigin.scale(scalingFactor, scalingFactor); context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); } decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness)); Path path; path.addRect(FloatRect(decorationOrigin, FloatSize(width, thickness))); if (acquirePaintingResource(context, scalingFactor, decorationRenderer, decorationStyle)) releasePaintingResource(context, &path); }
void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, int& ascent, int& descent, bool& affectsAscent, bool& affectsDescent) const { bool ascentDescentSet = false; // Replaced boxes will return 0 for the line-height if line-box-contain says they are // not to be included. if (box->renderer().isReplaced()) { if (lineStyle().lineBoxContain() & LineBoxContainReplaced) { ascent = box->baselinePosition(baselineType()); descent = box->lineHeight() - ascent; // Replaced elements always affect both the ascent and descent. affectsAscent = true; affectsDescent = true; } return; } Vector<const SimpleFontData*>* usedFonts = 0; GlyphOverflow* glyphOverflow = 0; if (box->isInlineTextBox()) { GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(toInlineTextBox(box)); usedFonts = it == textBoxDataMap.end() ? 0 : &it->value.first; glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second; } bool includeLeading = includeLeadingForBox(box); bool includeFont = includeFontForBox(box); bool setUsedFont = false; bool setUsedFontWithLeading = false; const RenderStyle& boxLineStyle = box->lineStyle(); #if PLATFORM(IOS) if (usedFonts && !usedFonts->isEmpty() && (includeFont || (boxLineStyle.lineHeight().isNegative() && includeLeading)) && !box->renderer().document().settings()->alwaysUseBaselineOfPrimaryFont()) { #else if (usedFonts && !usedFonts->isEmpty() && (includeFont || (boxLineStyle.lineHeight().isNegative() && includeLeading))) { #endif usedFonts->append(boxLineStyle.font().primaryFont()); for (size_t i = 0; i < usedFonts->size(); ++i) { const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics(); int usedFontAscent = fontMetrics.ascent(baselineType()); int usedFontDescent = fontMetrics.descent(baselineType()); int halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2; int usedFontAscentAndLeading = usedFontAscent + halfLeading; int usedFontDescentAndLeading = fontMetrics.lineSpacing() - usedFontAscentAndLeading; if (includeFont) { setAscentAndDescent(ascent, descent, usedFontAscent, usedFontDescent, ascentDescentSet); setUsedFont = true; } if (includeLeading) { setAscentAndDescent(ascent, descent, usedFontAscentAndLeading, usedFontDescentAndLeading, ascentDescentSet); setUsedFontWithLeading = true; } if (!affectsAscent) affectsAscent = usedFontAscent - box->logicalTop() > 0; if (!affectsDescent) affectsDescent = usedFontDescent + box->logicalTop() > 0; } } // If leading is included for the box, then we compute that box. if (includeLeading && !setUsedFontWithLeading) { int ascentWithLeading = box->baselinePosition(baselineType()); int descentWithLeading = box->lineHeight() - ascentWithLeading; setAscentAndDescent(ascent, descent, ascentWithLeading, descentWithLeading, ascentDescentSet); // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline. // If the top of our font box relative to the root box baseline is above the root box baseline, then // we are contributing to the maxAscent value. Descent is similar. If any part of our font box is below // the root box's baseline, then we contribute to the maxDescent value. affectsAscent = ascentWithLeading - box->logicalTop() > 0; affectsDescent = descentWithLeading + box->logicalTop() > 0; } if (includeFontForBox(box) && !setUsedFont) { int fontAscent = boxLineStyle.fontMetrics().ascent(baselineType()); int fontDescent = boxLineStyle.fontMetrics().descent(baselineType()); setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet); affectsAscent = fontAscent - box->logicalTop() > 0; affectsDescent = fontDescent + box->logicalTop() > 0; } if (includeGlyphsForBox(box) && glyphOverflow && glyphOverflow->computeBounds) { setAscentAndDescent(ascent, descent, glyphOverflow->top, glyphOverflow->bottom, ascentDescentSet); affectsAscent = glyphOverflow->top - box->logicalTop() > 0; affectsDescent = glyphOverflow->bottom + box->logicalTop() > 0; glyphOverflow->top = std::min(glyphOverflow->top, std::max(0, glyphOverflow->top - boxLineStyle.fontMetrics().ascent(baselineType()))); glyphOverflow->bottom = std::min(glyphOverflow->bottom, std::max(0, glyphOverflow->bottom - boxLineStyle.fontMetrics().descent(baselineType()))); } if (includeMarginForBox(box)) { LayoutUnit ascentWithMargin = boxLineStyle.fontMetrics().ascent(baselineType()); LayoutUnit descentWithMargin = boxLineStyle.fontMetrics().descent(baselineType()); if (box->parent() && !box->renderer().isTextOrLineBreak()) { ascentWithMargin += box->boxModelObject()->borderAndPaddingBefore() + box->boxModelObject()->marginBefore(); descentWithMargin += box->boxModelObject()->borderAndPaddingAfter() + box->boxModelObject()->marginAfter(); } setAscentAndDescent(ascent, descent, ascentWithMargin, descentWithMargin, ascentDescentSet); // Treat like a replaced element, since we're using the margin box. affectsAscent = true; affectsDescent = true; } } LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositionCache& verticalPositionCache) { if (box->renderer().isTextOrLineBreak()) return box->parent()->logicalTop(); RenderBoxModelObject* renderer = box->boxModelObject(); ASSERT(renderer->isInline()); if (!renderer->isInline()) return 0; // This method determines the vertical position for inline elements. bool firstLine = isFirstLine(); if (firstLine && !renderer->document().styleSheetCollection().usesFirstLineRules()) firstLine = false; // Check the cache. bool isRenderInline = renderer->isRenderInline(); if (isRenderInline && !firstLine) { LayoutUnit verticalPosition = verticalPositionCache.get(renderer, baselineType()); if (verticalPosition != PositionUndefined) return verticalPosition; } LayoutUnit verticalPosition = 0; EVerticalAlign verticalAlign = renderer->style().verticalAlign(); if (verticalAlign == TOP || verticalAlign == BOTTOM) return 0; RenderElement* parent = renderer->parent(); if (parent->isRenderInline() && parent->style().verticalAlign() != TOP && parent->style().verticalAlign() != BOTTOM) verticalPosition = box->parent()->logicalTop(); if (verticalAlign != BASELINE) { const RenderStyle& parentLineStyle = firstLine ? parent->firstLineStyle() : parent->style(); const Font& font = parentLineStyle.font(); const FontMetrics& fontMetrics = font.fontMetrics(); int fontSize = font.pixelSize(); LineDirectionMode lineDirection = parent->isHorizontalWritingMode() ? HorizontalLine : VerticalLine; if (verticalAlign == SUB) verticalPosition += fontSize / 5 + 1; else if (verticalAlign == SUPER) verticalPosition -= fontSize / 3 + 1; else if (verticalAlign == TEXT_TOP) verticalPosition += renderer->baselinePosition(baselineType(), firstLine, lineDirection) - fontMetrics.ascent(baselineType()); else if (verticalAlign == MIDDLE) verticalPosition = (verticalPosition - LayoutUnit(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection)).round(); else if (verticalAlign == TEXT_BOTTOM) { verticalPosition += fontMetrics.descent(baselineType()); // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case. if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable()) verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType(), firstLine, lineDirection)); } else if (verticalAlign == BASELINE_MIDDLE) verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection); else if (verticalAlign == LENGTH) { LayoutUnit lineHeight; //Per http://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align: 'Percentages: refer to the 'line-height' of the element itself'. if (renderer->style().verticalAlignLength().isPercent()) lineHeight = renderer->style().computedLineHeight(); else lineHeight = renderer->lineHeight(firstLine, lineDirection); verticalPosition -= valueForLength(renderer->style().verticalAlignLength(), lineHeight); } } // Store the cached value. if (isRenderInline && !firstLine) verticalPositionCache.set(renderer, baselineType(), verticalPosition); return verticalPosition; } bool RootInlineBox::includeLeadingForBox(InlineBox* box) const { if (box->renderer().isReplaced() || (box->renderer().isTextOrLineBreak() && !box->behavesLikeText())) return false; LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return (lineBoxContain & LineBoxContainInline) || (box == this && (lineBoxContain & LineBoxContainBlock)); } bool RootInlineBox::includeFontForBox(InlineBox* box) const { if (box->renderer().isReplaced() || (box->renderer().isTextOrLineBreak() && !box->behavesLikeText())) return false; if (!box->behavesLikeText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren()) return false; // For now map "glyphs" to "font" in vertical text mode until the bounds returned by glyphs aren't garbage. LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return (lineBoxContain & LineBoxContainFont) || (!isHorizontal() && (lineBoxContain & LineBoxContainGlyphs)); } bool RootInlineBox::includeGlyphsForBox(InlineBox* box) const { if (box->renderer().isReplaced() || (box->renderer().isTextOrLineBreak() && !box->behavesLikeText())) return false; if (!box->behavesLikeText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren()) return false; // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage. LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs); } bool RootInlineBox::includeMarginForBox(InlineBox* box) const { if (box->renderer().isReplaced() || (box->renderer().isTextOrLineBreak() && !box->behavesLikeText())) return false; LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return lineBoxContain & LineBoxContainInlineBox; } bool RootInlineBox::fitsToGlyphs() const { // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage. LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs); }