Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
void LayoutReplaced::computePositionedLogicalHeight(
    LogicalExtentComputedValues& computedValues) const {
    // The following is based off of the W3C Working Draft from April 11, 2006 of
    // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
    // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
    // (block-style-comments in this function correspond to text from the spec and
    // the numbers correspond to numbers in spec)

    // We don't use containingBlock(), since we may be positioned by an enclosing
    // relpositioned inline.
    const LayoutBoxModelObject* containerBlock =
        toLayoutBoxModelObject(container());

    const LayoutUnit containerLogicalHeight =
        containingBlockLogicalHeightForPositioned(containerBlock);
    const LayoutUnit containerRelativeLogicalWidth =
        containingBlockLogicalWidthForPositioned(containerBlock, false);

    // Variables to solve.
    Length marginBefore = style()->marginBefore();
    Length marginAfter = style()->marginAfter();
    LayoutUnit& marginBeforeAlias = computedValues.m_margins.m_before;
    LayoutUnit& marginAfterAlias = computedValues.m_margins.m_after;

    Length logicalTop = style()->logicalTop();
    Length logicalBottom = style()->logicalBottom();

    // ---------------------------------------------------------------------------
    // 1. The used value of 'height' is determined as for inline replaced
    //    elements.
    // ---------------------------------------------------------------------------
    // NOTE: This value of height is final in that the min/max height calculations
    // are dealt with in computeReplacedHeight().  This means that the steps to
    // produce correct max/min in the non-replaced version, are not necessary.
    computedValues.m_extent =
        computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight();
    const LayoutUnit availableSpace =
        containerLogicalHeight - computedValues.m_extent;

    // ---------------------------------------------------------------------------
    // 2. If both 'top' and 'bottom' have the value 'auto', replace 'top' with the
    //    element's static position.
    // ---------------------------------------------------------------------------
    // see FIXME 1
    computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);

    // ---------------------------------------------------------------------------
    // 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
    //    'margin-bottom' with '0'.
    // ---------------------------------------------------------------------------
    // FIXME: The spec. says that this step should only be taken when bottom is
    // auto, but if only top is auto, this makes step 4 impossible.
    if (logicalTop.isAuto() || logicalBottom.isAuto()) {
        if (marginBefore.isAuto())
            marginBefore.setValue(Fixed, 0);
        if (marginAfter.isAuto())
            marginAfter.setValue(Fixed, 0);
    }

    // ---------------------------------------------------------------------------
    // 4. If at this point both 'margin-top' and 'margin-bottom' are still 'auto',
    //    solve the equation under the extra constraint that the two margins must
    //    get equal values.
    // ---------------------------------------------------------------------------
    LayoutUnit logicalTopValue;
    LayoutUnit logicalBottomValue;

    if (marginBefore.isAuto() && marginAfter.isAuto()) {
        // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
        ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));

        logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
        logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);

        LayoutUnit difference =
            availableSpace - (logicalTopValue + logicalBottomValue);
        // NOTE: This may result in negative values.
        marginBeforeAlias = difference / 2;  // split the difference
        marginAfterAlias =
            difference - marginBeforeAlias;  // account for odd valued differences

        // -------------------------------------------------------------------------
        // 5. If at this point there is only one 'auto' left, solve the equation
        //    for that value.
        // -------------------------------------------------------------------------
    } else if (logicalTop.isAuto()) {
        marginBeforeAlias =
            valueForLength(marginBefore, containerRelativeLogicalWidth);
        marginAfterAlias =
            valueForLength(marginAfter, containerRelativeLogicalWidth);
        logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);

        // Solve for 'top'
        logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias +
                                            marginAfterAlias);
    } else if (logicalBottom.isAuto()) {
        marginBeforeAlias =
            valueForLength(marginBefore, containerRelativeLogicalWidth);
        marginAfterAlias =
            valueForLength(marginAfter, containerRelativeLogicalWidth);
        logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);

        // Solve for 'bottom'
        // NOTE: It is not necessary to solve for 'bottom' because we don't ever
        // use the value.
    } else if (marginBefore.isAuto()) {
        marginAfterAlias =
            valueForLength(marginAfter, containerRelativeLogicalWidth);
        logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
        logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);

        // Solve for 'margin-top'
        marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue +
                                              marginAfterAlias);
    } else if (marginAfter.isAuto()) {
        marginBeforeAlias =
            valueForLength(marginBefore, containerRelativeLogicalWidth);
        logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
        logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);

        // Solve for 'margin-bottom'
        marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue +
                                             marginBeforeAlias);
    } else {
        // Nothing is 'auto', just calculate the values.
        marginBeforeAlias =
            valueForLength(marginBefore, containerRelativeLogicalWidth);
        marginAfterAlias =
            valueForLength(marginAfter, containerRelativeLogicalWidth);
        logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
        // NOTE: It is not necessary to solve for 'bottom' because we don't ever
        // use the value.
    }

    // ---------------------------------------------------------------------------
    // 6. If at this point the values are over-constrained, ignore the value for
    //    'bottom' and solve for that value.
    // ---------------------------------------------------------------------------
    // NOTE: It is not necessary to do this step because we don't end up using the
    // value of 'bottom' regardless of whether the values are over-constrained or
    // not.

    // Use computed values to calculate the vertical position.
    LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias;
    computeLogicalTopPositionedOffset(logicalTopPos, this,
                                      computedValues.m_extent, containerBlock,
                                      containerLogicalHeight);
    computedValues.m_position = logicalTopPos;
}