LayoutSize RenderBoxModelObject::relativePositionOffset() const { LayoutSize offset = accumulateInFlowPositionOffsets(this); RenderBlock* containingBlock = this->containingBlock(); // Objects that shrink to avoid floats normally use available line width when computing containing block width. However // in the case of relative positioning using percentages, we can't do this. The offset should always be resolved using the // available width of the containing block. Therefore we don't use containingBlockLogicalWidthForContent() here, but instead explicitly // call availableWidth on our containing block. if (!style()->left().isAuto()) { if (!style()->right().isAuto() && !containingBlock->style()->isLeftToRightDirection()) offset.setWidth(-valueForLength(style()->right(), containingBlock->availableWidth())); else offset.expand(valueForLength(style()->left(), containingBlock->availableWidth()), 0); } else if (!style()->right().isAuto()) { offset.expand(-valueForLength(style()->right(), containingBlock->availableWidth()), 0); } // If the containing block of a relatively positioned element does not // specify a height, a percentage top or bottom offset should be resolved as // auto. An exception to this is if the containing block has the WinIE quirk // where <html> and <body> assume the size of the viewport. In this case, // calculate the percent offset based on this height. // See <https://bugs.webkit.org/show_bug.cgi?id=26396>. if (!style()->top().isAuto() && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() || !style()->top().isPercent() || containingBlock->stretchesToViewport())) offset.expand(0, valueForLength(style()->top(), containingBlock->availableHeight())); else if (!style()->bottom().isAuto() && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() || !style()->bottom().isPercent() || containingBlock->stretchesToViewport())) offset.expand(0, -valueForLength(style()->bottom(), containingBlock->availableHeight())); return offset; }
bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const { Length logicalHeightLength = style()->logicalHeight(); if (logicalHeightLength.isAuto()) return true; // For percentage heights: The percentage is calculated with respect to the height of the generated box's // containing block. If the height of the containing block is not specified explicitly (i.e., it depends // on content height), and this element is not absolutely positioned, the value computes to 'auto'. if (!logicalHeightLength.isPercent() || isOutOfFlowPositioned() || document().inQuirksMode()) return false; // Anonymous block boxes are ignored when resolving percentage values that would refer to it: // the closest non-anonymous ancestor box is used instead. RenderBlock* cb = containingBlock(); while (cb->isAnonymous()) cb = cb->containingBlock(); // Matching RenderBox::percentageLogicalHeightIsResolvableFromBlock() by // ignoring table cell's attribute value, where it says that table cells violate // what the CSS spec says to do with heights. Basically we // don't care if the cell specified a height or not. if (cb->isTableCell()) return false; // Match RenderBox::availableLogicalHeightUsing by special casing // the render view. The available height is taken from the frame. if (cb->isRenderView()) return false; if (cb->isOutOfFlowPositioned() && !cb->style()->logicalTop().isAuto() && !cb->style()->logicalBottom().isAuto()) return false; // If the height of the containing block computes to 'auto', then it hasn't been 'specified explicitly'. return cb->hasAutoHeightOrContainingBlockWithAutoHeight(); }