⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 284436 in webkit


Ignore:
Timestamp:
Oct 18, 2021, 11:32:24 PM (5 years ago)
Author:
Cameron McCormack
Message:

Make createImageBitmap() take EXIF orientation into account correctly
https://bugs.webkit.org/show_bug.cgi?id=231063
<rdar://problem/83753956>

Reviewed by Myles Maxfield and Said Abou-Hallawa.

LayoutTests/imported/w3c:

  • web-platform-tests/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation-expected.txt: Added.
  • web-platform-tests/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation.html: Added.
  • web-platform-tests/html/canvas/element/manual/imagebitmap/resources/squares.jpg: Added.

Source/WebCore:

Test: imported/w3c/web-platform-tests/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation.html

This makes us treat {imageOrientation:"none"} as meaning "apply EXIF
orientation without any additional transformation", and
{imageOrientation:"flipY"} as meaning "apply EXIF orientation and then
apply an additional vertical flip". This behavior matches Firefox;
https://github.com/whatwg/html/issues/7210 is open on clarifying this
behavior in the HTML spec.

  • html/ImageBitmap.cpp:

(WebCore::ImageBitmap::createPromise):
(WebCore::ImageBitmap::createFromBuffer):
(WebCore::imageOrientationForOrientation): Deleted.

  • html/ImageBitmapOptions.h:

(WebCore::ImageBitmapOptions::resolvedImageOrientation const):

  • html/ImageBitmapOptions.idl:
  • platform/graphics/ImageOrientation.h:

(WebCore::ImageOrientation::withFlippedY const):

