Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  * Copyright (C) 2000 Dirk Mueller (mueller (at) kde.org)
      4  * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
      5  * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  *
     22  */
     23 
     24 #include "config.h"
     25 #include "core/rendering/RenderReplaced.h"
     26 
     27 #include "RuntimeEnabledFeatures.h"
     28 #include "core/rendering/GraphicsContextAnnotator.h"
     29 #include "core/rendering/LayoutRectRecorder.h"
     30 #include "core/rendering/LayoutRepainter.h"
     31 #include "core/rendering/RenderBlock.h"
     32 #include "core/rendering/RenderImage.h"
     33 #include "core/rendering/RenderLayer.h"
     34 #include "core/rendering/RenderView.h"
     35 #include "platform/graphics/GraphicsContext.h"
     36 
     37 using namespace std;
     38 
     39 namespace WebCore {
     40 
     41 const int cDefaultWidth = 300;
     42 const int cDefaultHeight = 150;
     43 
     44 RenderReplaced::RenderReplaced(Element* element)
     45     : RenderBox(element)
     46     , m_intrinsicSize(cDefaultWidth, cDefaultHeight)
     47 {
     48     setReplaced(true);
     49 }
     50 
     51 RenderReplaced::RenderReplaced(Element* element, const LayoutSize& intrinsicSize)
     52     : RenderBox(element)
     53     , m_intrinsicSize(intrinsicSize)
     54 {
     55     setReplaced(true);
     56 }
     57 
     58 RenderReplaced::~RenderReplaced()
     59 {
     60 }
     61 
     62 void RenderReplaced::willBeDestroyed()
     63 {
     64     if (!documentBeingDestroyed() && parent())
     65         parent()->dirtyLinesFromChangedChild(this);
     66 
     67     RenderBox::willBeDestroyed();
     68 }
     69 
     70 void RenderReplaced::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
     71 {
     72     RenderBox::styleDidChange(diff, oldStyle);
     73 
     74     bool hadStyle = (oldStyle != 0);
     75     float oldZoom = hadStyle ? oldStyle->effectiveZoom() : RenderStyle::initialZoom();
     76     if (style() && style()->effectiveZoom() != oldZoom)
     77         intrinsicSizeChanged();
     78 }
     79 
     80 void RenderReplaced::layout()
     81 {
     82     ASSERT(needsLayout());
     83 
     84     LayoutRectRecorder recorder(*this);
     85     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
     86 
     87     setHeight(minimumReplacedHeight());
     88 
     89     updateLogicalWidth();
     90     updateLogicalHeight();
     91 
     92     m_overflow.clear();
     93     addVisualEffectOverflow();
     94     updateLayerTransform();
     95     invalidateBackgroundObscurationStatus();
     96 
     97     repainter.repaintAfterLayout();
     98     clearNeedsLayout();
     99 }
    100 
    101 void RenderReplaced::intrinsicSizeChanged()
    102 {
    103     int scaledWidth = static_cast<int>(cDefaultWidth * style()->effectiveZoom());
    104     int scaledHeight = static_cast<int>(cDefaultHeight * style()->effectiveZoom());
    105     m_intrinsicSize = IntSize(scaledWidth, scaledHeight);
    106     setNeedsLayoutAndPrefWidthsRecalc();
    107 }
    108 
    109 void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    110 {
    111     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
    112 
    113     if (!shouldPaint(paintInfo, paintOffset))
    114         return;
    115 
    116     LayoutPoint adjustedPaintOffset = paintOffset + location();
    117 
    118     if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
    119         paintBoxDecorations(paintInfo, adjustedPaintOffset);
    120 
    121     if (paintInfo.phase == PaintPhaseMask) {
    122         paintMask(paintInfo, adjustedPaintOffset);
    123         return;
    124     }
    125 
    126     if (paintInfo.phase == PaintPhaseClippingMask && (!hasLayer() || !layer()->hasCompositedClippingMask()))
    127         return;
    128 
    129     LayoutRect paintRect = LayoutRect(adjustedPaintOffset, size());
    130     if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
    131         paintOutline(paintInfo, paintRect);
    132 
    133     if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !canHaveChildren() && paintInfo.phase != PaintPhaseClippingMask)
    134         return;
    135 
    136     if (!paintInfo.shouldPaintWithinRoot(this))
    137         return;
    138 
    139     bool drawSelectionTint = selectionState() != SelectionNone && !document().printing();
    140     if (paintInfo.phase == PaintPhaseSelection) {
    141         if (selectionState() == SelectionNone)
    142             return;
    143         drawSelectionTint = false;
    144     }
    145 
    146     bool completelyClippedOut = false;
    147     if (style()->hasBorderRadius()) {
    148         LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size());
    149 
    150         if (borderRect.isEmpty())
    151             completelyClippedOut = true;
    152         else {
    153             // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
    154             paintInfo.context->save();
    155             RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(paintRect,
    156                 paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true);
    157             clipRoundedInnerRect(paintInfo.context, paintRect, roundedInnerRect);
    158         }
    159     }
    160 
    161     if (!completelyClippedOut) {
    162         if (paintInfo.phase == PaintPhaseClippingMask) {
    163             paintClippingMask(paintInfo, adjustedPaintOffset);
    164         } else {
    165             paintReplaced(paintInfo, adjustedPaintOffset);
    166         }
    167 
    168         if (style()->hasBorderRadius())
    169             paintInfo.context->restore();
    170     }
    171 
    172     // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of
    173     // surrounding content.
    174     if (drawSelectionTint) {
    175         LayoutRect selectionPaintingRect = localSelectionRect();
    176         selectionPaintingRect.moveBy(adjustedPaintOffset);
    177         paintInfo.context->fillRect(pixelSnappedIntRect(selectionPaintingRect), selectionBackgroundColor());
    178     }
    179 }
    180 
    181 bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    182 {
    183     if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline
    184         && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask && paintInfo.phase != PaintPhaseClippingMask)
    185         return false;
    186 
    187     if (!paintInfo.shouldPaintWithinRoot(this))
    188         return false;
    189 
    190     // if we're invisible or haven't received a layout yet, then just bail.
    191     if (style()->visibility() != VISIBLE)
    192         return false;
    193 
    194     LayoutPoint adjustedPaintOffset = paintOffset + location();
    195 
    196     // Early exit if the element touches the edges.
    197     LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y();
    198     LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY();
    199     if (isSelected() && m_inlineBoxWrapper) {
    200         LayoutUnit selTop = paintOffset.y() + m_inlineBoxWrapper->root()->selectionTop();
    201         LayoutUnit selBottom = paintOffset.y() + selTop + m_inlineBoxWrapper->root()->selectionHeight();
    202         top = min(selTop, top);
    203         bottom = max(selBottom, bottom);
    204     }
    205 
    206     LayoutRect localRepaintRect = paintInfo.rect;
    207     localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase));
    208     if (adjustedPaintOffset.x() + visualOverflowRect().x() >= localRepaintRect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= localRepaintRect.x())
    209         return false;
    210 
    211     if (top >= localRepaintRect.maxY() || bottom <= localRepaintRect.y())
    212         return false;
    213 
    214     return true;
    215 }
    216 
    217 static inline RenderBlock* firstContainingBlockWithLogicalWidth(const RenderReplaced* replaced)
    218 {
    219     // We have to lookup the containing block, which has an explicit width, which must not be equal to our direct containing block.
    220     // If the embedded document appears _after_ we performed the initial layout, our intrinsic size is 300x150. If our containing
    221     // block doesn't provide an explicit width, it's set to the 300 default, coming from the initial layout run.
    222     RenderBlock* containingBlock = replaced->containingBlock();
    223     if (!containingBlock)
    224         return 0;
    225 
    226     for (; !containingBlock->isRenderView() && !containingBlock->isBody(); containingBlock = containingBlock->containingBlock()) {
    227         if (containingBlock->style()->logicalWidth().isSpecified())
    228             return containingBlock;
    229     }
    230 
    231     return 0;
    232 }
    233 
    234 bool RenderReplaced::hasReplacedLogicalWidth() const
    235 {
    236     if (style()->logicalWidth().isSpecified())
    237         return true;
    238 
    239     if (style()->logicalWidth().isAuto())
    240         return false;
    241 
    242     return firstContainingBlockWithLogicalWidth(this);
    243 }
    244 
    245 bool RenderReplaced::hasReplacedLogicalHeight() const
    246 {
    247     if (style()->logicalHeight().isAuto())
    248         return false;
    249 
    250     if (style()->logicalHeight().isSpecified()) {
    251         if (hasAutoHeightOrContainingBlockWithAutoHeight())
    252             return false;
    253         return true;
    254     }
    255 
    256     if (style()->logicalHeight().isIntrinsic())
    257         return true;
    258 
    259     return false;
    260 }
    261 
    262 bool RenderReplaced::needsPreferredWidthsRecalculation() const
    263 {
    264     // If the height is a percentage and the width is auto, then the containingBlocks's height changing can cause
    265     // this node to change it's preferred width because it maintains aspect ratio.
    266     return hasRelativeLogicalHeight() && style()->logicalWidth().isAuto() && !hasAutoHeightOrContainingBlockWithAutoHeight();
    267 }
    268 
    269 static inline bool rendererHasAspectRatio(const RenderObject* renderer)
    270 {
    271     ASSERT(renderer);
    272     return renderer->isImage() || renderer->isCanvas() || renderer->isVideo();
    273 }
    274 
    275 void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& constrainedSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const
    276 {
    277     FloatSize intrinsicSize;
    278     if (contentRenderer) {
    279         contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
    280         if (intrinsicRatio)
    281             ASSERT(!isPercentageIntrinsicSize);
    282 
    283         // Handle zoom & vertical writing modes here, as the embedded document doesn't know about them.
    284         if (!isPercentageIntrinsicSize) {
    285             intrinsicSize.scale(style()->effectiveZoom());
    286             if (isRenderImage())
    287                 intrinsicSize.scale(toRenderImage(this)->imageDevicePixelRatio());
    288         }
    289 
    290         if (rendererHasAspectRatio(this) && isPercentageIntrinsicSize)
    291             intrinsicRatio = 1;
    292 
    293         // Update our intrinsic size to match what the content renderer has computed, so that when we
    294         // constrain the size below, the correct intrinsic size will be obtained for comparison against
    295         // min and max widths.
    296         if (intrinsicRatio && !isPercentageIntrinsicSize && !intrinsicSize.isEmpty())
    297             m_intrinsicSize = LayoutSize(intrinsicSize);
    298 
    299         if (!isHorizontalWritingMode()) {
    300             if (intrinsicRatio)
    301                 intrinsicRatio = 1 / intrinsicRatio;
    302             intrinsicSize = intrinsicSize.transposedSize();
    303         }
    304     } else {
    305         computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
    306         if (intrinsicRatio) {
    307             ASSERT(!isPercentageIntrinsicSize);
    308             if (!intrinsicSize.isEmpty())
    309                 m_intrinsicSize = LayoutSize(isHorizontalWritingMode() ? intrinsicSize : intrinsicSize.transposedSize());
    310         }
    311     }
    312 
    313     // Now constrain the intrinsic size along each axis according to minimum and maximum width/heights along the
    314     // opposite axis. So for example a maximum width that shrinks our width will result in the height we compute here
    315     // having to shrink in order to preserve the aspect ratio. Because we compute these values independently along
    316     // each axis, the final returned size may in fact not preserve the aspect ratio.
    317     // FIXME: In the long term, it might be better to just return this code more to the way it used to be before this
    318     // function was added, since all it has done is make the code more unclear.
    319     constrainedSize = intrinsicSize;
    320     if (intrinsicRatio && !isPercentageIntrinsicSize && !intrinsicSize.isEmpty() && style()->logicalWidth().isAuto() && style()->logicalHeight().isAuto()) {
    321         // We can't multiply or divide by 'intrinsicRatio' here, it breaks tests, like fast/images/zoomed-img-size.html, which
    322         // can only be fixed once subpixel precision is available for things like intrinsicWidth/Height - which include zoom!
    323         constrainedSize.setWidth(RenderBox::computeReplacedLogicalHeight() * intrinsicSize.width() / intrinsicSize.height());
    324         constrainedSize.setHeight(RenderBox::computeReplacedLogicalWidth() * intrinsicSize.height() / intrinsicSize.width());
    325     }
    326 }
    327 
    328 LayoutRect RenderReplaced::replacedContentRect(const LayoutSize* overriddenIntrinsicSize) const
    329 {
    330     LayoutRect contentRect = contentBoxRect();
    331     ObjectFit objectFit = style()->objectFit();
    332 
    333     if (objectFit == ObjectFitFill && style()->objectPosition() == RenderStyle::initialObjectPosition()) {
    334         if (!isVideo() || RuntimeEnabledFeatures::objectFitPositionEnabled())
    335             return contentRect;
    336         objectFit = ObjectFitContain;
    337     }
    338 
    339     LayoutSize intrinsicSize = overriddenIntrinsicSize ? *overriddenIntrinsicSize : this->intrinsicSize();
    340     if (!intrinsicSize.width() || !intrinsicSize.height())
    341         return contentRect;
    342 
    343     LayoutRect finalRect = contentRect;
    344     switch (objectFit) {
    345     case ObjectFitContain:
    346     case ObjectFitScaleDown:
    347     case ObjectFitCover:
    348         finalRect.setSize(finalRect.size().fitToAspectRatio(intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink));
    349         if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width())
    350             break;
    351         // fall through
    352     case ObjectFitNone:
    353         finalRect.setSize(intrinsicSize);
    354         break;
    355     case ObjectFitFill:
    356         break;
    357     default:
    358         ASSERT_NOT_REACHED();
    359     }
    360 
    361     LayoutUnit xOffset = minimumValueForLength(style()->objectPosition().x(), contentRect.width() - finalRect.width(), view());
    362     LayoutUnit yOffset = minimumValueForLength(style()->objectPosition().y(), contentRect.height() - finalRect.height(), view());
    363     finalRect.move(xOffset, yOffset);
    364 
    365     return finalRect;
    366 }
    367 
    368 void RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const
    369 {
    370     // If there's an embeddedContentBox() of a remote, referenced document available, this code-path should never be used.
    371     ASSERT(!embeddedContentBox());
    372     isPercentageIntrinsicSize = false;
    373     intrinsicSize = FloatSize(intrinsicLogicalWidth(), intrinsicLogicalHeight());
    374 
    375     // Figure out if we need to compute an intrinsic ratio.
    376     if (intrinsicSize.isEmpty() || !rendererHasAspectRatio(this))
    377         return;
    378 
    379     intrinsicRatio = intrinsicSize.width() / intrinsicSize.height();
    380 }
    381 
    382 LayoutUnit RenderReplaced::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
    383 {
    384     if (style()->logicalWidth().isSpecified() || style()->logicalWidth().isIntrinsic())
    385         return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred);
    386 
    387     RenderBox* contentRenderer = embeddedContentBox();
    388 
    389     // 10.3.2 Inline, replaced elements: http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-width
    390     bool isPercentageIntrinsicSize = false;
    391     double intrinsicRatio = 0;
    392     FloatSize constrainedSize;
    393     computeAspectRatioInformationForRenderBox(contentRenderer, constrainedSize, intrinsicRatio, isPercentageIntrinsicSize);
    394 
    395     if (style()->logicalWidth().isAuto()) {
    396         bool heightIsAuto = style()->logicalHeight().isAuto();
    397         bool hasIntrinsicWidth = !isPercentageIntrinsicSize && constrainedSize.width() > 0;
    398 
    399         // 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'.
    400         if (heightIsAuto && hasIntrinsicWidth)
    401             return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), shouldComputePreferred);
    402 
    403         bool hasIntrinsicHeight = !isPercentageIntrinsicSize && constrainedSize.height() > 0;
    404         if (intrinsicRatio || isPercentageIntrinsicSize) {
    405             // 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;
    406             // 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
    407             // of 'width' is: (used height) * (intrinsic ratio)
    408             if (intrinsicRatio && ((heightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !heightIsAuto)) {
    409                 LayoutUnit logicalHeight = computeReplacedLogicalHeight();
    410                 return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(round(logicalHeight * intrinsicRatio)), shouldComputePreferred);
    411             }
    412 
    413             // 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
    414             // '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
    415             // the used value of 'width' is calculated from the constraint equation used for block-level, non-replaced elements in normal flow.
    416             if (heightIsAuto && !hasIntrinsicWidth && !hasIntrinsicHeight) {
    417                 // The aforementioned 'constraint equation' used for block-level, non-replaced elements in normal flow:
    418                 // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
    419                 LayoutUnit logicalWidth;
    420                 if (RenderBlock* blockWithWidth = firstContainingBlockWithLogicalWidth(this))
    421                     logicalWidth = blockWithWidth->computeReplacedLogicalWidthRespectingMinMaxWidth(blockWithWidth->computeReplacedLogicalWidthUsing(blockWithWidth->style()->logicalWidth()), shouldComputePreferred);
    422                 else
    423                     logicalWidth = containingBlock()->availableLogicalWidth();
    424 
    425                 // This solves above equation for 'width' (== logicalWidth).
    426                 LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), logicalWidth);
    427                 LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), logicalWidth);
    428                 logicalWidth = max<LayoutUnit>(0, logicalWidth - (marginStart + marginEnd + (width() - clientWidth())));
    429                 if (isPercentageIntrinsicSize)
    430                     logicalWidth = logicalWidth * constrainedSize.width() / 100;
    431                 return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth, shouldComputePreferred);
    432             }
    433         }
    434 
    435         // 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'.
    436         if (hasIntrinsicWidth)
    437             return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), shouldComputePreferred);
    438 
    439         // 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
    440         // 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.
    441         // Note: We fall through and instead return intrinsicLogicalWidth() here - to preserve existing WebKit behavior, which might or might not be correct, or desired.
    442         // 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)
    443         // has no intrinsic size, which is wrong per CSS 2.1, but matches our behavior since a long time.
    444     }
    445 
    446     return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), shouldComputePreferred);
    447 }
    448 
    449 LayoutUnit RenderReplaced::computeReplacedLogicalHeight() const
    450 {
    451     // 10.5 Content height: the 'height' property: http://www.w3.org/TR/CSS21/visudet.html#propdef-height
    452     if (hasReplacedLogicalHeight())
    453         return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight()));
    454 
    455     RenderBox* contentRenderer = embeddedContentBox();
    456 
    457     // 10.6.2 Inline, replaced elements: http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-height
    458     bool isPercentageIntrinsicSize = false;
    459     double intrinsicRatio = 0;
    460     FloatSize constrainedSize;
    461     computeAspectRatioInformationForRenderBox(contentRenderer, constrainedSize, intrinsicRatio, isPercentageIntrinsicSize);
    462 
    463     bool widthIsAuto = style()->logicalWidth().isAuto();
    464     bool hasIntrinsicHeight = !isPercentageIntrinsicSize && constrainedSize.height() > 0;
    465 
    466     // 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'.
    467     if (widthIsAuto && hasIntrinsicHeight)
    468         return computeReplacedLogicalHeightRespectingMinMaxHeight(constrainedSize.height());
    469 
    470     // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is:
    471     // (used width) / (intrinsic ratio)
    472     if (intrinsicRatio)
    473         return computeReplacedLogicalHeightRespectingMinMaxHeight(roundToInt(round(availableLogicalWidth() / intrinsicRatio)));
    474 
    475     // 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'.
    476     if (hasIntrinsicHeight)
    477         return computeReplacedLogicalHeightRespectingMinMaxHeight(constrainedSize.height());
    478 
    479     // 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
    480     // 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.
    481     return computeReplacedLogicalHeightRespectingMinMaxHeight(intrinsicLogicalHeight());
    482 }
    483 
    484 void RenderReplaced::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
    485 {
    486     minLogicalWidth = maxLogicalWidth = intrinsicLogicalWidth();
    487 }
    488 
    489 void RenderReplaced::computePreferredLogicalWidths()
    490 {
    491     ASSERT(preferredLogicalWidthsDirty());
    492 
    493     // We cannot resolve any percent logical width here as the available logical
    494     // width may not be set on our containing block.
    495     if (style()->logicalWidth().isPercent())
    496         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
    497     else
    498         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeReplacedLogicalWidth(ComputePreferred);
    499 
    500     RenderStyle* styleToUse = style();
    501     if (styleToUse->logicalWidth().isPercent() || styleToUse->logicalMaxWidth().isPercent() || hasRelativeIntrinsicLogicalWidth())
    502         m_minPreferredLogicalWidth = 0;
    503 
    504     if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
    505         m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
    506         m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
    507     }
    508 
    509     if (styleToUse->logicalMaxWidth().isFixed()) {
    510         m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
    511         m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
    512     }
    513 
    514     LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
    515     m_minPreferredLogicalWidth += borderAndPadding;
    516     m_maxPreferredLogicalWidth += borderAndPadding;
    517 
    518     clearPreferredLogicalWidthsDirty();
    519 }
    520 
    521 PositionWithAffinity RenderReplaced::positionForPoint(const LayoutPoint& point)
    522 {
    523     // FIXME: This code is buggy if the replaced element is relative positioned.
    524     InlineBox* box = inlineBoxWrapper();
    525     RootInlineBox* rootBox = box ? box->root() : 0;
    526 
    527     LayoutUnit top = rootBox ? rootBox->selectionTop() : logicalTop();
    528     LayoutUnit bottom = rootBox ? rootBox->selectionBottom() : logicalBottom();
    529 
    530     LayoutUnit blockDirectionPosition = isHorizontalWritingMode() ? point.y() + y() : point.x() + x();
    531     LayoutUnit lineDirectionPosition = isHorizontalWritingMode() ? point.x() + x() : point.y() + y();
    532 
    533     if (blockDirectionPosition < top)
    534         return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM); // coordinates are above
    535 
    536     if (blockDirectionPosition >= bottom)
    537         return createPositionWithAffinity(caretMaxOffset(), DOWNSTREAM); // coordinates are below
    538 
    539     if (node()) {
    540         if (lineDirectionPosition <= logicalLeft() + (logicalWidth() / 2))
    541             return createPositionWithAffinity(0, DOWNSTREAM);
    542         return createPositionWithAffinity(1, DOWNSTREAM);
    543     }
    544 
    545     return RenderBox::positionForPoint(point);
    546 }
    547 
    548 LayoutRect RenderReplaced::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent)
    549 {
    550     ASSERT(!needsLayout());
    551 
    552     if (!isSelected())
    553         return LayoutRect();
    554 
    555     LayoutRect rect = localSelectionRect();
    556     if (clipToVisibleContent)
    557         computeRectForRepaint(repaintContainer, rect);
    558     else
    559         rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
    560 
    561     return rect;
    562 }
    563 
    564 LayoutRect RenderReplaced::localSelectionRect(bool checkWhetherSelected) const
    565 {
    566     if (checkWhetherSelected && !isSelected())
    567         return LayoutRect();
    568 
    569     if (!m_inlineBoxWrapper)
    570         // We're a block-level replaced element.  Just return our own dimensions.
    571         return LayoutRect(LayoutPoint(), size());
    572 
    573     RootInlineBox* root = m_inlineBoxWrapper->root();
    574     LayoutUnit newLogicalTop = root->block()->style()->isFlippedBlocksWritingMode() ? m_inlineBoxWrapper->logicalBottom() - root->selectionBottom() : root->selectionTop() - m_inlineBoxWrapper->logicalTop();
    575     if (root->block()->style()->isHorizontalWritingMode())
    576         return LayoutRect(0, newLogicalTop, width(), root->selectionHeight());
    577     return LayoutRect(newLogicalTop, 0, root->selectionHeight(), height());
    578 }
    579 
    580 void RenderReplaced::setSelectionState(SelectionState state)
    581 {
    582     // The selection state for our containing block hierarchy is updated by the base class call.
    583     RenderBox::setSelectionState(state);
    584 
    585     if (m_inlineBoxWrapper && canUpdateSelectionOnRootLineBoxes())
    586         if (RootInlineBox* root = m_inlineBoxWrapper->root())
    587             root->setHasSelectedChildren(isSelected());
    588 }
    589 
    590 bool RenderReplaced::isSelected() const
    591 {
    592     SelectionState s = selectionState();
    593     if (s == SelectionNone)
    594         return false;
    595     if (s == SelectionInside)
    596         return true;
    597 
    598     int selectionStart, selectionEnd;
    599     selectionStartEnd(selectionStart, selectionEnd);
    600     if (s == SelectionStart)
    601         return selectionStart == 0;
    602 
    603     int end = node()->hasChildNodes() ? node()->childNodeCount() : 1;
    604     if (s == SelectionEnd)
    605         return selectionEnd == end;
    606     if (s == SelectionBoth)
    607         return selectionStart == 0 && selectionEnd == end;
    608 
    609     ASSERT(0);
    610     return false;
    611 }
    612 
    613 LayoutRect RenderReplaced::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
    614 {
    615     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
    616         return LayoutRect();
    617 
    618     // The selectionRect can project outside of the overflowRect, so take their union
    619     // for repainting to avoid selection painting glitches.
    620     LayoutRect r = unionRect(localSelectionRect(false), visualOverflowRect());
    621 
    622     RenderView* v = view();
    623     if (v) {
    624         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
    625         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
    626         r.move(v->layoutDelta());
    627     }
    628 
    629     if (style()) {
    630         if (v)
    631             r.inflate(style()->outlineSize());
    632     }
    633     computeRectForRepaint(repaintContainer, r);
    634     return r;
    635 }
    636 
    637 }
    638