LayoutRect RenderReplaced::replacedContentRect(const LayoutSize& intrinsicSize) const { LayoutRect contentRect = contentBoxRect(); if (intrinsicSize.isEmpty()) return contentRect; ObjectFit objectFit = style().objectFit(); LayoutRect finalRect = contentRect; switch (objectFit) { case ObjectFitContain: case ObjectFitScaleDown: case ObjectFitCover: finalRect.setSize(finalRect.size().fitToAspectRatio(intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink)); if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width()) break; FALLTHROUGH; case ObjectFitNone: finalRect.setSize(intrinsicSize); break; case ObjectFitFill: break; } LengthPoint objectPosition = style().objectPosition(); LayoutUnit xOffset = minimumValueForLength(objectPosition.x(), contentRect.width() - finalRect.width()); LayoutUnit yOffset = minimumValueForLength(objectPosition.y(), contentRect.height() - finalRect.height()); finalRect.move(xOffset, yOffset); return finalRect; }
LayoutUnit RenderReplaced::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const { if (style()->logicalWidth().isSpecified() || style()->logicalWidth().isIntrinsic()) return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred); // 10.3.2 Inline, replaced elements: http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-width double intrinsicRatio = 0; FloatSize constrainedSize; computeAspectRatioInformationForRenderBox(constrainedSize, intrinsicRatio); if (style()->logicalWidth().isAuto()) { bool computedHeightIsAuto = hasAutoHeightOrContainingBlockWithAutoHeight(); bool hasIntrinsicWidth = constrainedSize.width() > 0; // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic width, then that intrinsic width is the used value of 'width'. if (computedHeightIsAuto && hasIntrinsicWidth) return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), shouldComputePreferred); bool hasIntrinsicHeight = constrainedSize.height() > 0; if (intrinsicRatio) { // If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, but does have an intrinsic height and intrinsic ratio; // or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value // of 'width' is: (used height) * (intrinsic ratio) if (intrinsicRatio && ((computedHeightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !computedHeightIsAuto)) { LayoutUnit logicalHeight = computeReplacedLogicalHeight(); return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(round(logicalHeight * intrinsicRatio)), shouldComputePreferred); } // If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width, then the used value of // 'width' is undefined in CSS 2.1. However, it is suggested that, if the containing block's width does not itself depend on the replaced element's width, then // the used value of 'width' is calculated from the constraint equation used for block-level, non-replaced elements in normal flow. if (computedHeightIsAuto && !hasIntrinsicWidth && !hasIntrinsicHeight) { if (shouldComputePreferred == ComputePreferred) return 0; // The aforementioned 'constraint equation' used for block-level, non-replaced elements in normal flow: // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block LayoutUnit logicalWidth = containingBlock()->availableLogicalWidth(); // This solves above equation for 'width' (== logicalWidth). LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), logicalWidth); LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), logicalWidth); logicalWidth = std::max<LayoutUnit>(0, logicalWidth - (marginStart + marginEnd + (width() - clientWidth()))); return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth, shouldComputePreferred); } } // Otherwise, if 'width' has a computed value of 'auto', and the element has an intrinsic width, then that intrinsic width is the used value of 'width'. if (hasIntrinsicWidth) return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), shouldComputePreferred); // Otherwise, if 'width' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'width' becomes 300px. If 300px is too // wide to fit the device, UAs should use the width of the largest rectangle that has a 2:1 ratio and fits the device instead. // Note: We fall through and instead return intrinsicLogicalWidth() here - to preserve existing WebKit behavior, which might or might not be correct, or desired. // Changing this to return cDefaultWidth, will affect lots of test results. Eg. some tests assume that a blank <img> tag (which implies width/height=auto) // has no intrinsic size, which is wrong per CSS 2.1, but matches our behavior since a long time. } return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), shouldComputePreferred); }
Path HTMLAreaElement::getRegion(const LayoutSize& size) const { if (m_coords.isEmpty() && m_shape != Default) return Path(); LayoutUnit width = size.width(); LayoutUnit height = size.height(); // If element omits the shape attribute, select shape based on number of coordinates. Shape shape = m_shape; if (shape == Unknown) { if (m_coords.size() == 3) shape = Circle; else if (m_coords.size() == 4) shape = Rect; else if (m_coords.size() >= 6) shape = Poly; } Path path; switch (shape) { case Poly: if (m_coords.size() >= 6) { int numPoints = m_coords.size() / 2; path.moveTo(FloatPoint(minimumValueForLength(m_coords[0], width).toFloat(), minimumValueForLength(m_coords[1], height).toFloat())); for (int i = 1; i < numPoints; ++i) path.addLineTo(FloatPoint(minimumValueForLength(m_coords[i * 2], width).toFloat(), minimumValueForLength(m_coords[i * 2 + 1], height).toFloat())); path.closeSubpath(); } break; case Circle: if (m_coords.size() >= 3) { Length radius = m_coords[2]; float r = std::min(minimumValueForLength(radius, width).toFloat(), minimumValueForLength(radius, height).toFloat()); path.addEllipse(FloatRect(minimumValueForLength(m_coords[0], width).toFloat() - r, minimumValueForLength(m_coords[1], height).toFloat() - r, 2 * r, 2 * r)); } break; case Rect: if (m_coords.size() >= 4) { float x0 = minimumValueForLength(m_coords[0], width).toFloat(); float y0 = minimumValueForLength(m_coords[1], height).toFloat(); float x1 = minimumValueForLength(m_coords[2], width).toFloat(); float y1 = minimumValueForLength(m_coords[3], height).toFloat(); path.addRect(FloatRect(x0, y0, x1 - x0, y1 - y0)); } break; case Default: path.addRect(FloatRect(0, 0, width.toFloat(), height.toFloat())); break; case Unknown: break; } return path; }
LayoutRect LayoutReplaced::computeObjectFit( const LayoutSize* overriddenIntrinsicSize) const { LayoutRect contentRect = contentBoxRect(); ObjectFit objectFit = style()->getObjectFit(); if (objectFit == ObjectFitFill && style()->objectPosition() == ComputedStyle::initialObjectPosition()) { return contentRect; } // TODO(davve): intrinsicSize doubles as both intrinsic size and intrinsic // ratio. In the case of SVG images this isn't correct since they can have // intrinsic ratio but no intrinsic size. In order to maintain aspect ratio, // the intrinsic size for SVG might be faked from the aspect ratio, // see SVGImage::containerSize(). LayoutSize intrinsicSize = overriddenIntrinsicSize ? *overriddenIntrinsicSize : this->intrinsicSize(); if (!intrinsicSize.width() || !intrinsicSize.height()) return contentRect; LayoutRect finalRect = contentRect; switch (objectFit) { case ObjectFitContain: case ObjectFitScaleDown: case ObjectFitCover: finalRect.setSize(finalRect.size().fitToAspectRatio( intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink)); if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width()) break; // fall through case ObjectFitNone: finalRect.setSize(intrinsicSize); break; case ObjectFitFill: break; default: ASSERT_NOT_REACHED(); } LayoutUnit xOffset = minimumValueForLength( style()->objectPosition().x(), contentRect.width() - finalRect.width()); LayoutUnit yOffset = minimumValueForLength( style()->objectPosition().y(), contentRect.height() - finalRect.height()); finalRect.move(xOffset, yOffset); return finalRect; }
void RenderScrollbarPart::computeScrollbarWidth() { if (!m_scrollbar->owningRenderer()) return; RenderView* renderView = view(); int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->borderLeft() - m_scrollbar->owningRenderer()->borderRight(); int w = calcScrollbarThicknessUsing(style()->width(), visibleSize, renderView); int minWidth = calcScrollbarThicknessUsing(style()->minWidth(), visibleSize, renderView); int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(style()->maxWidth(), visibleSize, renderView); setWidth(max(minWidth, min(maxWidth, w))); // Buttons and track pieces can all have margins along the axis of the scrollbar. m_marginLeft = minimumValueForLength(style()->marginLeft(), visibleSize, renderView); m_marginRight = minimumValueForLength(style()->marginRight(), visibleSize, renderView); }
void RenderScrollbarPart::computeScrollbarHeight() { if (!m_scrollbar->owningRenderer()) return; RenderView* renderView = view(); int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->borderTop() - m_scrollbar->owningRenderer()->borderBottom(); int h = calcScrollbarThicknessUsing(style()->height(), visibleSize, renderView); int minHeight = calcScrollbarThicknessUsing(style()->minHeight(), visibleSize, renderView); int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(style()->maxHeight(), visibleSize, renderView); setHeight(max(minHeight, min(maxHeight, h))); // Buttons and track pieces can all have margins along the axis of the scrollbar. m_marginTop = minimumValueForLength(style()->marginTop(), visibleSize, renderView); m_marginBottom = minimumValueForLength(style()->marginBottom(), visibleSize, renderView); }
LayoutUnit valueForLength(const Length& length, LayoutUnit maximumValue) { switch (length.type()) { case Fixed: case Percent: case Calculated: return minimumValueForLength(length, maximumValue); case FillAvailable: case Auto: return maximumValue; case Intrinsic: case MinIntrinsic: case MinContent: case MaxContent: case FitContent: case ExtendToZoom: case DeviceWidth: case DeviceHeight: case Undefined: ASSERT_NOT_REACHED(); return 0; } ASSERT_NOT_REACHED(); return 0; }
void LayoutScrollbarPart::computeScrollbarHeight() { if (!m_scrollbar->owningLayoutObject()) return; // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change. // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders. int visibleSize = m_scrollbar->owningLayoutObject()->size().height() - m_scrollbar->owningLayoutObject()->style()->borderTopWidth() - m_scrollbar->owningLayoutObject()->style()->borderBottomWidth(); int h = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->height(), visibleSize); int minHeight = calcScrollbarThicknessUsing(MinSize, style()->minHeight(), visibleSize); int maxHeight = style()->maxHeight().isMaxSizeNone() ? h : calcScrollbarThicknessUsing(MaxSize, style()->maxHeight(), visibleSize); setHeight(std::max(minHeight, std::min(maxHeight, h))); // Buttons and track pieces can all have margins along the axis of the scrollbar. setMarginTop(minimumValueForLength(style()->marginTop(), visibleSize)); setMarginBottom(minimumValueForLength(style()->marginBottom(), visibleSize)); }
LayoutUnit valueForLength(const Length& length, LayoutUnit maximumValue, RenderView* renderView, bool roundPercentages) { switch (length.type()) { case Fixed: case Percent: case Calculated: case ViewportPercentageWidth: case ViewportPercentageHeight: case ViewportPercentageMin: case ViewportPercentageMax: return minimumValueForLength(length, maximumValue, renderView, roundPercentages); case FillAvailable: case Auto: return maximumValue; case Relative: case Intrinsic: case MinIntrinsic: case MinContent: case MaxContent: case FitContent: case Undefined: ASSERT_NOT_REACHED(); return 0; } ASSERT_NOT_REACHED(); return 0; }
LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const { LayoutUnit w = 0; if (padding.isPercent()) w = containingBlockLogicalWidthForContent(); return minimumValueForLength(padding, w); }
void RenderScrollbarPart::computeScrollbarWidth() { if (!m_scrollbar->owningRenderer()) return; // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change. // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders. int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->style().borderLeftWidth() - m_scrollbar->owningRenderer()->style().borderRightWidth(); int w = calcScrollbarThicknessUsing(MainOrPreferredSize, style().width(), visibleSize); int minWidth = calcScrollbarThicknessUsing(MinSize, style().minWidth(), visibleSize); int maxWidth = style().maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(MaxSize, style().maxWidth(), visibleSize); setWidth(std::max(minWidth, std::min(maxWidth, w))); // Buttons and track pieces can all have margins along the axis of the scrollbar. m_marginBox.setLeft(minimumValueForLength(style().marginLeft(), visibleSize)); m_marginBox.setRight(minimumValueForLength(style().marginRight(), visibleSize)); }
LayoutRect RenderReplaced::replacedContentRect(const LayoutSize* overriddenIntrinsicSize) const { LayoutRect contentRect = contentBoxRect(); ObjectFit objectFit = style()->objectFit(); if (objectFit == ObjectFitFill && style()->objectPosition() == RenderStyle::initialObjectPosition()) { if (RuntimeEnabledFeatures::objectFitPositionEnabled()) return contentRect; objectFit = ObjectFitContain; } LayoutSize intrinsicSize = overriddenIntrinsicSize ? *overriddenIntrinsicSize : this->intrinsicSize(); if (!intrinsicSize.width() || !intrinsicSize.height()) return contentRect; LayoutRect finalRect = contentRect; switch (objectFit) { case ObjectFitContain: case ObjectFitScaleDown: case ObjectFitCover: finalRect.setSize(finalRect.size().fitToAspectRatio(intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink)); if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width()) break; // fall through case ObjectFitNone: finalRect.setSize(intrinsicSize); break; case ObjectFitFill: break; default: ASSERT_NOT_REACHED(); } LayoutUnit xOffset = minimumValueForLength(style()->objectPosition().x(), contentRect.width() - finalRect.width()); LayoutUnit yOffset = minimumValueForLength(style()->objectPosition().y(), contentRect.height() - finalRect.height()); finalRect.move(xOffset, yOffset); return finalRect; }
LayoutUnit LayoutReplaced::computeConstrainedLogicalWidth( ShouldComputePreferred shouldComputePreferred) const { if (shouldComputePreferred == ComputePreferred) return computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit(), ComputePreferred); // The aforementioned 'constraint equation' used for block-level, non-replaced // elements in normal flow: // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + // 'padding-right' + 'border-right-width' + 'margin-right' = width of // containing block LayoutUnit logicalWidth = containingBlock()->availableLogicalWidth(); // This solves above equation for 'width' (== logicalWidth). LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), logicalWidth); LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), logicalWidth); logicalWidth = (logicalWidth - (marginStart + marginEnd + (size().width() - clientWidth()))) .clampNegativeToZero(); return computeReplacedLogicalWidthRespectingMinMaxWidth( logicalWidth, shouldComputePreferred); }
bool TextAutoSizingValue::adjustNodeSizes() { bool objectsRemoved = false; // Remove stale nodes. Nodes may have had their renderers detached. We'll // also need to remove the style from the documents m_textAutoSizedNodes // collection. Return true indicates we need to do that removal. Vector<RefPtr<Node> > nodesForRemoval; HashSet<RefPtr<Node> >::iterator end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { RefPtr<Node> autoSizingNode = *i; RenderText* text = static_cast<RenderText*>(autoSizingNode->renderer()); if (!text || !text->style().textSizeAdjust().isAuto() || !text->candidateComputedTextSize()) { // remove node. nodesForRemoval.append(autoSizingNode); objectsRemoved = true; } } unsigned count = nodesForRemoval.size(); for (unsigned i = 0; i < count; i++) m_autoSizedNodes.remove(nodesForRemoval[i]); // If we only have one piece of text with the style on the page don't // adjust it's size. if (m_autoSizedNodes.size() <= 1) return objectsRemoved; // Compute average size float cumulativeSize = 0; end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { RefPtr<Node> autoSizingNode = *i; RenderText* renderText = static_cast<RenderText*>(autoSizingNode->renderer()); cumulativeSize += renderText->candidateComputedTextSize(); } float averageSize = roundf(cumulativeSize / m_autoSizedNodes.size()); // Adjust sizes bool firstPass = true; end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { const RefPtr<Node>& autoSizingNode = *i; RenderText* text = static_cast<RenderText*>(autoSizingNode->renderer()); if (text && text->style().fontDescription().computedSize() != averageSize) { float specifiedSize = text->style().fontDescription().specifiedSize(); float scaleChange = averageSize / specifiedSize; if (scaleChange > MAX_SCALE_INCREASE && firstPass) { firstPass = false; averageSize = roundf(specifiedSize * MAX_SCALE_INCREASE); scaleChange = averageSize / specifiedSize; } RefPtr<RenderStyle> style = cloneRenderStyleWithState(text->style()); FontDescription fontDescription = style->fontDescription(); fontDescription.setComputedSize(averageSize); style->setFontDescription(fontDescription); style->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); text->parent()->setStyle(style.releaseNonNull()); RenderElement* parentRenderer = text->parent(); if (parentRenderer->isAnonymousBlock()) parentRenderer = parentRenderer->parent(); // If we have a list we should resize ListMarkers separately. RenderObject* listMarkerRenderer = parentRenderer->firstChild(); if (listMarkerRenderer->isListMarker()) { RefPtr<RenderStyle> style = cloneRenderStyleWithState(listMarkerRenderer->style()); style->setFontDescription(fontDescription); style->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); toRenderListMarker(*listMarkerRenderer).setStyle(style.releaseNonNull()); } // Resize the line height of the parent. const RenderStyle& parentStyle = parentRenderer->style(); Length lineHeightLength = parentStyle.specifiedLineHeight(); int specifiedLineHeight = 0; if (lineHeightLength.isPercent()) specifiedLineHeight = minimumValueForLength(lineHeightLength, fontDescription.specifiedSize()); else specifiedLineHeight = lineHeightLength.value(); int lineHeight = specifiedLineHeight * scaleChange; if (!lineHeightLength.isFixed() || lineHeightLength.value() != lineHeight) { RefPtr<RenderStyle> newParentStyle = cloneRenderStyleWithState(parentStyle); newParentStyle->setLineHeight(Length(lineHeight, Fixed)); newParentStyle->setSpecifiedLineHeight(lineHeightLength); newParentStyle->setFontDescription(fontDescription); newParentStyle->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); parentRenderer->setStyle(newParentStyle.releaseNonNull()); } } } return objectsRemoved; }
static int calcScrollbarThicknessUsing(SizeType sizeType, const Length& length, int containingLength) { if (!length.isIntrinsicOrAuto() || (sizeType == MinSize && length.isAuto())) return minimumValueForLength(length, containingLength); return ScrollbarTheme::theme()->scrollbarThickness(); }
int minimumIntValueForLength(const Length& length, LayoutUnit maximumValue, RenderView* renderView, bool roundPercentages) { return static_cast<int>(minimumValueForLength(length, maximumValue, renderView, roundPercentages)); }
LayoutUnit roundedMinimumValueForLength(const Length& length, LayoutUnit maximumValue) { if (length.type() == Percent) return static_cast<LayoutUnit>(round(maximumValue * length.percent() / 100.0f)); return minimumValueForLength(length, maximumValue); }
static int calcScrollbarThicknessUsing(const Length& length, int containingLength, RenderView* renderView) { if (length.isIntrinsicOrAuto()) return ScrollbarTheme::theme()->scrollbarThickness(); return minimumValueForLength(length, containingLength, renderView); }
LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) const { if (style()->logicalWidth().isSpecified()) return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), includeMaxWidth); RenderBox* contentRenderer = embeddedContentBox(); // 10.3.2 Inline, replaced elements: http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-width bool isPercentageIntrinsicSize = false; double intrinsicRatio = 0; FloatSize intrinsicSize; computeIntrinsicRatioInformationForRenderBox(contentRenderer, intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); // FIXME: Remove unnecessary round/roundToInt calls from this method when layout is off ints: webkit.org/b/63656 if (style()->logicalWidth().isAuto()) { bool heightIsAuto = style()->logicalHeight().isAuto(); bool hasIntrinsicWidth = !isPercentageIntrinsicSize && intrinsicSize.width() > 0; // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic width, then that intrinsic width is the used value of 'width'. if (heightIsAuto && hasIntrinsicWidth) return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(intrinsicSize.width()), includeMaxWidth); bool hasIntrinsicHeight = !isPercentageIntrinsicSize && intrinsicSize.height() > 0; if (intrinsicRatio || isPercentageIntrinsicSize) { // If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, but does have an intrinsic height and intrinsic ratio; // or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value // of 'width' is: (used height) * (intrinsic ratio) if (intrinsicRatio && ((heightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !heightIsAuto)) { LayoutUnit logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight()); return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(round(logicalHeight * intrinsicRatio))); } // If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width, then the used value of // 'width' is undefined in CSS 2.1. However, it is suggested that, if the containing block's width does not itself depend on the replaced element's width, then // the used value of 'width' is calculated from the constraint equation used for block-level, non-replaced elements in normal flow. if (heightIsAuto && !hasIntrinsicWidth && !hasIntrinsicHeight && contentRenderer) { // The aforementioned 'constraint equation' used for block-level, non-replaced elements in normal flow: // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block LayoutUnit logicalWidth; if (RenderBlock* blockWithWidth = firstContainingBlockWithLogicalWidth(this)) logicalWidth = blockWithWidth->computeReplacedLogicalWidthRespectingMinMaxWidth(blockWithWidth->computeReplacedLogicalWidthUsing(blockWithWidth->style()->logicalWidth()), false); else logicalWidth = containingBlock()->availableLogicalWidth(); // This solves above equation for 'width' (== logicalWidth). LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), logicalWidth); LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), logicalWidth); logicalWidth = max(ZERO_LAYOUT_UNIT, logicalWidth - (marginStart + marginEnd + (width() - clientWidth()))); if (isPercentageIntrinsicSize) logicalWidth = roundToInt(logicalWidth * intrinsicSize.width() / 100); return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth, includeMaxWidth); } } // Otherwise, if 'width' has a computed value of 'auto', and the element has an intrinsic width, then that intrinsic width is the used value of 'width'. if (hasIntrinsicWidth) return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(intrinsicSize.width()), includeMaxWidth); // Otherwise, if 'width' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'width' becomes 300px. If 300px is too // wide to fit the device, UAs should use the width of the largest rectangle that has a 2:1 ratio and fits the device instead. // Note: We fall through and instead return intrinsicLogicalWidth() here - to preserve existing WebKit behavior, which might or might not be correct, or desired. // Changing this to return cDefaultWidth, will affect lots of test results. Eg. some tests assume that a blank <img> tag (which implies width/height=auto) // has no intrinsic size, which is wrong per CSS 2.1, but matches our behavior since a long time. } return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), includeMaxWidth); }