Location:
trunk
Files:
4 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r284404 r284436  
     12021-10-18  Cameron McCormack  <heycam@apple.com>
     2
     3        Make createImageBitmap() take EXIF orientation into account correctly
     4        https://bugs.webkit.org/show_bug.cgi?id=231063
     5        <rdar://problem/83753956>
     6
     7        Reviewed by Myles Maxfield and Said Abou-Hallawa.
     8
     9        * web-platform-tests/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation-expected.txt: Added.
     10        * web-platform-tests/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation.html: Added.
     11        * web-platform-tests/html/canvas/element/manual/imagebitmap/resources/squares.jpg: Added.
     12
    1132021-10-18  Chris Dumez  <cdumez@apple.com>
    214
  • trunk/Source/WebCore/ChangeLog

    r284434 r284436  
     12021-10-18  Cameron McCormack  <heycam@apple.com>
     2
     3        Make createImageBitmap() take EXIF orientation into account correctly
     4        https://bugs.webkit.org/show_bug.cgi?id=231063
     5        <rdar://problem/83753956>
     6
     7        Reviewed by Myles Maxfield and Said Abou-Hallawa.
     8
     9        Test: imported/w3c/web-platform-tests/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation.html
     10
     11        This makes us treat {imageOrientation:"none"} as meaning "apply EXIF
     12        orientation without any additional transformation", and
     13        {imageOrientation:"flipY"} as meaning "apply EXIF orientation and then
     14        apply an additional vertical flip". This behavior matches Firefox;
     15        https://github.com/whatwg/html/issues/7210 is open on clarifying this
     16        behavior in the HTML spec.
     17
     18        * html/ImageBitmap.cpp:
     19        (WebCore::ImageBitmap::createPromise):
     20        (WebCore::ImageBitmap::createFromBuffer):
     21        (WebCore::imageOrientationForOrientation): Deleted.
     22        * html/ImageBitmapOptions.h:
     23        (WebCore::ImageBitmapOptions::resolvedImageOrientation const):
     24        * html/ImageBitmapOptions.idl:
     25        * platform/graphics/ImageOrientation.h:
     26        (WebCore::ImageOrientation::withFlippedY const):
     27
    1282021-10-18  Jean-Yves Avenard  <jya@apple.com>
    229
  • trunk/Source/WebCore/html/ImageBitmap.cpp

    r284213 r284436  
    236236}
    237237
    238 static ImageOrientation imageOrientationForOrientation(ImageBitmapOptions::Orientation orientation)
    239 {
    240     if (orientation == ImageBitmapOptions::Orientation::FlipY)
    241         return ImageOrientation(ImageOrientation::OriginBottomLeft);
    242     return ImageOrientation();
    243 }
    244 
    245238static AlphaPremultiplication alphaPremultiplicationForPremultiplyAlpha(ImageBitmapOptions::PremultiplyAlpha premultiplyAlpha)
    246239{
     
    374367    }
    375368
    376     auto imageForRender = cachedImage->imageForRenderer(imageElement->renderer());
    377     if (!imageForRender) {
     369    auto imageForRenderer = cachedImage->imageForRenderer(imageElement->renderer());
     370    if (!imageForRenderer) {
    378371        promise.reject(InvalidStateError, "Cannot create ImageBitmap from image that can't be rendered");
    379372        return;
     
    381374
    382375    auto outputSize = outputSizeForSourceRectangle(sourceRectangle.returnValue(), options);
    383     auto bitmapData = createImageBuffer(scriptExecutionContext, outputSize, bufferRenderingMode, imageForRender->colorSpace());
     376    auto bitmapData = createImageBuffer(scriptExecutionContext, outputSize, bufferRenderingMode, imageForRenderer->colorSpace());
    384377    if (!bitmapData) {
    385378        resolveWithBlankImageBuffer(scriptExecutionContext, !taintsOrigin(*cachedImage), WTFMove(promise));
     
    387380    }
    388381
     382    auto orientation = imageForRenderer->orientation();
     383    if (orientation == ImageOrientation::FromImage)
     384        orientation = ImageOrientation::None;
     385
    389386    FloatRect destRect(FloatPoint(), outputSize);
    390     bitmapData->context().drawImage(*imageForRender, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), imageOrientationForOrientation(options.imageOrientation) });
     387    bitmapData->context().drawImage(*imageForRenderer, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), options.resolvedImageOrientation(orientation) });
    391388
    392389    // 9. If the origin of image's image is not the same origin as the origin specified by the
     
    456453
    457454    FloatRect destRect(FloatPoint(), outputSize);
    458     bitmapData->context().drawImage(*imageForRender, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), imageOrientationForOrientation(options.imageOrientation) });
     455    bitmapData->context().drawImage(*imageForRender, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), options.resolvedImageOrientation(ImageOrientation::None) });
    459456
    460457    // 5. Set the origin-clean flag of the ImageBitmap object's bitmap to the same value as
     
    526523        auto scaleX = float(outputSize.width()) / float(sourceRectangle.width());
    527524        auto scaleY = float(outputSize.height()) / float(sourceRectangle.height());
    528         if (options.imageOrientation == ImageBitmapOptions::Orientation::FlipY) {
     525        if (options.orientation == ImageBitmapOptions::Orientation::FlipY) {
    529526            c.scale(FloatSize(scaleX, -scaleY));
    530527            c.translate(IntPoint(-sourceRectangle.location().x(), sourceRectangle.location().y() - outputSize.height()));
     
    589586
    590587    FloatRect destRect(FloatPoint(), outputSize);
    591     bitmapData->context().drawImage(*imageForRender, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), imageOrientationForOrientation(options.imageOrientation) });
     588    bitmapData->context().drawImage(*imageForRender, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), options.resolvedImageOrientation(ImageOrientation::None) });
    592589
    593590    // 5. Set the origin-clean flag of the ImageBitmap object's bitmap to the same
     
    769766
    770767    FloatRect destRect(FloatPoint(), outputSize);
    771     bitmapData->context().drawImage(image, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), imageOrientationForOrientation(options.imageOrientation) });
     768    bitmapData->context().drawImage(image, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), options.resolvedImageOrientation(ImageOrientation::None) });
    772769
    773770    OptionSet<SerializationState> serializationState = SerializationState::OriginClean;
     
    816813    // resulting ImageBuffer directly.
    817814    auto alphaPremultiplication = alphaPremultiplicationForPremultiplyAlpha(options.premultiplyAlpha);
    818     if (sourceRectangle.returnValue().location().isZero() && sourceRectangle.returnValue().size() == imageData->size() && sourceRectangle.returnValue().size() == outputSize && options.imageOrientation == ImageBitmapOptions::Orientation::None) {
     815    if (sourceRectangle.returnValue().location().isZero() && sourceRectangle.returnValue().size() == imageData->size() && sourceRectangle.returnValue().size() == outputSize && options.orientation == ImageBitmapOptions::Orientation::None) {
    819816        bitmapData->putPixelBuffer(imageData->pixelBuffer(), sourceRectangle.releaseReturnValue(), { }, alphaPremultiplication);
    820817       
     
    834831    tempBitmapData->putPixelBuffer(imageData->pixelBuffer(), IntRect(0, 0, imageData->width(), imageData->height()), { }, alphaPremultiplication);
    835832    FloatRect destRect(FloatPoint(), outputSize);
    836     bitmapData->context().drawImageBuffer(*tempBitmapData, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), imageOrientationForOrientation(options.imageOrientation) });
     833    bitmapData->context().drawImageBuffer(*tempBitmapData, destRect, sourceRectangle.releaseReturnValue(), { interpolationQualityForResizeQuality(options.resizeQuality), options.resolvedImageOrientation(ImageOrientation::None) });
    837834
    838835    // 6.4.1. Resolve p with ImageBitmap.
  • trunk/Source/WebCore/html/ImageBitmapOptions.h

    r278340 r284436  
    2626#pragma once
    2727
     28#include "ImageOrientation.h"
    2829#include <optional>
    2930
     
    3637    enum class ResizeQuality { Pixelated, Low, Medium, High };
    3738
    38     Orientation imageOrientation { Orientation::None };
     39    Orientation orientation { Orientation::None };
    3940    PremultiplyAlpha premultiplyAlpha { PremultiplyAlpha::Default };
    4041    ColorSpaceConversion colorSpaceConversion { ColorSpaceConversion::Default };
     
    4243    std::optional<unsigned> resizeHeight;
    4344    ResizeQuality resizeQuality { ResizeQuality::Low };
     45
     46    ImageOrientation resolvedImageOrientation(ImageOrientation imageOrientation) const
     47    {
     48        return orientation == Orientation::FlipY ? imageOrientation.withFlippedY() : imageOrientation;
     49    }
    4450};
    4551
  • trunk/Source/WebCore/html/ImageBitmapOptions.idl

    r222986 r284436  
    3030
    3131dictionary ImageBitmapOptions {
    32     ImageOrientation imageOrientation = "none";
     32    [ImplementedAs=orientation] ImageOrientation imageOrientation = "none";
    3333    PremultiplyAlpha premultiplyAlpha = "default";
    3434    ColorSpaceConversion colorSpaceConversion = "default";
  • trunk/Source/WebCore/platform/graphics/ImageOrientation.h

    r282307 r284436  
    109109    }
    110110
     111    ImageOrientation withFlippedY() const
     112    {
     113        ASSERT(isValidEXIFOrientation(m_orientation));
     114
     115        switch (m_orientation) {
     116        case FromImage:
     117            ASSERT_NOT_REACHED();
     118            return None;
     119        case OriginTopLeft:
     120            return OriginBottomLeft;
     121        case OriginTopRight:
     122            return OriginBottomRight;
     123        case OriginBottomRight:
     124            return OriginTopRight;
     125        case OriginBottomLeft:
     126            return OriginTopLeft;
     127        case OriginLeftTop:
     128            return OriginLeftBottom;
     129        case OriginRightTop:
     130            return OriginRightBottom;
     131        case OriginRightBottom:
     132            return OriginRightTop;
     133        case OriginLeftBottom:
     134            return OriginLeftTop;
     135        }
     136
     137        ASSERT_NOT_REACHED();
     138        return None;
     139    }
     140
    111141private:
    112142    static const Orientation EXIFFirst = OriginTopLeft;
Note: See TracChangeset for help on using the changeset viewer.