2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
6 * (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
7 * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
8 * Copyright (C) 2010 Google Inc. All rights reserved.
9 * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
29 #include "core/rendering/RenderImage.h"
31 #include "HTMLNames.h"
32 #include "core/editing/FrameSelection.h"
33 #include "core/fetch/ImageResource.h"
34 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
35 #include "core/fetch/ResourceLoader.h"
36 #include "core/html/HTMLAreaElement.h"
37 #include "core/html/HTMLImageElement.h"
38 #include "core/html/HTMLInputElement.h"
39 #include "core/html/HTMLMapElement.h"
40 #include "core/inspector/InspectorInstrumentation.h"
41 #include "core/frame/Frame.h"
42 #include "core/rendering/HitTestResult.h"
43 #include "core/rendering/LayoutRectRecorder.h"
44 #include "core/rendering/PaintInfo.h"
45 #include "core/rendering/RenderView.h"
46 #include "core/svg/graphics/SVGImage.h"
47 #include "platform/fonts/Font.h"
48 #include "platform/fonts/FontCache.h"
49 #include "platform/graphics/GraphicsContext.h"
50 #include "platform/graphics/GraphicsContextStateSaver.h"
56 using namespace HTMLNames;
58 RenderImage::RenderImage(Element* element)
59 : RenderReplaced(element, IntSize())
60 , m_didIncrementVisuallyNonEmptyPixelCount(false)
61 , m_isGeneratedContent(false)
62 , m_imageDevicePixelRatio(1.0f)
65 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->addRenderObject(this);
68 RenderImage* RenderImage::createAnonymous(Document* document)
70 RenderImage* image = new RenderImage(0);
71 image->setDocumentForAnonymous(document);
75 RenderImage::~RenderImage()
77 ASSERT(m_imageResource);
78 m_imageResource->shutdown();
81 void RenderImage::setImageResource(PassOwnPtr<RenderImageResource> imageResource)
83 ASSERT(!m_imageResource);
84 m_imageResource = imageResource;
85 m_imageResource->initialize(this);
88 // If we'll be displaying either alt text or an image, add some padding.
89 static const unsigned short paddingWidth = 4;
90 static const unsigned short paddingHeight = 4;
92 // Alt text is restricted to this maximum size, in pixels. These are
93 // signed integers because they are compared with other signed values.
94 static const float maxAltTextWidth = 1024;
95 static const int maxAltTextHeight = 256;
97 IntSize RenderImage::imageSizeForError(ImageResource* newImage) const
99 ASSERT_ARG(newImage, newImage);
100 ASSERT_ARG(newImage, newImage->imageForRenderer(this));
103 if (newImage->willPaintBrokenImage()) {
104 float deviceScaleFactor = WebCore::deviceScaleFactor(frame());
105 pair<Image*, float> brokenImageAndImageScaleFactor = ImageResource::brokenImage(deviceScaleFactor);
106 imageSize = brokenImageAndImageScaleFactor.first->size();
107 imageSize.scale(1 / brokenImageAndImageScaleFactor.second);
109 imageSize = newImage->imageForRenderer(this)->size();
111 // imageSize() returns 0 for the error image. We need the true size of the
112 // error image, so we have to get it by grabbing image() directly.
113 return IntSize(paddingWidth + imageSize.width() * style()->effectiveZoom(), paddingHeight + imageSize.height() * style()->effectiveZoom());
116 // Sets the image height and width to fit the alt text. Returns true if the
117 // image size changed.
118 bool RenderImage::setImageSizeForAltText(ImageResource* newImage /* = 0 */)
121 if (newImage && newImage->imageForRenderer(this))
122 imageSize = imageSizeForError(newImage);
123 else if (!m_altText.isEmpty() || newImage) {
124 // If we'll be displaying either text or an image, add a little padding.
125 imageSize = IntSize(paddingWidth, paddingHeight);
128 // we have an alt and the user meant it (its not a text we invented)
129 if (!m_altText.isEmpty()) {
130 FontCachePurgePreventer fontCachePurgePreventer;
132 const Font& font = style()->font();
133 IntSize paddedTextSize(paddingWidth + min(ceilf(font.width(RenderBlockFlow::constructTextRun(this, font, m_altText, style()))), maxAltTextWidth), paddingHeight + min(font.fontMetrics().height(), maxAltTextHeight));
134 imageSize = imageSize.expandedTo(paddedTextSize);
137 if (imageSize == intrinsicSize())
140 setIntrinsicSize(imageSize);
144 void RenderImage::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
146 RenderReplaced::styleDidChange(diff, oldStyle);
149 void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
151 if (documentBeingDestroyed())
154 if (hasBoxDecorations() || hasMask())
155 RenderReplaced::imageChanged(newImage, rect);
157 if (!m_imageResource)
160 if (newImage != m_imageResource->imagePtr())
163 // Per the spec, we let the server-sent header override srcset/other sources of dpr.
164 // https://github.com/igrigorik/http-client-hints/blob/master/draft-grigorik-http-client-hints-01.txt#L255
165 if (m_imageResource->cachedImage() && m_imageResource->cachedImage()->hasDevicePixelRatioHeaderValue())
166 m_imageDevicePixelRatio = 1 / m_imageResource->cachedImage()->devicePixelRatioHeaderValue();
168 if (!m_didIncrementVisuallyNonEmptyPixelCount) {
169 // At a zoom level of 1 the image is guaranteed to have an integer size.
170 view()->frameView()->incrementVisuallyNonEmptyPixelCount(flooredIntSize(m_imageResource->imageSize(1.0f)));
171 m_didIncrementVisuallyNonEmptyPixelCount = true;
174 bool imageSizeChanged = false;
176 // Set image dimensions, taking into account the size of the alt text.
177 if (m_imageResource->errorOccurred() || !newImage)
178 imageSizeChanged = setImageSizeForAltText(m_imageResource->cachedImage());
180 imageDimensionsChanged(imageSizeChanged, rect);
183 bool RenderImage::updateIntrinsicSizeIfNeeded(const LayoutSize& newSize, bool imageSizeChanged)
185 if (newSize == intrinsicSize() && !imageSizeChanged)
187 if (m_imageResource->errorOccurred() || !m_imageResource->hasImage())
188 return imageSizeChanged;
189 setIntrinsicSize(newSize);
193 void RenderImage::updateInnerContentRect()
195 // Propagate container size to the image resource.
196 LayoutRect containerRect = replacedContentRect();
197 IntSize containerSize(containerRect.width(), containerRect.height());
198 if (!containerSize.isEmpty())
199 m_imageResource->setContainerSizeForRenderer(containerSize);
202 void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* rect)
204 bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(m_imageResource->intrinsicSize(style()->effectiveZoom()), imageSizeChanged);
206 // In the case of generated image content using :before/:after/content, we might not be
207 // in the render tree yet. In that case, we just need to update our intrinsic size.
208 // layout() will be called after we are inserted in the tree which will take care of
209 // what we are doing here.
210 if (!containingBlock())
213 bool shouldRepaint = true;
214 if (intrinsicSizeChanged) {
215 if (!preferredLogicalWidthsDirty())
216 setPreferredLogicalWidthsDirty();
218 bool hasOverrideSize = hasOverrideHeight() || hasOverrideWidth();
219 if (!hasOverrideSize && !imageSizeChanged) {
220 LogicalExtentComputedValues computedValues;
221 computeLogicalWidth(computedValues);
222 LayoutUnit newWidth = computedValues.m_extent;
223 computeLogicalHeight(height(), 0, computedValues);
224 LayoutUnit newHeight = computedValues.m_extent;
226 imageSizeChanged = width() != newWidth || height() != newHeight;
229 // FIXME: We only need to recompute the containing block's preferred size
230 // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing).
231 // There's no easy way to detect that shrink-to-fit is needed, always force a layout.
232 bool containingBlockNeedsToRecomputePreferredSize =
233 style()->logicalWidth().isPercent()
234 || style()->logicalMaxWidth().isPercent()
235 || style()->logicalMinWidth().isPercent();
237 if (imageSizeChanged || hasOverrideSize || containingBlockNeedsToRecomputePreferredSize) {
238 shouldRepaint = false;
239 if (!selfNeedsLayout())
244 if (everHadLayout() && !selfNeedsLayout()) {
245 // The inner content rectangle is calculated during layout, but may need an update now
246 // (unless the box has already been scheduled for layout). In order to calculate it, we
247 // may need values from the containing block, though, so make sure that we're not too
248 // early. It may be that layout hasn't even taken place once yet.
249 updateInnerContentRect();
253 LayoutRect repaintRect;
255 // The image changed rect is in source image coordinates (pre-zooming),
256 // so map from the bounds of the image to the contentsBox.
257 repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), m_imageResource->imageSize(1.0f)), contentBoxRect()));
258 // Guard against too-large changed rects.
259 repaintRect.intersect(contentBoxRect());
261 repaintRect = contentBoxRect();
264 // FIXME: We should not be allowing repaint during layout. crbug.com/339584
265 AllowRepaintScope scoper(frameView());
266 repaintRectangle(repaintRect);
269 // Tell any potential compositing layers that the image needs updating.
270 contentChanged(ImageChanged);
274 void RenderImage::notifyFinished(Resource* newImage)
276 if (!m_imageResource)
279 if (documentBeingDestroyed())
282 invalidateBackgroundObscurationStatus();
284 if (newImage == m_imageResource->cachedImage()) {
285 // tell any potential compositing layers
286 // that the image is done and they can reference it directly.
287 contentChanged(ImageChanged);
291 void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
293 LayoutUnit cWidth = contentWidth();
294 LayoutUnit cHeight = contentHeight();
295 LayoutUnit leftBorder = borderLeft();
296 LayoutUnit topBorder = borderTop();
297 LayoutUnit leftPad = paddingLeft();
298 LayoutUnit topPad = paddingTop();
300 GraphicsContext* context = paintInfo.context;
302 if (!m_imageResource->hasImage() || m_imageResource->errorOccurred()) {
303 if (paintInfo.phase == PaintPhaseSelection)
306 if (cWidth > 2 && cHeight > 2) {
307 const int borderWidth = 1;
309 // Draw an outline rect where the image should be.
310 context->setStrokeStyle(SolidStroke);
311 context->setStrokeColor(Color::lightGray);
312 context->setFillColor(Color::transparent);
313 context->drawRect(pixelSnappedIntRect(LayoutRect(paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight)));
315 bool errorPictureDrawn = false;
316 LayoutSize imageOffset;
317 // When calculating the usable dimensions, exclude the pixels of
318 // the ouline rect so the error image/alt text doesn't draw on it.
319 LayoutUnit usableWidth = cWidth - 2 * borderWidth;
320 LayoutUnit usableHeight = cHeight - 2 * borderWidth;
322 RefPtr<Image> image = m_imageResource->image();
324 if (m_imageResource->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) {
325 float deviceScaleFactor = WebCore::deviceScaleFactor(frame());
326 // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution.
327 pair<Image*, float> brokenImageAndImageScaleFactor = ImageResource::brokenImage(deviceScaleFactor);
328 image = brokenImageAndImageScaleFactor.first;
329 IntSize imageSize = image->size();
330 imageSize.scale(1 / brokenImageAndImageScaleFactor.second);
331 // Center the error image, accounting for border and padding.
332 LayoutUnit centerX = (usableWidth - imageSize.width()) / 2;
335 LayoutUnit centerY = (usableHeight - imageSize.height()) / 2;
338 imageOffset = LayoutSize(leftBorder + leftPad + centerX + borderWidth, topBorder + topPad + centerY + borderWidth);
339 context->drawImage(image.get(), pixelSnappedIntRect(LayoutRect(paintOffset + imageOffset, imageSize)), CompositeSourceOver, shouldRespectImageOrientation());
340 errorPictureDrawn = true;
343 if (!m_altText.isEmpty()) {
344 const Font& font = style()->font();
345 const FontMetrics& fontMetrics = font.fontMetrics();
346 LayoutUnit ascent = fontMetrics.ascent();
347 LayoutPoint textRectOrigin = paintOffset;
348 textRectOrigin.move(leftBorder + leftPad + (paddingWidth / 2) - borderWidth, topBorder + topPad + (paddingHeight / 2) - borderWidth);
349 LayoutPoint textOrigin(textRectOrigin.x(), textRectOrigin.y() + ascent);
351 // Only draw the alt text if it'll fit within the content box,
352 // and only if it fits above the error image.
353 TextRun textRun = RenderBlockFlow::constructTextRun(this, font, m_altText, style(), TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, DefaultTextRunFlags | RespectDirection);
354 LayoutUnit textWidth = font.width(textRun);
355 TextRunPaintInfo textRunPaintInfo(textRun);
356 textRunPaintInfo.bounds = FloatRect(textRectOrigin, FloatSize(textWidth, fontMetrics.height()));
357 context->setFillColor(resolveColor(CSSPropertyColor));
358 if (textRun.direction() == RTL) {
359 int availableWidth = cWidth - static_cast<int>(paddingWidth);
360 textOrigin.move(availableWidth - ceilf(textWidth), 0);
362 if (errorPictureDrawn) {
363 if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height())
364 context->drawBidiText(font, textRunPaintInfo, textOrigin);
365 } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height()) {
366 context->drawBidiText(font, textRunPaintInfo, textOrigin);
370 } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) {
371 RefPtr<Image> img = m_imageResource->image(cWidth, cHeight);
372 if (!img || img->isNull())
375 LayoutRect contentRect = contentBoxRect();
376 contentRect.moveBy(paintOffset);
377 LayoutRect paintRect = replacedContentRect();
378 paintRect.moveBy(paintOffset);
379 bool clip = !contentRect.contains(paintRect);
382 context->clip(contentRect);
385 paintIntoRect(context, paintRect);
392 void RenderImage::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
394 RenderReplaced::paint(paintInfo, paintOffset);
396 if (paintInfo.phase == PaintPhaseOutline)
397 paintAreaElementFocusRing(paintInfo);
400 void RenderImage::paintAreaElementFocusRing(PaintInfo& paintInfo)
402 Document& document = this->document();
404 if (document.printing() || !document.frame()->selection().isFocusedAndActive())
407 if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints())
410 Element* focusedElement = document.focusedElement();
411 if (!focusedElement || !focusedElement->hasTagName(areaTag))
414 HTMLAreaElement* areaElement = toHTMLAreaElement(focusedElement);
415 if (areaElement->imageElement() != node())
418 // Even if the theme handles focus ring drawing for entire elements, it won't do it for
419 // an area within an image, so we don't call RenderTheme::supportsFocusRing here.
421 Path path = areaElement->computePath(this);
425 RenderStyle* areaElementStyle = areaElement->computedStyle();
426 unsigned short outlineWidth = areaElementStyle->outlineWidth();
430 // FIXME: Clip path instead of context when Skia pathops is ready.
431 // https://crbug.com/251206
432 GraphicsContextStateSaver savedContext(*paintInfo.context);
433 paintInfo.context->clip(absoluteContentBox());
434 paintInfo.context->drawFocusRing(path, outlineWidth,
435 areaElementStyle->outlineOffset(),
436 resolveColor(areaElementStyle, CSSPropertyOutlineColor));
439 void RenderImage::areaElementFocusChanged(HTMLAreaElement* areaElement)
441 ASSERT(areaElement->imageElement() == node());
443 Path path = areaElement->computePath(this);
447 RenderStyle* areaElementStyle = areaElement->computedStyle();
448 unsigned short outlineWidth = areaElementStyle->outlineWidth();
450 IntRect repaintRect = enclosingIntRect(path.boundingRect());
451 repaintRect.moveBy(-absoluteContentBox().location());
452 repaintRect.inflate(outlineWidth);
454 repaintRectangle(repaintRect);
457 void RenderImage::paintIntoRect(GraphicsContext* context, const LayoutRect& rect)
459 IntRect alignedRect = pixelSnappedIntRect(rect);
460 if (!m_imageResource->hasImage() || m_imageResource->errorOccurred() || alignedRect.width() <= 0 || alignedRect.height() <= 0)
463 RefPtr<Image> img = m_imageResource->image(alignedRect.width(), alignedRect.height());
464 if (!img || img->isNull())
467 HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? toHTMLImageElement(node()) : 0;
468 CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
469 Image* image = m_imageResource->image().get();
470 bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size());
472 InspectorInstrumentation::willPaintImage(this);
473 context->drawImage(m_imageResource->image(alignedRect.width(), alignedRect.height()).get(), alignedRect, compositeOperator, shouldRespectImageOrientation(), useLowQualityScaling);
474 InspectorInstrumentation::didPaintImage(this);
477 bool RenderImage::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox*) const
479 if (!RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(bleedAvoidance))
482 return !const_cast<RenderImage*>(this)->backgroundIsKnownToBeObscured();
485 bool RenderImage::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned) const
487 if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
489 if (m_imageResource->cachedImage() && !m_imageResource->cachedImage()->isLoaded())
491 if (!contentBoxRect().contains(localRect))
493 EFillBox backgroundClip = style()->backgroundClip();
494 // Background paints under borders.
495 if (backgroundClip == BorderFillBox && style()->hasBorder() && !borderObscuresBackground())
497 // Background shows in padding area.
498 if ((backgroundClip == BorderFillBox || backgroundClip == PaddingFillBox) && style()->hasPadding())
500 // Object-position may leave parts of the content box empty, regardless of the value of object-fit.
501 if (style()->objectPosition() != RenderStyle::initialObjectPosition())
503 // Object-fit may leave parts of the content box empty.
504 ObjectFit objectFit = style()->objectFit();
505 if (objectFit != ObjectFitFill && objectFit != ObjectFitCover)
507 // Check for image with alpha.
508 return m_imageResource->cachedImage() && m_imageResource->cachedImage()->currentFrameKnownToBeOpaque(this);
511 bool RenderImage::computeBackgroundIsKnownToBeObscured()
513 if (!hasBackground())
515 return foregroundIsKnownToBeOpaqueInRect(backgroundPaintedExtent(), 0);
518 LayoutUnit RenderImage::minimumReplacedHeight() const
520 return m_imageResource->errorOccurred() ? intrinsicSize().height() : LayoutUnit();
523 HTMLMapElement* RenderImage::imageMap() const
525 HTMLImageElement* i = node() && node()->hasTagName(imgTag) ? toHTMLImageElement(node()) : 0;
526 return i ? i->treeScope().getImageMap(i->fastGetAttribute(usemapAttr)) : 0;
529 bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
531 HitTestResult tempResult(result.hitTestLocation());
532 bool inside = RenderReplaced::nodeAtPoint(request, tempResult, locationInContainer, accumulatedOffset, hitTestAction);
534 if (tempResult.innerNode() && node()) {
535 if (HTMLMapElement* map = imageMap()) {
536 LayoutRect contentBox = contentBoxRect();
537 float scaleFactor = 1 / style()->effectiveZoom();
538 LayoutPoint mapLocation = locationInContainer.point() - toLayoutSize(accumulatedOffset) - locationOffset() - toLayoutSize(contentBox.location());
539 mapLocation.scale(scaleFactor, scaleFactor);
541 if (map->mapMouseEvent(mapLocation, contentBox.size(), tempResult))
542 tempResult.setInnerNonSharedNode(node());
546 if (!inside && result.isRectBasedTest())
547 result.append(tempResult);
553 void RenderImage::updateAltText()
558 if (node()->hasTagName(inputTag))
559 m_altText = toHTMLInputElement(node())->altText();
560 else if (node()->hasTagName(imgTag))
561 m_altText = toHTMLImageElement(node())->altText();
564 void RenderImage::layout()
566 LayoutRectRecorder recorder(*this);
567 RenderReplaced::layout();
568 updateInnerContentRect();
571 bool RenderImage::updateImageLoadingPriorities()
573 if (!m_imageResource || !m_imageResource->cachedImage() || m_imageResource->cachedImage()->isLoaded())
576 LayoutRect viewBounds = viewRect();
577 LayoutRect objectBounds = absoluteContentBox();
579 // The object bounds might be empty right now, so intersects will fail since it doesn't deal
580 // with empty rects. Use LayoutRect::contains in that case.
582 if (!objectBounds.isEmpty())
583 isVisible = viewBounds.intersects(objectBounds);
585 isVisible = viewBounds.contains(objectBounds);
587 ResourceLoadPriorityOptimizer::VisibilityStatus status = isVisible ?
588 ResourceLoadPriorityOptimizer::Visible : ResourceLoadPriorityOptimizer::NotVisible;
590 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->notifyImageResourceVisibility(m_imageResource->cachedImage(), status);
595 void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const
597 RenderReplaced::computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
599 // Our intrinsicSize is empty if we're rendering generated images with relative width/height. Figure out the right intrinsic size to use.
600 if (intrinsicSize.isEmpty() && (m_imageResource->imageHasRelativeWidth() || m_imageResource->imageHasRelativeHeight())) {
601 RenderObject* containingBlock = isOutOfFlowPositioned() ? container() : this->containingBlock();
602 if (containingBlock->isBox()) {
603 RenderBox* box = toRenderBox(containingBlock);
604 intrinsicSize.setWidth(box->availableLogicalWidth());
605 intrinsicSize.setHeight(box->availableLogicalHeight(IncludeMarginBorderPadding));
608 // Don't compute an intrinsic ratio to preserve historical WebKit behavior if we're painting alt text and/or a broken image.
609 // Video is excluded from this behavior because video elements have a default aspect ratio that a failed poster image load should not override.
610 if (m_imageResource && m_imageResource->errorOccurred() && !isVideo()) {
616 bool RenderImage::needsPreferredWidthsRecalculation() const
618 if (RenderReplaced::needsPreferredWidthsRecalculation())
620 return embeddedContentBox();
623 RenderBox* RenderImage::embeddedContentBox() const
625 if (!m_imageResource)
628 ImageResource* cachedImage = m_imageResource->cachedImage();
629 if (cachedImage && cachedImage->image() && cachedImage->image()->isSVGImage())
630 return toSVGImage(cachedImage->image())->embeddedContentBox();
635 } // namespace WebCore