Ignore:
Timestamp:
Aug 29, 2013, 5:23:23 PM (12 years ago)
Author:
Simon Fraser
Message:

Implement object-fit CSS property
https://bugs.webkit.org/show_bug.cgi?id=52040

Source/WebCore:

Reviewed by Antti Koivisto, Sam Weinig.

Merge object-fit patch from Blink r156535, which started as a patch
by me.

Since then, the spec has gone to CR. This patch is an
implementation of object-fit as described in
http://www.w3.org/TR/2012/CR-css3-images-20120417/#object-fit

Object-fit is used to maintain the aspect ratio of replaced content
within its content box. All object-fit values but the initial one
('fill') will always ensure that the aspect ratio is retained, in
different ways (fit inside the content box, cover the content box, or
use intrinsic size). Painting is always clipped against the content
box, regardless of the 'overflow' property.

Tests: fast/css/object-fit/object-fit-canvas.html

fast/css/object-fit/object-fit-embed.html
fast/css/object-fit/object-fit-grow-landscape.html
fast/css/object-fit/object-fit-grow-portrait.html
fast/css/object-fit/object-fit-img-svg.html
fast/css/object-fit/object-fit-img-svg2.html
fast/css/object-fit/object-fit-img.html
fast/css/object-fit/object-fit-input-image.html
fast/css/object-fit/object-fit-object.html
fast/css/object-fit/object-fit-shrink.html
fast/css/object-fit/object-fit-video-poster.html
fast/css/parsing-object-fit.html
http/tests/css/object-fit-delayed-img-svg.html
media/video-object-fit-change.html
media/video-object-fit.html

  • css/CSSComputedStyleDeclaration.cpp:

(WebCore::ComputedStyleExtractor::propertyValue):

  • css/CSSParser.cpp:

(WebCore::isValidKeywordPropertyAndValue):
(WebCore::isKeywordPropertyID):
(WebCore::CSSParser::parseValue):

  • css/CSSPrimitiveValueMappings.h:

