void LayoutReplaced::computePositionedLogicalWidth( LogicalExtentComputedValues& computedValues) const { // The following is based off of the W3C Working Draft from April 11, 2006 of // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements" // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width> // (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 // relative positioned inline. const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(container()); const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock); const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false); // To match WinIE, in quirks mode use the parent's 'direction' property // instead of the the container block's. TextDirection containerDirection = containerBlock->style()->direction(); // Variables to solve. bool isHorizontal = isHorizontalWritingMode(); Length logicalLeft = style()->logicalLeft(); Length logicalRight = style()->logicalRight(); Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop(); Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom(); LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end; LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start; // --------------------------------------------------------------------------- // 1. The used value of 'width' is determined as for inline replaced // elements. // --------------------------------------------------------------------------- // NOTE: This value of width is final in that the min/max width calculations // are dealt with in computeReplacedWidth(). This means that the steps to // produce correct max/min in the non-replaced version, are not necessary. computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth(); const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_extent; // --------------------------------------------------------------------------- // 2. If both 'left' and 'right' have the value 'auto', then if 'direction' // of the containing block is 'ltr', set 'left' to the static position; // else if 'direction' is 'rtl', set 'right' to the static position. // --------------------------------------------------------------------------- // see FIXME 1 computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth); // --------------------------------------------------------------------------- // 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' // or 'margin-right' with '0'. // --------------------------------------------------------------------------- if (logicalLeft.isAuto() || logicalRight.isAuto()) { if (marginLogicalLeft.isAuto()) marginLogicalLeft.setValue(Fixed, 0); if (marginLogicalRight.isAuto()) marginLogicalRight.setValue(Fixed, 0); } // --------------------------------------------------------------------------- // 4. If at this point both 'margin-left' and 'margin-right' are still 'auto', // solve the equation under the extra constraint that the two margins must // get equal values, unless this would make them negative, in which case // when the direction of the containing block is 'ltr' ('rtl'), set // 'margin-left' ('margin-right') to zero and solve for 'margin-right' // ('margin-left'). // --------------------------------------------------------------------------- LayoutUnit logicalLeftValue; LayoutUnit logicalRightValue; if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { // 'left' and 'right' cannot be 'auto' due to step 3 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto())); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue); if (difference > LayoutUnit()) { marginLogicalLeftAlias = difference / 2; // split the difference marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences } else { // Use the containing block's direction rather than the parent block's // per CSS 2.1 reference test abspos-replaced-width-margin-000. if (containerDirection == LTR) { marginLogicalLeftAlias = LayoutUnit(); marginLogicalRightAlias = difference; // will be negative } else { marginLogicalLeftAlias = difference; // will be negative marginLogicalRightAlias = LayoutUnit(); } } // ------------------------------------------------------------------------- // 5. If at this point there is an 'auto' left, solve the equation for that // value. // ------------------------------------------------------------------------- } else if (logicalLeft.isAuto()) { marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); // Solve for 'left' logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias); } else if (logicalRight.isAuto()) { marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); // Solve for 'right' logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias); } else if (marginLogicalLeft.isAuto()) { marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); // Solve for 'margin-left' marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias); } else if (marginLogicalRight.isAuto()) { marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); // Solve for 'margin-right' marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias); } else { // Nothing is 'auto', just calculate the values. marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); // If the containing block is right-to-left, then push the left position as // far to the right as possible if (containerDirection == RTL) { int totalLogicalWidth = (computedValues.m_extent + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias) .toInt(); logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue); } } // --------------------------------------------------------------------------- // 6. If at this point the values are over-constrained, ignore the value for // either 'left' (in case the 'direction' property of the containing block // is 'rtl') or 'right' (in case 'direction' is 'ltr') and solve for that // value. // --------------------------------------------------------------------------- // NOTE: Constraints imposed by the width of the containing block and its // content have already been accounted for above. // // FIXME: Deal with differing writing modes here. Our offset needs to be in // the containing block's coordinate space, so that // can make the result here rather complicated to compute. // // Use computed values to calculate the horizontal position. // // FIXME: This hack is needed to calculate the logical left position for a // 'rtl' relatively positioned, inline containing block because right now, it // is using the logical left position of the first line box when really it // should use the last line box. When this is fixed elsewhere, this block // should be removed. if (containerBlock->isLayoutInline() && !containerBlock->style()->isLeftToRightDirection()) { const LayoutInline* flow = toLayoutInline(containerBlock); InlineFlowBox* firstLine = flow->firstLineBox(); InlineFlowBox* lastLine = flow->lastLineBox(); if (firstLine && lastLine && firstLine != lastLine) { computedValues.m_position = logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()); return; } } LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias; computeLogicalLeftPositionedOffset(logicalLeftPos, this, computedValues.m_extent, containerBlock, containerLogicalWidth); computedValues.m_position = logicalLeftPos; }