void RenderReplaced::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; ASSERT(needsLayout()); LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); setHeight(minimumReplacedHeight()); updateLogicalWidth(); updateLogicalHeight(); // Now that we've calculated our preferred layout, we check to see // if we should further constrain sizing to the intrinsic aspect ratio. if (style().aspectRatioType() == AspectRatioFromIntrinsic && !m_intrinsicSize.isEmpty()) { float aspectRatio = m_intrinsicSize.aspectRatio(); LayoutSize frameSize = size(); float frameAspectRatio = frameSize.aspectRatio(); if (frameAspectRatio < aspectRatio) setHeight(computeReplacedLogicalHeightRespectingMinMaxHeight(frameSize.height() * frameAspectRatio / aspectRatio)); else if (frameAspectRatio > aspectRatio) setWidth(computeReplacedLogicalWidthRespectingMinMaxWidth(frameSize.width() * aspectRatio / frameAspectRatio, ComputePreferred)); } clearOverflow(); addVisualEffectOverflow(); updateLayerTransform(); invalidateBackgroundObscurationStatus(); repainter.repaintAfterLayout(); clearNeedsLayout(); }
int RenderReplaced::computeIntrinsicLogicalWidth(RenderBox* contentRenderer, bool includeMaxWidth) const { if (m_hasIntrinsicSize) return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth); ASSERT(contentRenderer); ASSERT(contentRenderer->style()); return contentRenderer->computeReplacedLogicalWidthRespectingMinMaxWidth(contentRenderer->computeReplacedLogicalWidthUsing(contentRenderer->style()->logicalWidth()), includeMaxWidth); }
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); }
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); }
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); }
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; if (contentRenderer) contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); else computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); if (intrinsicRatio && !isHorizontalWritingMode()) intrinsicRatio = 1 / intrinsicRatio; if (style()->logicalWidth().isAuto()) { bool heightIsAuto = style()->logicalHeight().isAuto(); bool hasIntrinsicWidth = m_hasIntrinsicSize || (!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) { if (m_hasIntrinsicSize) return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth); return static_cast<LayoutUnit>(intrinsicSize.width() * style()->effectiveZoom()); } bool hasIntrinsicHeight = m_hasIntrinsicSize || (!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(static_cast<LayoutUnit>(ceil(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 = miminumValueForLength(style()->marginStart(), logicalWidth); LayoutUnit marginEnd = miminumValueForLength(style()->marginEnd(), logicalWidth); logicalWidth = max(0, logicalWidth - (marginStart + marginEnd + (width() - clientWidth()))); if (isPercentageIntrinsicSize) // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 logicalWidth = static_cast<LayoutUnit>(round(logicalWidth * intrinsicSize.width() / 100)); return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth); } } // 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) { if (isPercentageIntrinsicSize || m_hasIntrinsicSize) return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth); return static_cast<LayoutUnit>(intrinsicSize.width() * style()->effectiveZoom()); } // 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. return computeReplacedLogicalWidthRespectingMinMaxWidth(cDefaultWidth, includeMaxWidth); } return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), includeMaxWidth); }
LayoutUnit LayoutReplaced::computeReplacedLogicalWidth( ShouldComputePreferred shouldComputePreferred) const { if (style()->logicalWidth().isSpecified() || style()->logicalWidth().isIntrinsic()) return computeReplacedLogicalWidthRespectingMinMaxWidth( computeReplacedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth()), shouldComputePreferred); LayoutReplaced* contentLayoutObject = embeddedReplacedContent(); // 10.3.2 Inline, replaced elements: // http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-width IntrinsicSizingInfo intrinsicSizingInfo; computeIntrinsicSizingInfoForReplacedContent(contentLayoutObject, intrinsicSizingInfo); FloatSize constrainedSize = constrainIntrinsicSizeToMinMax(intrinsicSizingInfo); if (style()->logicalWidth().isAuto()) { bool computedHeightIsAuto = style()->logicalHeight().isAuto(); // 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 && intrinsicSizingInfo.hasWidth) return computeReplacedLogicalWidthRespectingMinMaxWidth( LayoutUnit(constrainedSize.width()), shouldComputePreferred); if (!intrinsicSizingInfo.aspectRatio.isEmpty()) { // 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 ((computedHeightIsAuto && !intrinsicSizingInfo.hasWidth && intrinsicSizingInfo.hasHeight) || !computedHeightIsAuto) { LayoutUnit estimatedUsedWidth = intrinsicSizingInfo.hasWidth ? LayoutUnit(constrainedSize.width()) : computeConstrainedLogicalWidth(shouldComputePreferred); LayoutUnit logicalHeight = computeReplacedLogicalHeight(estimatedUsedWidth); return computeReplacedLogicalWidthRespectingMinMaxWidth( resolveWidthForRatio(logicalHeight, intrinsicSizingInfo.aspectRatio), 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 && !intrinsicSizingInfo.hasWidth && !intrinsicSizingInfo.hasHeight) return computeConstrainedLogicalWidth(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 (intrinsicSizingInfo.hasWidth) return computeReplacedLogicalWidthRespectingMinMaxWidth( LayoutUnit(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); }