(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
(WebCore::CSSPrimitiveValue::operator EObjectFit):

  • css/CSSProperty.cpp:

(WebCore::CSSProperty::isInheritedProperty):

  • css/CSSPropertyNames.in:
  • css/CSSValueKeywords.in:
  • css/DeprecatedStyleBuilder.cpp:

(WebCore::DeprecatedStyleBuilder::DeprecatedStyleBuilder):

  • css/StyleResolver.cpp:

(WebCore::StyleResolver::applyProperty):

  • css/html.css:

(video): Set object-fit to 'contain'. This is how VIDEO elements
work, apparently.

  • loader/cache/CachedImage.cpp:

(WebCore::CachedImage::imageSizeForRenderer):

  • loader/cache/CachedImage.h:
  • platform/graphics/LayoutSize.h:

(WebCore::fitLayoutSizeToAspectRatio): New function to grow or shrink
in one dimension to fit to the aspect ratio.

  • rendering/RenderHTMLCanvas.cpp:

(WebCore::RenderHTMLCanvas::paintReplaced): Apply object-fit and
clip if necessary.

  • rendering/RenderImage.cpp:

(WebCore::RenderImage::updateInnerContentRect):
(WebCore::RenderImage::imageDimensionsChanged): Update intrinsic
size properly, and recalculate the inner content rectangle (the
exact area occupied by the replaced content) again if appropriate.
(WebCore::RenderImage::paintReplaced): Apply object-fit and clip
if necessary.
(WebCore::RenderImage::foregroundIsKnownToBeOpaqueInRect):
object-fit may leave parts of the content box empty, in which case
it won't be fully obscured.
(WebCore::RenderImage::layout):

  • rendering/RenderImage.h:
  • rendering/RenderImageResource.cpp:

(WebCore::RenderImageResource::intrinsicSize): Need this to
differentiate between intrinsic and extrinsic size for SVG images.

  • rendering/RenderImageResource.h:
  • rendering/RenderImageResourceStyleImage.h:
  • rendering/RenderReplaced.cpp:

(WebCore::RenderReplaced::replacedContentRect): Return the
rectangle occupied by the replaced content. This will be identical
to the content box if object-fit is 'fill', but will typically be
something else for other values.

  • rendering/RenderReplaced.h:
  • rendering/RenderVideo.cpp:

(WebCore::RenderVideo::videoBox): Not much left to do here, with
the new RenderReplaced::replacedContentRect() method in place.
(WebCore::RenderVideo::paintReplaced): Apply object-fit and clip
if necessary.

  • rendering/style/RenderStyle.cpp:

(WebCore::RenderStyle::changeRequiresRepaint):

  • rendering/style/RenderStyle.h:
  • rendering/style/RenderStyleConstants.h:
  • rendering/style/StyleRareNonInheritedData.cpp:

(WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
(WebCore::StyleRareNonInheritedData::operator==):

  • rendering/style/StyleRareNonInheritedData.h:

LayoutTests:

Reviewed by Antti Koivisto, Sam Weinig.

Tests for object-fit.

  • fast/css/object-fit/object-fit-canvas-expected.html: Added.
  • fast/css/object-fit/object-fit-canvas.html: Added.
  • fast/css/object-fit/object-fit-embed-expected.html: Added.
  • fast/css/object-fit/object-fit-embed.html: Added.
  • fast/css/object-fit/object-fit-grow-landscape-expected.html: Added.
  • fast/css/object-fit/object-fit-grow-landscape.html: Added.
  • fast/css/object-fit/object-fit-grow-portrait-expected.html: Added.
  • fast/css/object-fit/object-fit-grow-portrait.html: Added.
  • fast/css/object-fit/object-fit-img-expected.html: Added.
  • fast/css/object-fit/object-fit-img-svg-expected.html: Added.
  • fast/css/object-fit/object-fit-img-svg.html: Added.
  • fast/css/object-fit/object-fit-img-svg2-expected.html: Added.
  • fast/css/object-fit/object-fit-img-svg2.html: Added.
  • fast/css/object-fit/object-fit-img.html: Added.
  • fast/css/object-fit/object-fit-input-image-expected.html: Added.
  • fast/css/object-fit/object-fit-input-image.html: Added.
  • fast/css/object-fit/object-fit-object-expected.html: Added.
  • fast/css/object-fit/object-fit-object.html: Added.
  • fast/css/object-fit/object-fit-shrink-expected.html: Added.
  • fast/css/object-fit/object-fit-shrink.html: Added.
  • fast/css/object-fit/object-fit-video-poster-expected.html: Added.
  • fast/css/object-fit/object-fit-video-poster.html: Added.
  • fast/css/parsing-object-fit-expected.txt: Added.
  • fast/css/parsing-object-fit.html: Added.
  • fast/css/resources/circle.svg: Added.
  • fast/css/resources/circle2.svg: Added.
  • fast/css/resources/circles-landscape-small.png: Added.
  • fast/css/resources/circles-landscape.png: Added.
  • fast/css/resources/circles-portrait-small.png: Added.
  • fast/css/resources/circles-portrait.png: Added.
  • http/tests/css/object-fit-delayed-img-svg-expected.html: Added.
  • http/tests/css/object-fit-delayed-img-svg.html: Added.
  • media/video-object-fit-change-expected.html: Added.
  • media/video-object-fit-change.html: Added.
  • media/video-object-fit-expected.html: Added.
  • media/video-object-fit.html: Added.
  • platform/mac/TestExpectations:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/rendering/RenderImage.cpp

    r154580 r154858  
    207207}
    208208
     209void RenderImage::updateInnerContentRect()
     210{
     211    // Propagate container size to image resource.
     212    LayoutRect paintRect = replacedContentRect(intrinsicSize());
     213    IntSize containerSize(paintRect.width(), paintRect.height());
     214    if (!containerSize.isEmpty())
     215        m_imageResource->setContainerSizeForRenderer(containerSize);
     216}
     217
    209218void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* rect)
    210219{
     
    215224    if (scale <= 0)
    216225        scale = 1;
    217     bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(m_imageResource->imageSize(style()->effectiveZoom() / scale), imageSizeChanged);
     226    bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(m_imageResource->intrinsicSize(style()->effectiveZoom() / scale), imageSizeChanged);
    218227#else
    219     bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(m_imageResource->imageSize(style()->effectiveZoom()), imageSizeChanged);
     228    bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(m_imageResource->intrinsicSize(style()->effectiveZoom()), imageSizeChanged);
    220229#endif
    221230
     
    255264            if (!selfNeedsLayout())
    256265                setNeedsLayout(true);
     266        }
     267
     268        if (everHadLayout() && !selfNeedsLayout()) {
     269            // The inner content rectangle is calculated during layout, but may need an update now
     270            // (unless the box has already been scheduled for layout). In order to calculate it, we
     271            // may need values from the containing block, though, so make sure that we're not too
     272            // early. It may be that layout hasn't even taken place once yet.
     273
     274            // FIXME: we should not have to trigger another call to setContainerSizeForRenderer()
     275            // from here, since it's already being done during layout.
     276            updateInnerContentRect();
    257277        }
    258278    }
     
    395415#endif
    396416
    397         LayoutSize contentSize(cWidth, cHeight);
    398         LayoutPoint contentLocation = paintOffset;
    399         contentLocation.move(leftBorder + leftPad, topBorder + topPad);
    400         paintIntoRect(context, LayoutRect(contentLocation, contentSize));
     417        LayoutRect contentRect = contentBoxRect();
     418        contentRect.moveBy(paintOffset);
     419        LayoutRect paintRect = replacedContentRect(intrinsicSize());
     420        paintRect.moveBy(paintOffset);
     421        bool clip = !contentRect.contains(paintRect);
     422        GraphicsContextStateSaver stateSaver(*context, clip);
     423        if (clip)
     424            context->clip(contentRect);
     425
     426        paintIntoRect(context, paintRect);
    401427       
    402428        if (cachedImage() && page && paintInfo.phase == PaintPhaseForeground) {
    403429            // For now, count images as unpainted if they are still progressively loading. We may want
    404430            // to refine this in the future to account for the portion of the image that has painted.
     431            LayoutRect visibleRect = intersection(paintRect, contentRect);
    405432            if (cachedImage()->isLoading())
    406                 page->addRelevantUnpaintedObject(this, LayoutRect(contentLocation, contentSize));
     433                page->addRelevantUnpaintedObject(this, visibleRect);
    407434            else
    408                 page->addRelevantRepaintedObject(this, LayoutRect(contentLocation, contentSize));
     435                page->addRelevantRepaintedObject(this, visibleRect);
    409436        }
    410437    }
     
    510537    if ((backgroundClip == BorderFillBox || backgroundClip == PaddingFillBox) && style()->hasPadding())
    511538        return false;
     539    // Object-fit may leave parts of the content box empty.
     540    ObjectFit objectFit = style()->objectFit();
     541    if (objectFit != ObjectFitFill && objectFit != ObjectFitCover)
     542        return false;
    512543    // Check for image with alpha.
    513544    return m_imageResource->cachedImage() && m_imageResource->cachedImage()->currentFrameKnownToBeOpaque(this);
     
    575606    StackStats::LayoutCheckPoint layoutCheckPoint;
    576607    RenderReplaced::layout();
    577 
    578     // Propagate container size to image resource.
    579     IntSize containerSize(contentWidth(), contentHeight());
    580     if (!containerSize.isEmpty())
    581         m_imageResource->setContainerSizeForRenderer(containerSize);
     608    updateInnerContentRect();
    582609}
    583610
Note: See TracChangeset for help on using the changeset viewer.