diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderReplaced.cpp')
| -rw-r--r-- | Source/WebCore/rendering/RenderReplaced.cpp | 229 |
1 files changed, 136 insertions, 93 deletions
diff --git a/Source/WebCore/rendering/RenderReplaced.cpp b/Source/WebCore/rendering/RenderReplaced.cpp index 017dd678c..82c344866 100644 --- a/Source/WebCore/rendering/RenderReplaced.cpp +++ b/Source/WebCore/rendering/RenderReplaced.cpp @@ -23,8 +23,10 @@ #include "config.h" #include "RenderReplaced.h" +#include "Frame.h" #include "GraphicsContext.h" #include "LayoutRepainter.h" +#include "Page.h" #include "RenderBlock.h" #include "RenderLayer.h" #include "RenderTheme.h" @@ -122,7 +124,7 @@ void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) paintOutline(paintInfo.context, paintRect); - if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection) + if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !canHaveChildren()) return; if (!paintInfo.shouldPaintWithinRoot(this)) @@ -135,6 +137,11 @@ void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) drawSelectionTint = false; } + if (Frame* frame = this->frame()) { + if (Page* page = frame->page()) + page->addRelevantRepaintedObject(this, paintInfo.rect); + } + bool completelyClippedOut = false; if (style()->hasBorderRadius()) { LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size()); @@ -216,85 +223,137 @@ int RenderReplaced::computeIntrinsicLogicalHeight(RenderBox* contentRenderer) co return contentRenderer->computeReplacedLogicalHeightRespectingMinMaxHeight(contentRenderer->computeReplacedLogicalHeightUsing(contentRenderer->style()->logicalHeight())); } +static inline RenderBlock* firstContainingBlockWithLogicalWidth(const RenderReplaced* replaced) +{ + // We have to lookup the containing block, which has an explicit width, which must not be equal to our direct containing block. + // If the embedded document appears _after_ we performed the initial layout, our intrinsic size is 300x150. If our containing + // block doesn't provide an explicit width, it's set to the 300 default, coming from the initial layout run. + RenderBlock* containingBlock = replaced->containingBlock(); + if (!containingBlock) + return 0; + + for (; !containingBlock->isRenderView() && !containingBlock->isBody(); containingBlock = containingBlock->containingBlock()) { + if (containingBlock->style()->logicalWidth().isSpecified()) + return containingBlock; + } + + return 0; +} + +bool RenderReplaced::hasReplacedLogicalWidth() const +{ + if (style()->logicalWidth().isSpecified()) + return true; + + if (style()->logicalWidth().isAuto()) + return false; + + return firstContainingBlockWithLogicalWidth(this); +} + +static inline bool hasAutoHeightOrContainingBlockWithAutoHeight(const RenderReplaced* replaced) +{ + Length logicalHeightLength = replaced->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() || replaced->isPositioned() || replaced->document()->inQuirksMode()) + return false; + + for (RenderBlock* cb = replaced->containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { + if (cb->isTableCell() || (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()))) + return false; + } + + return true; +} + +bool RenderReplaced::hasReplacedLogicalHeight() const +{ + if (style()->logicalHeight().isAuto()) + return false; + + if (style()->logicalHeight().isSpecified()) { + if (hasAutoHeightOrContainingBlockWithAutoHeight(this)) + return false; + return true; + } + + return false; +} + LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) const { if (style()->logicalWidth().isSpecified()) return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), includeMaxWidth); RenderBox* contentRenderer = embeddedContentBox(); - RenderStyle* contentRenderStyle = 0; // 10.3.2 Inline, replaced elements: http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-width bool isPercentageIntrinsicSize = false; - FloatSize intrinsicRatio; - if (contentRenderer) { - contentRenderer->computeIntrinsicRatioInformation(intrinsicRatio, isPercentageIntrinsicSize); - contentRenderStyle = contentRenderer->style(); - ASSERT(contentRenderStyle); - } else - computeIntrinsicRatioInformation(intrinsicRatio, isPercentageIntrinsicSize); + 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 || (contentRenderer && contentRenderStyle->logicalWidth().isFixed()); + 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) - return computeIntrinsicLogicalWidth(contentRenderer, includeMaxWidth); - - bool hasIntrinsicHeight = m_hasIntrinsicSize || (contentRenderer && contentRenderStyle->logicalHeight().isFixed()); - if (!intrinsicRatio.isEmpty()) { + 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 ((heightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !heightIsAuto) { - if (heightIsAuto) { - if (contentRenderer) { - LayoutUnit logicalHeight = contentRenderer->computeReplacedLogicalHeightUsing(contentRenderStyle->logicalHeight()); - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - return contentRenderer->computeReplacedLogicalWidthRespectingMinMaxWidth(static_cast<int>(ceilf(logicalHeight * intrinsicRatio.width() / intrinsicRatio.height()))); - } - } else { - LayoutUnit logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight()); - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - return computeReplacedLogicalWidthRespectingMinMaxWidth(static_cast<int>(ceilf(logicalHeight * intrinsicRatio.width() / intrinsicRatio.height()))); - } + 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. - RenderBlock* containingBlock = this->containingBlock(); - if (heightIsAuto && !hasIntrinsicWidth && !hasIntrinsicHeight && contentRenderer && containingBlock) { + 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(); - // We have to lookup the containing block, which has an explicit width, which must not be equal to our direct containing block. - // If the embedded document appears _after_ we performed the initial layout, our intrinsic size is 300x150. If our containing - // block doesn't provide an explicit width, it's set to the 300 default, coming from the initial layout run. - bool foundExplicitWidth = false; - for (; !containingBlock->isRenderView() && !containingBlock->isBody(); containingBlock = containingBlock->containingBlock()) { - if (containingBlock->style()->logicalWidth().isSpecified()) { - foundExplicitWidth = true; - break; - } - } - // This solves above equation for 'width' (== logicalWidth). - LayoutUnit logicalWidth = foundExplicitWidth ? computeIntrinsicLogicalWidth(containingBlock, false) : containingBlock->availableLogicalWidth(); LayoutUnit marginStart = style()->marginStart().calcMinValue(logicalWidth); LayoutUnit marginEnd = style()->marginEnd().calcMinValue(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<int>(ceilf(logicalWidth * intrinsicRatio.width() / 100)); + 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) - return computeIntrinsicLogicalWidth(contentRenderer, includeMaxWidth); + 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. @@ -304,69 +363,53 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), includeMaxWidth); } -bool RenderReplaced::logicalHeightIsAuto() 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() || isPositioned() || document()->inQuirksMode()) - return false; - - for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { - if (cb->isTableCell() || (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()))) - return false; - } - - return true; -} - LayoutUnit RenderReplaced::computeReplacedLogicalHeight() const { // 10.5 Content height: the 'height' property: http://www.w3.org/TR/CSS21/visudet.html#propdef-height - bool heightIsAuto = logicalHeightIsAuto(); - if (style()->logicalHeight().isSpecified() && !heightIsAuto) + if (hasReplacedLogicalHeight()) return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight())); RenderBox* contentRenderer = embeddedContentBox(); - RenderStyle* contentRenderStyle = 0; // 10.6.2 Inline, replaced elements: http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-height bool isPercentageIntrinsicSize = false; - FloatSize intrinsicRatio; - if (contentRenderer) { - contentRenderer->computeIntrinsicRatioInformation(intrinsicRatio, isPercentageIntrinsicSize); - contentRenderStyle = contentRenderer->style(); - ASSERT(contentRenderStyle); + double intrinsicRatio = 0; + FloatSize intrinsicSize; + if (contentRenderer) + contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); + else + computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); + + if (intrinsicRatio && !isHorizontalWritingMode()) + intrinsicRatio = 1 / intrinsicRatio; + + bool widthIsAuto = style()->logicalWidth().isAuto(); + bool hasIntrinsicHeight = m_hasIntrinsicSize || (!isPercentageIntrinsicSize && intrinsicSize.height() > 0); + + // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic height, then that intrinsic height is the used value of 'height'. + if (widthIsAuto && hasIntrinsicHeight) { + if (m_hasIntrinsicSize) + return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight()); + return static_cast<LayoutUnit>(intrinsicSize.height() * style()->effectiveZoom()); } - if (heightIsAuto) { - bool widthIsAuto = style()->logicalWidth().isAuto(); - bool hasIntrinsicHeight = m_hasIntrinsicSize || (contentRenderer && contentRenderStyle->logicalHeight().isFixed()); + // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is: + // (used width) / (intrinsic ratio) + if (intrinsicRatio && !isPercentageIntrinsicSize) { + // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 + return computeReplacedLogicalHeightRespectingMinMaxHeight(round(availableLogicalWidth() / intrinsicRatio)); + } - // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic height, then that intrinsic height is the used value of 'height'. - if (widthIsAuto && hasIntrinsicHeight) - return computeIntrinsicLogicalHeight(contentRenderer); - - // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is: - // (used width) / (intrinsic ratio) - if (!intrinsicRatio.isEmpty() && !isPercentageIntrinsicSize) - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - return computeReplacedLogicalHeightRespectingMinMaxHeight(static_cast<int>(ceilf(availableLogicalWidth() * intrinsicRatio.height() / intrinsicRatio.width()))); - - // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'. - if (hasIntrinsicHeight) - return computeIntrinsicLogicalHeight(contentRenderer); - - // Otherwise, if 'height' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'height' must be set to the height - // of the largest rectangle that has a 2:1 ratio, has a height not greater than 150px, and has a width not greater than the device width. - return computeReplacedLogicalHeightRespectingMinMaxHeight(cDefaultHeight); + // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'. + if (hasIntrinsicHeight) { + if (m_hasIntrinsicSize) + return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight()); + return static_cast<LayoutUnit>(intrinsicSize.height() * style()->effectiveZoom()); } - return computeReplacedLogicalHeightRespectingMinMaxHeight(intrinsicLogicalHeight()); + // Otherwise, if 'height' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'height' must be set to the height + // of the largest rectangle that has a 2:1 ratio, has a height not greater than 150px, and has a width not greater than the device width. + return computeReplacedLogicalHeightRespectingMinMaxHeight(cDefaultHeight); } int RenderReplaced::calcAspectRatioLogicalWidth() const |
