Changeset 171957 in webkit


Ignore:
Timestamp:
Aug 1, 2014 4:22:44 PM (10 years ago)
Author:
Simon Fraser
Message:

Clean up image subsampling code, make it less iOS-specific
https://bugs.webkit.org/show_bug.cgi?id=134916

Reviewed by Dean Jackson.

Compile the image subsampling code on both Mac and iOS, and make it more platform
neutral in general. Add a setting to allow it to be enabled on Mac for testing.

The most significant changes are in ImageSourceCG and BitmapImageCG. CG's ImageSource
is no longer stateful with respect to subsampling; its functions take a SubsamplingLevel
when appropriate. CG's BitmapImage now determines which level of subsampling to use
for a given frame, storing the subsampling level in the frame data. It can replace
an aggressively subsampled frame with a less subsampled frame if necessary.

To reduce the chances of subsampling affecting rendering, BitmapImage::size() now
always returns the non-subsampled size; subsampling is strictly internal to BitmapImage.
BitmapImage::draw() takes care of scaling the srcRect for subsampled images.

iOS had a code path that enabled caching of frame metadata in BitmapImage without
actually decoding the frame; make this cross-platform.

  • WebCore.exp.in: Changed signature for GraphicsContext::drawNativeImage().
  • WebCore.xcodeproj/project.pbxproj: Added ImageSource.cpp, which is not built

for Cocoa but useful for reference.

  • loader/cache/CachedImage.cpp:

(WebCore::CachedImage::imageSizeForRenderer): Remove iOS-specific subsampling code.
(WebCore::CachedImage::createImage): Call setAllowSubsampling() on the image if we
can get to Settings (m_loader is null for image documents).
(WebCore::CachedImage::currentFrameKnownToBeOpaque): This forced decode always
caused creation of the non-subsampled image, so remove it. There's no reason to
eagerly decode the frame here.

  • loader/cache/CachedImage.h: Fix comment.
  • page/Settings.cpp: Add defaultImageSubsamplingEnabled, true for iOS and false for Mac.
  • page/Settings.in: Added imageSubsamplingEnabled.
  • platform/graphics/BitmapImage.cpp:

(WebCore::BitmapImage::BitmapImage): Init some more things. Default m_allowSubsampling to
true for iOS to catch images created in code paths where we can't get to Settings.
(WebCore::BitmapImage::haveFrameAtIndex): Handy helper.
(WebCore::BitmapImage::cacheFrame): Now takes the subsampling level and whether to cache
just metadata, or also the frame.
(WebCore::BitmapImage::didDecodeProperties): No need to store originalSize.
(WebCore::BitmapImage::updateSize): When we get the size for the first time, call
determineMinimumSubsamplingLevel() to choose a reasonable subsampling level which takes
platform-specific limits into account.
(WebCore::BitmapImage::dataChanged): Comment.
(WebCore::BitmapImage::ensureFrameIsCached): Take ImageFrameCaching into account.
(WebCore::BitmapImage::frameAtIndex): Choose a subsampling level given the scale,
then determine if we can use the currently cached frame, or whether we should resample.
(WebCore::BitmapImage::frameIsCompleteAtIndex): Caching m_isComplete is now done when caching
frame metadata.
(WebCore::BitmapImage::frameDurationAtIndex):
(WebCore::BitmapImage::frameHasAlphaAtIndex): The 'true' return is the safe return value.
(WebCore::BitmapImage::frameOrientationAtIndex): Caching m_orientation is now done when caching
frame metadata.
(WebCore::BitmapImage::cacheFrameInfo): Deleted.
(WebCore::BitmapImage::originalSize): Deleted.
(WebCore::BitmapImage::originalSizeRespectingOrientation): Deleted.
(WebCore::BitmapImage::currentFrameSize): Deleted.
(WebCore::BitmapImage::ensureFrameInfoIsCached): Deleted.

  • platform/graphics/BitmapImage.h:

(WebCore::FrameData::FrameData):

  • platform/graphics/GraphicsContext.h: No need to pass a scale param now.
  • platform/graphics/ImageSource.cpp: Non-Cocoa changes.

(WebCore::ImageSource::subsamplingLevelForScale):
(WebCore::ImageSource::allowSubsamplingOfFrameAtIndex):
(WebCore::ImageSource::size):
(WebCore::ImageSource::frameSizeAtIndex):
(WebCore::ImageSource::createFrameAtIndex):
(WebCore::ImageSource::frameBytesAtIndex):

  • platform/graphics/ImageSource.h: No longer stores subsampling state.

(WebCore::ImageSource::isSubsampled): Deleted.

  • platform/graphics/cairo/BitmapImageCairo.cpp:

(WebCore::BitmapImage::determineMinimumSubsamplingLevel):

  • platform/graphics/cg/BitmapImageCG.cpp:

(WebCore::FrameData::clear):
(WebCore::BitmapImage::BitmapImage): Init more members.
(WebCore::BitmapImage::determineMinimumSubsamplingLevel): Choose a minimum subsampling
level for the platform (subsample until the image area falls under a threshold).
(WebCore::BitmapImage::checkForSolidColor): Don't bother decoding frames if the image
is not 1x1. Also take care not to decode a non-subsampled image.
(WebCore::BitmapImage::draw): The actual bug fix is here; remove logic that
computed srcRectForCurrentFrame from m_size and m_originalSize; for some callers
srcRect was computed using the pre-subsampled size, and for others it was the subsampled size.
Instead, scale srcRect by mapping between the non-subsampled size, and the size of the CGImageRef
which is affected by subsampling.
(WebCore::BitmapImage::copyUnscaledFrameAtIndex):

  • platform/graphics/cg/GraphicsContext3DCG.cpp:

(WebCore::GraphicsContext3D::ImageExtractor::extractImage): Remove #ifdeffed code.
(WebCore::GraphicsContext3D::paintToCanvas):

  • platform/graphics/cg/GraphicsContextCG.cpp:

(WebCore::GraphicsContext::drawNativeImage): No more weird scaling!

  • platform/graphics/cg/ImageBufferCG.cpp:

(WebCore::ImageBuffer::draw):

  • platform/graphics/cg/ImageSourceCG.cpp:

(WebCore::ImageSource::ImageSource):
(WebCore::createImageSourceOptions): Helper that always returns a new CFDictionaryRef.
(WebCore::imageSourceOptions): If not subsampling, return the cached CFDictionaryRef, otherwise
make a new options dict and return it.
(WebCore::ImageSource::subsamplingLevelForScale): Helper that returns a subsampling level
between 0 and 3 given a scale.
(WebCore::ImageSource::isSizeAvailable): SkipMetadata is a default value for the param now.
(WebCore::ImageSource::allowSubsamplingOfFrameAtIndex): We turn off subsampling for progressive
JPEGs because of a bug, so need this to know if a frame should be subsampled.
(WebCore::ImageSource::frameSizeAtIndex): The looping to find a subsampling level is now in BitmapImageCG.
(WebCore::ImageSource::orientationAtIndex):
(WebCore::ImageSource::size): Always use a subsampling level of 0 for size().
(WebCore::ImageSource::getHotSpot):
(WebCore::ImageSource::repetitionCount):
(WebCore::ImageSource::createFrameAtIndex): The caller mapped a scale to a level.
(WebCore::ImageSource::frameDurationAtIndex):
(WebCore::ImageSource::frameBytesAtIndex):
(WebCore::ImageSource::imageSourceOptions): Deleted.
(WebCore::ImageSource::originalSize): Deleted.

  • platform/graphics/mac/ImageMac.mm:

(WebCore::BitmapImage::invalidatePlatformData): 0 -> nullptr

  • platform/graphics/wince/ImageWinCE.cpp:

(WebCore::BitmapImage::determineMinimumSubsamplingLevel):

Location:
trunk/Source/WebCore
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r171956 r171957  
     12014-08-01  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Clean up image subsampling code, make it less iOS-specific
     4        https://bugs.webkit.org/show_bug.cgi?id=134916
     5
     6        Reviewed by Dean Jackson.
     7
     8        Compile the image subsampling code on both Mac and iOS, and make it more platform
     9        neutral in general. Add a setting to allow it to be enabled on Mac for testing.
     10       
     11        The most significant changes are in ImageSourceCG and BitmapImageCG. CG's ImageSource
     12        is no longer stateful with respect to subsampling; its functions take a SubsamplingLevel
     13        when appropriate. CG's BitmapImage now determines which level of subsampling to use
     14        for a given frame, storing the subsampling level in the frame data. It can replace
     15        an aggressively subsampled frame with a less subsampled frame if necessary.
     16       
     17        To reduce the chances of subsampling affecting rendering, BitmapImage::size() now
     18        always returns the non-subsampled size; subsampling is strictly internal to BitmapImage.
     19        BitmapImage::draw() takes care of scaling the srcRect for subsampled images.
     20       
     21        iOS had a code path that enabled caching of frame metadata in BitmapImage without
     22        actually decoding the frame; make this cross-platform.
     23
     24        * WebCore.exp.in: Changed signature for GraphicsContext::drawNativeImage().
     25        * WebCore.xcodeproj/project.pbxproj: Added ImageSource.cpp, which is not built
     26        for Cocoa but useful for reference.
     27        * loader/cache/CachedImage.cpp:
     28        (WebCore::CachedImage::imageSizeForRenderer): Remove iOS-specific subsampling code.
     29        (WebCore::CachedImage::createImage): Call setAllowSubsampling() on the image if we
     30        can get to Settings (m_loader is null for image documents).
     31        (WebCore::CachedImage::currentFrameKnownToBeOpaque): This forced decode always
     32        caused creation of the non-subsampled image, so remove it. There's no reason to
     33        eagerly decode the frame here.
     34        * loader/cache/CachedImage.h: Fix comment.
     35        * page/Settings.cpp: Add defaultImageSubsamplingEnabled, true for iOS and false for Mac.
     36        * page/Settings.in: Added imageSubsamplingEnabled.
     37        * platform/graphics/BitmapImage.cpp:
     38        (WebCore::BitmapImage::BitmapImage): Init some more things. Default m_allowSubsampling to
     39        true for iOS to catch images created in code paths where we can't get to Settings.
     40        (WebCore::BitmapImage::haveFrameAtIndex): Handy helper.
     41        (WebCore::BitmapImage::cacheFrame): Now takes the subsampling level and whether to cache
     42        just metadata, or also the frame.
     43        (WebCore::BitmapImage::didDecodeProperties): No need to store originalSize.
     44        (WebCore::BitmapImage::updateSize): When we get the size for the first time, call
     45        determineMinimumSubsamplingLevel() to choose a reasonable subsampling level which takes
     46        platform-specific limits into account.
     47        (WebCore::BitmapImage::dataChanged): Comment.
     48        (WebCore::BitmapImage::ensureFrameIsCached): Take ImageFrameCaching into account.
     49        (WebCore::BitmapImage::frameAtIndex): Choose a subsampling level given the scale,
     50        then determine if we can use the currently cached frame, or whether we should resample.
     51        (WebCore::BitmapImage::frameIsCompleteAtIndex): Caching m_isComplete is now done when caching
     52        frame metadata.
     53        (WebCore::BitmapImage::frameDurationAtIndex):
     54        (WebCore::BitmapImage::frameHasAlphaAtIndex): The 'true' return is the safe return value.
     55        (WebCore::BitmapImage::frameOrientationAtIndex): Caching m_orientation is now done when caching
     56        frame metadata.
     57        (WebCore::BitmapImage::cacheFrameInfo): Deleted.
     58        (WebCore::BitmapImage::originalSize): Deleted.
     59        (WebCore::BitmapImage::originalSizeRespectingOrientation): Deleted.
     60        (WebCore::BitmapImage::currentFrameSize): Deleted.
     61        (WebCore::BitmapImage::ensureFrameInfoIsCached): Deleted.
     62        * platform/graphics/BitmapImage.h:
     63        (WebCore::FrameData::FrameData):
     64        * platform/graphics/GraphicsContext.h: No need to pass a scale param now.
     65        * platform/graphics/ImageSource.cpp: Non-Cocoa changes.
     66        (WebCore::ImageSource::subsamplingLevelForScale):
     67        (WebCore::ImageSource::allowSubsamplingOfFrameAtIndex):
     68        (WebCore::ImageSource::size):
     69        (WebCore::ImageSource::frameSizeAtIndex):
     70        (WebCore::ImageSource::createFrameAtIndex):
     71        (WebCore::ImageSource::frameBytesAtIndex):
     72        * platform/graphics/ImageSource.h: No longer stores subsampling state.
     73        (WebCore::ImageSource::isSubsampled): Deleted.
     74        * platform/graphics/cairo/BitmapImageCairo.cpp:
     75        (WebCore::BitmapImage::determineMinimumSubsamplingLevel):
     76        * platform/graphics/cg/BitmapImageCG.cpp:
     77        (WebCore::FrameData::clear):
     78        (WebCore::BitmapImage::BitmapImage): Init more members.
     79        (WebCore::BitmapImage::determineMinimumSubsamplingLevel): Choose a minimum subsampling
     80        level for the platform (subsample until the image area falls under a threshold).
     81        (WebCore::BitmapImage::checkForSolidColor): Don't bother decoding frames if the image
     82        is not 1x1. Also take care not to decode a non-subsampled image.
     83        (WebCore::BitmapImage::draw): The actual bug fix is here; remove logic that
     84        computed srcRectForCurrentFrame from m_size and m_originalSize; for some callers
     85        srcRect was computed using the pre-subsampled size, and for others it was the subsampled size.
     86        Instead, scale srcRect by mapping between the non-subsampled size, and the size of the CGImageRef
     87        which is affected by subsampling.
     88        (WebCore::BitmapImage::copyUnscaledFrameAtIndex):
     89        * platform/graphics/cg/GraphicsContext3DCG.cpp:
     90        (WebCore::GraphicsContext3D::ImageExtractor::extractImage): Remove #ifdeffed code.
     91        (WebCore::GraphicsContext3D::paintToCanvas):
     92        * platform/graphics/cg/GraphicsContextCG.cpp:
     93        (WebCore::GraphicsContext::drawNativeImage): No more weird scaling!
     94        * platform/graphics/cg/ImageBufferCG.cpp:
     95        (WebCore::ImageBuffer::draw):
     96        * platform/graphics/cg/ImageSourceCG.cpp:
     97        (WebCore::ImageSource::ImageSource):
     98        (WebCore::createImageSourceOptions): Helper that always returns a new CFDictionaryRef.
     99        (WebCore::imageSourceOptions): If not subsampling, return the cached CFDictionaryRef, otherwise
     100        make a new options dict and return it.
     101        (WebCore::ImageSource::subsamplingLevelForScale): Helper that returns a subsampling level
     102        between 0 and 3 given a scale.
     103        (WebCore::ImageSource::isSizeAvailable): SkipMetadata is a default value for the param now.
     104        (WebCore::ImageSource::allowSubsamplingOfFrameAtIndex): We turn off subsampling for progressive
     105        JPEGs because of a bug, so need this to know if a frame should be subsampled.
     106        (WebCore::ImageSource::frameSizeAtIndex): The looping to find a subsampling level is now in BitmapImageCG.
     107        (WebCore::ImageSource::orientationAtIndex):
     108        (WebCore::ImageSource::size): Always use a subsampling level of 0 for size().
     109        (WebCore::ImageSource::getHotSpot):
     110        (WebCore::ImageSource::repetitionCount):
     111        (WebCore::ImageSource::createFrameAtIndex): The caller mapped a scale to a level.
     112        (WebCore::ImageSource::frameDurationAtIndex):
     113        (WebCore::ImageSource::frameBytesAtIndex):
     114        (WebCore::ImageSource::imageSourceOptions): Deleted.
     115        (WebCore::ImageSource::originalSize): Deleted.
     116        * platform/graphics/mac/ImageMac.mm:
     117        (WebCore::BitmapImage::invalidatePlatformData): 0 -> nullptr
     118        * platform/graphics/wince/ImageWinCE.cpp:
     119        (WebCore::BitmapImage::determineMinimumSubsamplingLevel):
     120
    11212014-08-01  Andreas Kling  <akling@apple.com>
    2122
  • trunk/Source/WebCore/WebCore.exp.in

    r171891 r171957  
    522522__ZN7WebCore15GraphicsContext12setFillColorERKNS_5ColorENS_10ColorSpaceE
    523523__ZN7WebCore15GraphicsContext14setStrokeColorERKNS_5ColorENS_10ColorSpaceE
     524__ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_NS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE
    524525__ZN7WebCore15GraphicsContext15setFillGradientEN3WTF10PassRefPtrINS_8GradientEEE
    525526__ZN7WebCore15GraphicsContext18setShouldAntialiasEb
     
    22382239__ZN7WebCore13toDeviceSpaceERKNS_9FloatRectEP8NSWindow
    22392240__ZN7WebCore14cookiesEnabledERKNS_21NetworkStorageSessionERKNS_3URLES5_
    2240 __ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_fNS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE
    22412241__ZN7WebCore15GraphicsContextC1EP9CGContext
    22422242__ZN7WebCore15ResourceRequest41updateFromDelegatePreservingOldPropertiesERKS0_
     
    25892589__ZN7WebCore15GraphicsContext12drawBidiTextERKNS_4FontERKNS_7TextRunERKNS_10FloatPointENS1_24CustomFontNotReadyActionEPNS_10BidiStatusEi
    25902590__ZN7WebCore15GraphicsContext15drawLineForTextERKNS_10FloatPointEfbb
    2591 __ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_fNS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE
    25922591__ZN7WebCore15GraphicsContext22setEmojiDrawingEnabledEb
    25932592__ZN7WebCore15GraphicsContext23setIsAcceleratedContextEb
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r171824 r171957  
    474474                0F1774811378B772009DA76A /* ScrollAnimatorIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F17747F1378B772009DA76A /* ScrollAnimatorIOS.mm */; };
    475475                0F29C16E1300C2E2002D794E /* AccessibilityAllInOne.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F29C16D1300C2E2002D794E /* AccessibilityAllInOne.cpp */; };
     476                0F3C725E1974874B00AEDD0C /* ImageSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3C725D1974874B00AEDD0C /* ImageSource.cpp */; };
    476477                0F3DD44F12F5EA1B000D9190 /* ShadowBlur.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3DD44D12F5EA1B000D9190 /* ShadowBlur.cpp */; };
    477478                0F3DD45012F5EA1B000D9190 /* ShadowBlur.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3DD44E12F5EA1B000D9190 /* ShadowBlur.h */; };
     
    74157416                0F17747F1378B772009DA76A /* ScrollAnimatorIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ScrollAnimatorIOS.mm; path = ios/ScrollAnimatorIOS.mm; sourceTree = "<group>"; };
    74167417                0F29C16D1300C2E2002D794E /* AccessibilityAllInOne.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityAllInOne.cpp; sourceTree = "<group>"; };
     7418                0F3C725D1974874B00AEDD0C /* ImageSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageSource.cpp; sourceTree = "<group>"; };
    74177419                0F3DD44D12F5EA1B000D9190 /* ShadowBlur.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShadowBlur.cpp; sourceTree = "<group>"; };
    74187420                0F3DD44E12F5EA1B000D9190 /* ShadowBlur.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowBlur.h; sourceTree = "<group>"; };
     
    2049120493                                49291E4A134172C800E753DE /* ImageRenderingMode.h */,
    2049220494                                B27535430B053814002CE64F /* ImageSource.h */,
     20495                                0F3C725D1974874B00AEDD0C /* ImageSource.cpp */,
    2049320496                                07941793166EA04E009416C2 /* InbandTextTrackPrivate.h */,
    2049420497                                07CE77D416712A6A00C55A47 /* InbandTextTrackPrivateClient.h */,
     
    2943929442                                97BC6A471505F081001B74AC /* SQLStatement.cpp in Sources */,
    2944029443                                FE8A674716CDD19E00930BF8 /* SQLStatementBackend.cpp in Sources */,
     29444                                0F3C725E1974874B00AEDD0C /* ImageSource.cpp in Sources */,
    2944129445                                97BC6A4D1505F081001B74AC /* SQLStatementSync.cpp in Sources */,
    2944229446                                97BC6A4F1505F081001B74AC /* SQLTransaction.cpp in Sources */,
  • trunk/Source/WebCore/loader/cache/CachedImage.cpp

    r171743 r171957  
    290290#else
    291291    if (m_image->isBitmapImage() && (renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation))
    292 #if !PLATFORM(IOS)
    293292        imageSize = LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
    294 #else
    295     {
    296         // On iOS, the image may have been subsampled to accommodate our size restrictions. However
    297         // we should tell the renderer what the original size was.
    298         imageSize = LayoutSize(toBitmapImage(m_image.get())->originalSizeRespectingOrientation());
    299     } else if (m_image->isBitmapImage())
    300         imageSize = LayoutSize(toBitmapImage(m_image.get())->originalSize());
    301 #endif // !PLATFORM(IOS)
    302293#endif // ENABLE(CSS_IMAGE_ORIENTATION)
    303294
     
    353344    if (m_image)
    354345        return;
     346
    355347#if USE(CG) && !USE(WEBKIT_IMAGE_DECODERS)
    356348    else if (m_response.mimeType() == "application/pdf")
     
    361353        m_svgImageCache = std::make_unique<SVGImageCache>(svgImage.get());
    362354        m_image = svgImage.release();
    363     } else
     355    } else {
    364356        m_image = BitmapImage::create(this);
     357        toBitmapImage(m_image.get())->setAllowSubsampling(m_loader && m_loader->frameLoader()->frame().settings().imageSubsamplingEnabled());
     358    }
    365359
    366360    if (m_image) {
     
    519513{
    520514    Image* image = imageForRenderer(renderer);
    521     if (image->isBitmapImage())
    522         image->nativeImageForCurrentFrame(); // force decode
    523515    return image->currentFrameKnownToBeOpaque();
    524516}
  • trunk/Source/WebCore/loader/cache/CachedImage.h

    r166665 r171957  
    6060    Image* imageForRenderer(const RenderObject*); // Returns the nullImage() if the image is not available yet.
    6161    bool hasImage() const { return m_image.get(); }
    62     bool currentFrameKnownToBeOpaque(const RenderElement*); // Side effect: ensures decoded image is in cache, therefore should only be called when about to draw the image.
     62    bool currentFrameKnownToBeOpaque(const RenderElement*);
    6363
    6464    std::pair<Image*, float> brokenImage(float deviceScaleFactor) const; // Returns an image and the image's resolution scale factor.
  • trunk/Source/WebCore/page/Settings.cpp

    r170235 r171957  
    128128static const bool defaultMediaPlaybackRequiresUserGesture = true;
    129129static const bool defaultShouldRespectImageOrientation = true;
     130static const bool defaultImageSubsamplingEnabled = true;
    130131static const bool defaultScrollingTreeIncludesFrames = true;
    131132#else
     
    136137static const bool defaultMediaPlaybackRequiresUserGesture = false;
    137138static const bool defaultShouldRespectImageOrientation = false;
     139static const bool defaultImageSubsamplingEnabled = false;
    138140static const bool defaultScrollingTreeIncludesFrames = false;
    139141#endif
  • trunk/Source/WebCore/page/Settings.in

    r171001 r171957  
    142142
    143143shouldRespectImageOrientation initial=defaultShouldRespectImageOrientation
     144imageSubsamplingEnabled initial=defaultImageSubsamplingEnabled
    144145wantsBalancedSetDefersLoadingBehavior initial=false
    145146requestAnimationFrameEnabled initial=true
  • trunk/Source/WebCore/platform/graphics/BitmapImage.cpp

    r171119 r171957  
    4545namespace WebCore {
    4646
    47 // FIXME: We should better integrate the iOS and non-iOS code in this class. Unlike other ports, the
    48 // iOS port caches the metadata for a frame without decoding the image.
    4947BitmapImage::BitmapImage(ImageObserver* observer)
    5048    : Image(observer)
     49    , m_minimumSubsamplingLevel(0)
     50    , m_imageOrientation(OriginTopLeft)
     51    , m_shouldRespectImageOrientation(false)
    5152    , m_currentFrame(0)
    52     , m_frames(0)
    5353    , m_repetitionCount(cAnimationNone)
    5454    , m_repetitionCountStatus(Unknown)
     
    6262    , m_progressiveLoadChunkTime(0)
    6363    , m_progressiveLoadChunkCount(0)
     64    , m_allowSubsampling(true)
     65#else
     66    , m_allowSubsampling(false)
    6467#endif
    6568    , m_isSolidColor(false)
     
    7982    invalidatePlatformData();
    8083    stopAnimation();
     84}
     85
     86bool BitmapImage::haveFrameAtIndex(size_t index)
     87{
     88    if (index >= frameCount())
     89        return false;
     90
     91    if (index >= m_frames.size())
     92        return false;
     93
     94    return m_frames[index].m_frame;
    8195}
    8296
     
    153167}
    154168
    155 #if PLATFORM(IOS)
    156 void BitmapImage::cacheFrame(size_t index, float scaleHint)
    157 #else
    158 void BitmapImage::cacheFrame(size_t index)
    159 #endif
     169void BitmapImage::cacheFrame(size_t index, SubsamplingLevel subsamplingLevel, ImageFrameCaching frameCaching)
    160170{
    161171    size_t numFrames = frameCount();
     
    165175        m_frames.grow(numFrames);
    166176
    167 #if PLATFORM(IOS)
    168     m_frames[index].m_frame = m_source.createFrameAtIndex(index, &scaleHint);
    169     m_frames[index].m_subsamplingScale = scaleHint;
    170 #else
    171     m_frames[index].m_frame = m_source.createFrameAtIndex(index);
    172 #endif
    173     if (numFrames == 1 && m_frames[index].m_frame)
    174         checkForSolidColor();
     177    if (frameCaching == CacheMetadataAndFrame) {
     178        m_frames[index].m_frame = m_source.createFrameAtIndex(index, subsamplingLevel);
     179        m_frames[index].m_subsamplingLevel = subsamplingLevel;
     180        if (numFrames == 1 && m_frames[index].m_frame)
     181            checkForSolidColor();
     182    }
    175183
    176184    m_frames[index].m_orientation = m_source.orientationAtIndex(index);
    177185    m_frames[index].m_haveMetadata = true;
    178186    m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index);
     187
    179188    if (repetitionCount(false) != cAnimationNone)
    180189        m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
     190
    181191    m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
    182     m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index);
    183 
    184     const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size);
    185     if (frameSize != m_size)
     192    m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index, subsamplingLevel);
     193
     194    const IntSize frameSize(index ? m_source.frameSizeAtIndex(index, subsamplingLevel) : m_size);
     195    if (!subsamplingLevel && frameSize != m_size)
    186196        m_hasUniformFrameSize = false;
     197
    187198    if (m_frames[index].m_frame) {
    188199        int deltaBytes = safeCast<int>(m_frames[index].m_frameBytes);
     
    197208}
    198209
    199 #if PLATFORM(IOS)
    200 void BitmapImage::cacheFrameInfo(size_t index)
    201 {
    202     size_t numFrames = frameCount();
    203 
    204     if (m_frames.size() < numFrames)
    205         m_frames.resize(numFrames);
    206 
    207     ASSERT(!m_frames[index].m_haveInfo);
    208 
    209     if (shouldAnimate())
    210         m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
    211     m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
    212     m_frames[index].m_haveInfo = true;
    213 }
    214 #endif
    215 
    216210void BitmapImage::didDecodeProperties() const
    217211{
    218212    if (m_decodedSize)
    219213        return;
     214
    220215    size_t updatedSize = m_source.bytesDecodedToDetermineProperties();
    221216    if (m_decodedPropertiesSize == updatedSize)
    222217        return;
     218
    223219    int deltaBytes = updatedSize - m_decodedPropertiesSize;
    224220#if !ASSERT_DISABLED
     
    239235    m_size = m_source.size(description);
    240236    m_sizeRespectingOrientation = m_source.size(ImageOrientationDescription(RespectImageOrientation, description.imageOrientation()));
     237
    241238    m_imageOrientation = static_cast<unsigned>(description.imageOrientation());
    242239    m_shouldRespectImageOrientation = static_cast<unsigned>(description.respectImageOrientation());
    243 #if PLATFORM(IOS)
    244     m_originalSize = m_source.originalSize();
    245     m_originalSizeRespectingOrientation = m_source.originalSize(RespectImageOrientation);
    246 #endif
     240
    247241    m_haveSize = true;
     242
     243    determineMinimumSubsamplingLevel();
    248244    didDecodeProperties();
    249245}
     
    259255    updateSize(description);
    260256    return m_sizeRespectingOrientation;
    261 }
    262 
    263 #if PLATFORM(IOS)
    264 FloatSize BitmapImage::originalSize() const
    265 {
    266     updateSize();
    267     return m_originalSize;
    268 }
    269 
    270 IntSize BitmapImage::originalSizeRespectingOrientation() const
    271 {
    272     updateSize();
    273     return m_originalSizeRespectingOrientation;
    274 }
    275 #endif
    276 
    277 IntSize BitmapImage::currentFrameSize() const
    278 {
    279     if (!m_currentFrame || m_hasUniformFrameSize)
    280         return IntSize(size());
    281     IntSize frameSize = m_source.frameSizeAtIndex(m_currentFrame);
    282     didDecodeProperties();
    283     return frameSize;
    284257}
    285258
     
    324297    destroyMetadataAndNotify(frameBytesCleared);
    325298#else
     299    // FIXME: why is this different for iOS?
    326300    int deltaBytes = 0;
    327301    if (!m_frames.isEmpty()) {
     
    391365}
    392366
    393 #if !PLATFORM(IOS)
    394 bool BitmapImage::ensureFrameIsCached(size_t index)
     367bool BitmapImage::ensureFrameIsCached(size_t index, ImageFrameCaching frameCaching)
    395368{
    396369    if (index >= frameCount())
    397370        return false;
    398371
    399     if (index >= m_frames.size() || !m_frames[index].m_frame)
    400         cacheFrame(index);
     372    if (index >= m_frames.size()
     373        || (frameCaching == CacheMetadataAndFrame && !m_frames[index].m_frame)
     374        || (frameCaching == CacheMetadataOnly && !m_frames[index].m_haveMetadata))
     375        cacheFrame(index, 0, frameCaching);
     376
    401377    return true;
    402378}
    403 #else
    404 bool BitmapImage::ensureFrameInfoIsCached(size_t index)
    405 {
    406     if (index >= frameCount())
    407         return false;
    408 
    409     if (index >= m_frames.size() || !m_frames[index].m_haveInfo)
    410         cacheFrameInfo(index);
    411     return true;
    412 }
    413 #endif
    414 
    415 PassNativeImagePtr BitmapImage::frameAtIndex(size_t index)
    416 {
    417 #if PLATFORM(IOS)
    418     return frameAtIndex(index, 1.0f);
    419 #else
    420     if (!ensureFrameIsCached(index))
    421         return nullptr;
    422     return m_frames[index].m_frame;
    423 #endif
    424 }
    425 
    426 #if PLATFORM(IOS)
    427 PassNativeImagePtr BitmapImage::frameAtIndex(size_t index, float scaleHint)
     379
     380PassNativeImagePtr BitmapImage::frameAtIndex(size_t index, float presentationScaleHint)
    428381{
    429382    if (index >= frameCount())
    430383        return nullptr;
    431384
    432     if (index >= m_frames.size() || !m_frames[index].m_frame)
    433         cacheFrame(index, scaleHint);
    434     else if (std::min(1.0f, scaleHint) > m_frames[index].m_subsamplingScale) {
     385    SubsamplingLevel subsamplingLevel = std::min(m_source.subsamplingLevelForScale(presentationScaleHint), m_minimumSubsamplingLevel);
     386
     387    // We may have cached a frame with a higher subsampling level, in which case we need to
     388    // re-decode with a lower level.
     389    if (index < m_frames.size() && m_frames[index].m_frame && subsamplingLevel < m_frames[index].m_subsamplingLevel) {
    435390        // If the image is already cached, but at too small a size, re-decode a larger version.
    436391        int sizeChange = -m_frames[index].m_frameBytes;
    437         ASSERT(static_cast<int>(m_decodedSize) + sizeChange >= 0);
    438392        m_frames[index].clear(true);
    439393        invalidatePlatformData();
    440394        m_decodedSize += sizeChange;
     395        WTFLogAlways("BitmapImage %p frameAtIndex recaching, m_decodedSize now %u (size change %d)", this, m_decodedSize, sizeChange);
    441396        if (imageObserver())
    442397            imageObserver()->decodedSizeChanged(this, sizeChange);
    443 
    444         cacheFrame(index, scaleHint);
    445     }
     398    }
     399
     400    // If we haven't fetched a frame yet, do so.
     401    if (index >= m_frames.size() || !m_frames[index].m_frame)
     402        cacheFrame(index, subsamplingLevel, CacheMetadataAndFrame);
     403
    446404    return m_frames[index].m_frame;
    447405}
    448 #endif
    449406
    450407bool BitmapImage::frameIsCompleteAtIndex(size_t index)
    451408{
    452 #if PLATFORM(IOS)
    453     // FIXME: cacheFrameInfo does not set m_isComplete. Should it?
    454     if (!ensureFrameInfoIsCached(index))
     409    if (!ensureFrameIsCached(index, CacheMetadataOnly))
    455410        return false;
    456 #else
    457     if (!ensureFrameIsCached(index))
    458         return false;
    459 #endif
     411
    460412    return m_frames[index].m_isComplete;
    461413}
     
    463415float BitmapImage::frameDurationAtIndex(size_t index)
    464416{
    465 #if PLATFORM(IOS)
    466     if (!ensureFrameInfoIsCached(index))
     417    if (!ensureFrameIsCached(index, CacheMetadataOnly))
    467418        return 0;
    468 #else
    469     if (!ensureFrameIsCached(index))
    470         return 0;
    471 #endif
     419
    472420    return m_frames[index].m_duration;
    473421}
     
    480428bool BitmapImage::frameHasAlphaAtIndex(size_t index)
    481429{
    482 #if PLATFORM(IOS)
    483     if (!ensureFrameInfoIsCached(index))
    484         return true; // FIXME: Why would an invalid index return true here?
    485 #else
    486     if (m_frames.size() <= index)
     430    if (!ensureFrameIsCached(index, CacheMetadataOnly))
    487431        return true;
    488 #endif
     432
    489433    if (m_frames[index].m_haveMetadata)
    490434        return m_frames[index].m_hasAlpha;
     
    500444ImageOrientation BitmapImage::frameOrientationAtIndex(size_t index)
    501445{
    502 #if PLATFORM(IOS)
    503     // FIXME: cacheFrameInfo does not set m_orientation. Should it?
    504     if (!ensureFrameInfoIsCached(index))
     446    if (!ensureFrameIsCached(index, CacheMetadataOnly))
    505447        return DefaultImageOrientation;
    506 #else
    507     if (!ensureFrameIsCached(index))
    508         return DefaultImageOrientation;
    509 #endif
    510448
    511449    if (m_frames[index].m_haveMetadata)
  • trunk/Source/WebCore/platform/graphics/BitmapImage.h

    r171119 r171957  
    7171        : m_frame(0)
    7272        , m_orientation(DefaultImageOrientation)
    73 #if PLATFORM(IOS)
    74         , m_subsamplingScale(0)
    75         , m_haveInfo(false)
    76 #endif
     73        , m_subsamplingLevel(0)
    7774        , m_duration(0)
    7875        , m_haveMetadata(false)
     
    9491    NativeImagePtr m_frame;
    9592    ImageOrientation m_orientation;
    96 #if PLATFORM(IOS)
    97     float m_subsamplingScale;
    98     bool m_haveInfo;
    99 #endif
     93    SubsamplingLevel m_subsamplingLevel;
    10094    float m_duration;
    10195    bool m_haveMetadata : 1;
     
    108102// BitmapImage Class
    109103// =================================================
    110 
    111 // FIXME: We should better integrate the iOS and non-iOS code in this class. Unlike other ports, the
    112 // iOS port caches the metadata for a frame without decoding the image.
    113104
    114105class BitmapImage final : public Image {
     
    138129    virtual FloatSize size() const override;
    139130    IntSize sizeRespectingOrientation(ImageOrientationDescription = ImageOrientationDescription()) const;
    140 #if PLATFORM(IOS)
    141     virtual FloatSize originalSize() const override;
    142     IntSize originalSizeRespectingOrientation() const;
    143 #endif
    144     IntSize currentFrameSize() const;
     131
    145132    virtual bool getHotSpot(IntPoint&) const override;
    146133
     
    195182    bool canAnimate();
    196183
     184    bool allowSubsampling() const { return m_allowSubsampling; }
     185    void setAllowSubsampling(bool allowSubsampling) { m_allowSubsampling = allowSubsampling; }
     186   
    197187private:
    198188    void updateSize(ImageOrientationDescription = ImageOrientationDescription()) const;
     189    void determineMinimumSubsamplingLevel() const;
    199190
    200191protected:
     
    219210
    220211    size_t currentFrame() const { return m_currentFrame; }
    221 #if PLATFORM(IOS)
    222     PassNativeImagePtr frameAtIndex(size_t, float scaleHint);
     212    size_t frameCount();
     213
     214    PassNativeImagePtr frameAtIndex(size_t, float presentationScaleHint = 1);
    223215    PassNativeImagePtr copyUnscaledFrameAtIndex(size_t);
    224 #endif
    225     size_t frameCount();
    226     PassNativeImagePtr frameAtIndex(size_t);
     216
     217    bool haveFrameAtIndex(size_t);
     218
    227219    bool frameIsCompleteAtIndex(size_t);
    228220    float frameDurationAtIndex(size_t);
     
    231223
    232224    // Decodes and caches a frame. Never accessed except internally.
    233 #if PLATFORM(IOS)
    234     void cacheFrame(size_t index, float scaleHint);
    235 
    236     // Cache frame metadata without decoding image.
    237     void cacheFrameInfo(size_t index);
     225    enum ImageFrameCaching { CacheMetadataOnly, CacheMetadataAndFrame };
     226    void cacheFrame(size_t index, SubsamplingLevel, ImageFrameCaching = CacheMetadataAndFrame);
     227
    238228    // Called before accessing m_frames[index] for info without decoding. Returns false on index out of bounds.
    239     bool ensureFrameInfoIsCached(size_t index);
    240 #else
    241     void cacheFrame(size_t index);
    242     // Called before accessing m_frames[index]. Returns false on index out of bounds.
    243     bool ensureFrameIsCached(size_t index);
    244 #endif
     229    bool ensureFrameIsCached(size_t index, ImageFrameCaching = CacheMetadataAndFrame);
    245230
    246231    // Called to invalidate cached data.  When |destroyAll| is true, we wipe out
     
    302287    mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image).
    303288    mutable IntSize m_sizeRespectingOrientation;
     289
     290    mutable SubsamplingLevel m_minimumSubsamplingLevel;
     291
    304292    mutable unsigned m_imageOrientation : 4; // ImageOrientationEnum
    305293    mutable unsigned m_shouldRespectImageOrientation : 1; // RespectImageOrientationEnum
    306294
    307 #if PLATFORM(IOS)
    308     mutable IntSize m_originalSize; // The size of the unsubsampled image.
    309     mutable IntSize m_originalSizeRespectingOrientation;
    310 #endif
    311295    size_t m_currentFrame; // The index of the current frame of animation.
    312296    Vector<FrameData, 1> m_frames; // An array of the cached frames of the animation. We have to ref frames to pin them in the cache.
     
    337321#endif
    338322
     323    bool m_allowSubsampling : 1; // Whether we should attempt subsampling if this image is very large.
    339324    bool m_isSolidColor : 1; // Whether or not we are a 1x1 solid image.
    340325    bool m_checkedForSolidColor : 1; // Whether we've checked the frame for solid color.
  • trunk/Source/WebCore/platform/graphics/GraphicsContext.h

    r169534 r171957  
    284284        void drawPath(const Path&);
    285285
    286         void drawNativeImage(PassNativeImagePtr, const FloatSize& selfSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, float scale = 1, CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, ImageOrientation = DefaultImageOrientation);
     286        void drawNativeImage(PassNativeImagePtr, const FloatSize& selfSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, ImageOrientation = DefaultImageOrientation);
    287287
    288288        // Allow font smoothing (LCD antialiasing). Not part of the graphics state.
  • trunk/Source/WebCore/platform/graphics/ImageSource.cpp

    r165676 r171957  
    3030#include "ImageSource.h"
    3131
     32#if !USE(CG)
     33
    3234#include "ImageDecoder.h"
    3335
     
    9597}
    9698
     99SubsamplingLevel ImageSource::subsamplingLevelForScale(float) const
     100{
     101    return 0;
     102}
     103
     104bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t) const
     105{
     106    return true;
     107}
     108
    97109bool ImageSource::isSizeAvailable()
    98110{
     
    102114IntSize ImageSource::size(ImageOrientationDescription description) const
    103115{
    104     return frameSizeAtIndex(0, description);
    105 }
    106 
    107 IntSize ImageSource::frameSizeAtIndex(size_t index, ImageOrientationDescription description) const
     116    return frameSizeAtIndex(0, 0, description);
     117}
     118
     119IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel, ImageOrientationDescription description) const
    108120{
    109121    if (!m_decoder)
     
    137149}
    138150
    139 PassNativeImagePtr ImageSource::createFrameAtIndex(size_t index, float* scale)
    140 {
    141     UNUSED_PARAM(scale);
    142 
     151PassNativeImagePtr ImageSource::createFrameAtIndex(size_t index, SubsamplingLevel)
     152{
    143153    if (!m_decoder)
    144154        return 0;
     
    198208}
    199209
    200 unsigned ImageSource::frameBytesAtIndex(size_t index) const
     210unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel) const
    201211{
    202212    if (!m_decoder)
     
    206216
    207217}
     218
     219#endif // USE(CG)
  • trunk/Source/WebCore/platform/graphics/ImageSource.h

    r168452 r171957  
    7878const int cAnimationNone = -2;
    7979
     80// SubsamplingLevel. 0 is no subsampling, 1 is half dimensions on each axis etc.
     81typedef short SubsamplingLevel;
     82
    8083class ImageSource {
    8184    WTF_MAKE_NONCOPYABLE(ImageSource);
     
    132135    String filenameExtension() const;
    133136
     137    SubsamplingLevel subsamplingLevelForScale(float) const;
     138    bool allowSubsamplingOfFrameAtIndex(size_t) const;
     139
    134140    bool isSizeAvailable();
     141    // Always original size, without subsampling.
    135142    IntSize size(ImageOrientationDescription = ImageOrientationDescription()) const;
    136     IntSize frameSizeAtIndex(size_t, ImageOrientationDescription = ImageOrientationDescription()) const;
    137 
    138 #if PLATFORM(IOS)
    139     IntSize originalSize(RespectImageOrientationEnum = DoNotRespectImageOrientation) const;
    140     bool isSubsampled() const { return m_baseSubsampling; }
    141 #endif
     143    // Size of optionally subsampled frame.
     144    IntSize frameSizeAtIndex(size_t, SubsamplingLevel = 0, ImageOrientationDescription = ImageOrientationDescription()) const;
    142145
    143146    bool getHotSpot(IntPoint&) const;
     
    151154    // Callers should not call this after calling clear() with a higher index;
    152155    // see comments on clear() above.
    153     PassNativeImagePtr createFrameAtIndex(size_t, float* scale = 0);
     156    PassNativeImagePtr createFrameAtIndex(size_t, SubsamplingLevel = 0);
    154157
    155158    float frameDurationAtIndex(size_t);
     
    160163    // Return the number of bytes in the decoded frame. If the frame is not yet
    161164    // decoded then return 0.
    162     unsigned frameBytesAtIndex(size_t) const;
     165    unsigned frameBytesAtIndex(size_t, SubsamplingLevel = 0) const;
    163166
    164167#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
     
    177180    static unsigned s_maxPixelsPerDecodedImage;
    178181#endif
    179 #if PLATFORM(IOS)
    180     mutable int m_baseSubsampling;
    181     mutable bool m_isProgressive;
    182     CFDictionaryRef imageSourceOptions(ShouldSkipMetadata, int subsampling = 0) const;
    183 #endif
    184182};
    185183
  • trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp

    r165676 r171957  
    120120}
    121121
     122void BitmapImage::determineMinimumSubsamplingLevel() const
     123{
     124    m_minimumSubsamplingLevel = 0;
     125}
     126
    122127void BitmapImage::checkForSolidColor()
    123128{
  • trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp

    r171119 r171957  
    3030
    3131#include "FloatConversion.h"
     32#include "GeometryUtilities.h"
    3233#include "GraphicsContextCG.h"
    3334#include "ImageObserver.h"
     
    5960
    6061    m_orientation = DefaultImageOrientation;
    61 
    62 #if PLATFORM(IOS)
    63     m_frameBytes = 0;
    64     m_subsamplingScale = 1;
    65     m_haveInfo = false;
    66 #endif
     62    m_subsamplingLevel = 0;
    6763
    6864    if (m_frame) {
     
    7975BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
    8076    : Image(observer)
     77    , m_minimumSubsamplingLevel(0)
     78    , m_imageOrientation(OriginTopLeft)
     79    , m_shouldRespectImageOrientation(false)
    8180    , m_currentFrame(0)
    82     , m_frames(0)
    8381    , m_repetitionCount(cAnimationNone)
    8482    , m_repetitionCountStatus(Unknown)
     
    104102    m_sizeRespectingOrientation = m_size;
    105103
    106 #if PLATFORM(IOS)
    107     m_originalSize = m_size;
    108     m_originalSizeRespectingOrientation = m_size;
    109 #endif
    110 
    111104    m_frames.grow(1);
    112105    m_frames[0].m_frame = CGImageRetain(cgImage);
     
    114107    m_frames[0].m_haveMetadata = true;
    115108
    116 #if PLATFORM(IOS)
    117     m_frames[0].m_subsamplingScale = 1;
    118 #endif
    119 
    120109    checkForSolidColor();
    121110}
    122111
    123 // Drawing Routines
     112void BitmapImage::determineMinimumSubsamplingLevel() const
     113{
     114    if (!m_allowSubsampling)
     115        return;
     116
     117    if (!m_source.allowSubsamplingOfFrameAtIndex(0))
     118        return;
     119
     120    // Values chosen to be appropriate for iOS.
     121    const int cMaximumImageAreaBeforeSubsampling = 5 * 1024 * 1024;
     122    const SubsamplingLevel maxSubsamplingLevel = 3;
     123
     124    SubsamplingLevel currentLevel = 0;
     125    for ( ; currentLevel <= maxSubsamplingLevel; ++currentLevel) {
     126        IntSize frameSize = m_source.frameSizeAtIndex(0, currentLevel);
     127        if (frameSize.area() < cMaximumImageAreaBeforeSubsampling)
     128            break;
     129    }
     130
     131    m_minimumSubsamplingLevel = currentLevel;
     132}
    124133
    125134void BitmapImage::checkForSolidColor()
    126135{
    127136    m_checkedForSolidColor = true;
    128     if (frameCount() > 1) {
    129         m_isSolidColor = false;
    130         return;
    131     }
    132 
    133 #if !PLATFORM(IOS)
    134     CGImageRef image = frameAtIndex(0);
    135 #else
    136     // Note, checkForSolidColor() may be called from frameAtIndex(). On iOS frameAtIndex() gets passed a scaleHint
    137     // argument which it uses to tell CG to create a scaled down image. Since we don't know the scaleHint here, if
    138     // we call frameAtIndex() again, we would pass it the default scale of 1 and would end up recreating the image.
    139     // So we do a quick check and call frameAtIndex(0) only if we haven't yet created an image.
     137    m_isSolidColor = false;
     138
     139    if (frameCount() > 1)
     140        return;
     141
     142    if (!haveFrameAtIndex(0)) {
     143        IntSize size = m_source.frameSizeAtIndex(0, 0);
     144        if (size.width() != 1 || size.height() != 1)
     145            return;
     146
     147        if (!ensureFrameIsCached(0))
     148            return;
     149    }
     150
    140151    CGImageRef image = nullptr;
    141152    if (m_frames.size())
     
    143154
    144155    if (!image)
    145         image = frameAtIndex(0);
    146 #endif
     156        return;
    147157
    148158    // Currently we only check for solid color in the important special case of a 1x1 image.
    149     if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) {
     159    if (CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) {
    150160        unsigned char pixel[4]; // RGBA
    151161        RetainPtr<CGContextRef> bitmapContext = adoptCF(CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), deviceRGBColorSpaceRef(),
     
    199209void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription description)
    200210{
    201     CGImageRef image;
    202     FloatRect srcRectForCurrentFrame = srcRect;
    203 
    204211#if PLATFORM(IOS)
    205     if (m_originalSize != m_size && !m_originalSize.isEmpty())
    206         srcRectForCurrentFrame.scale(m_size.width() / static_cast<float>(m_originalSize.width()), m_size.height() / static_cast<float>(m_originalSize.height()));
    207 
    208212    startAnimation(DoNotCatchUp);
    209 
    210     CGRect transformedDestinationRect = CGRectApplyAffineTransform(destRect, CGContextGetCTM(ctxt->platformContext()));
    211     RetainPtr<CGImageRef> imagePossiblyCopied;
    212     // Never use subsampled images for drawing into PDF contexts.
    213     if (CGContextGetType(ctxt->platformContext()) == kCGContextTypePDF)
    214         imagePossiblyCopied = adoptCF(copyUnscaledFrameAtIndex(m_currentFrame));
    215     else
    216         imagePossiblyCopied = frameAtIndex(m_currentFrame, std::min<float>(1.0f, std::max(transformedDestinationRect.size.width  / srcRectForCurrentFrame.width(), transformedDestinationRect.size.height / srcRectForCurrentFrame.height())));
    217 
    218     image = imagePossiblyCopied.get();
    219213#else
    220214    startAnimation();
    221 
    222     image = frameAtIndex(m_currentFrame);
    223 #endif
     215#endif
     216
     217    RetainPtr<CGImageRef> image;
     218    // Never use subsampled images for drawing into PDF contexts.
     219    if (wkCGContextIsPDFContext(ctxt->platformContext()))
     220        image = adoptCF(copyUnscaledFrameAtIndex(m_currentFrame));
     221    else {
     222        CGRect transformedDestinationRect = CGRectApplyAffineTransform(destRect, CGContextGetCTM(ctxt->platformContext()));
     223        float subsamplingScale = std::min<float>(1, std::max(transformedDestinationRect.size.width / srcRect.width(), transformedDestinationRect.size.height / srcRect.height()));
     224
     225        image = frameAtIndex(m_currentFrame, subsamplingScale);
     226    }
    224227
    225228    if (!image) // If it's too early we won't have an image yet.
     
    231234    }
    232235
    233     float scale = 1;
    234 #if PLATFORM(IOS)
    235     scale = m_frames[m_currentFrame].m_subsamplingScale;
    236 #endif
    237     FloatSize selfSize = currentFrameSize();
     236    // Subsampling may have given us an image that is smaller than size().
     237    IntSize imageSize(CGImageGetWidth(image.get()), CGImageGetHeight(image.get()));
     238   
     239    // srcRect is in the coordinates of the unsubsampled image, so we have to map it to the subsampled image.
     240    FloatRect scaledSrcRect = srcRect;
     241    if (imageSize != m_size) {
     242        FloatRect originalImageBounds(FloatPoint(), m_size);
     243        FloatRect subsampledImageBounds(FloatPoint(), imageSize);
     244        scaledSrcRect = mapRect(srcRect, originalImageBounds, subsampledImageBounds);
     245    }
     246   
    238247    ImageOrientation orientation;
    239 
    240248    if (description.respectImageOrientation() == RespectImageOrientation)
    241249        orientation = frameOrientationAtIndex(m_currentFrame);
    242250
    243     ctxt->drawNativeImage(image, selfSize, styleColorSpace, destRect, srcRectForCurrentFrame, scale, compositeOp, blendMode, orientation);
     251    ctxt->drawNativeImage(image.get(), imageSize, styleColorSpace, destRect, scaledSrcRect, compositeOp, blendMode, orientation);
    244252
    245253    if (imageObserver())
     
    247255}
    248256
    249 #if PLATFORM(IOS)
    250257PassNativeImagePtr BitmapImage::copyUnscaledFrameAtIndex(size_t index)
    251258{
     
    256263        cacheFrame(index, 1);
    257264
    258     if (m_frames[index].m_subsamplingScale == 1 && !m_source.isSubsampled())
     265    if (!m_frames[index].m_subsamplingLevel)
    259266        return CGImageRetain(m_frames[index].m_frame);
    260267
    261268    return m_source.createFrameAtIndex(index);
    262269}
    263 #endif
    264270
    265271}
  • trunk/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp

    r171119 r171957  
    333333        if (!decoder.frameCount())
    334334            return false;
    335 #if PLATFORM(IOS)
    336         float scaleHint = 1;
    337         if (m_image->isBitmapImage()) {
    338             FloatSize originalSize = toBitmapImage(m_image)->originalSize();
    339             if (!originalSize.isEmpty())
    340                 scaleHint = std::min<float>(1, std::max(m_image->size().width() / originalSize.width(), m_image->size().width() / originalSize.height()));
    341         }
    342         m_decodedImage = adoptCF(decoder.createFrameAtIndex(0, &scaleHint));
    343 #else
     335
    344336        m_decodedImage = adoptCF(decoder.createFrameAtIndex(0));
    345 #endif
    346337        m_cgImage = m_decodedImage.get();
    347338    } else
     
    546537    context->translate(0, -imageHeight);
    547538    context->setImageInterpolationQuality(InterpolationNone);
    548     context->drawNativeImage(cgImage.get(), imageSize, ColorSpaceDeviceRGB, canvasRect, FloatRect(FloatPoint(), imageSize), 1, CompositeCopy);
     539    context->drawNativeImage(cgImage.get(), imageSize, ColorSpaceDeviceRGB, canvasRect, FloatRect(FloatPoint(), imageSize), CompositeCopy);
    549540}
    550541
  • trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp

    r169623 r171957  
    170170}
    171171
    172 void GraphicsContext::drawNativeImage(PassNativeImagePtr imagePtr, const FloatSize& imageSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, float scale, CompositeOperator op, BlendMode blendMode, ImageOrientation orientation)
     172void GraphicsContext::drawNativeImage(PassNativeImagePtr imagePtr, const FloatSize& imageSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, ImageOrientation orientation)
    173173{
    174174    RetainPtr<CGImageRef> image(imagePtr);
    175175
    176176    float currHeight = orientation.usesWidthAsHeight() ? CGImageGetWidth(image.get()) : CGImageGetHeight(image.get());
    177 #if PLATFORM(IOS)
    178     // Unapply the scaling since we are getting this from a scaled bitmap.
    179     currHeight /= scale;
    180 #else
    181     UNUSED_PARAM(scale);
    182 #endif
    183 
    184177    if (currHeight <= srcRect.y())
    185178        return;
     
    222215            adjustedDestRect.setHeight(subimageRect.height() / yScale);
    223216
    224 #if PLATFORM(IOS)
    225             subimageRect.scale(scale, scale);
    226 #endif
    227217#if CACHE_SUBIMAGES
    228218            image = subimageCache().getSubimage(image.get(), subimageRect);
  • trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp

    r168577 r171957  
    302302    FloatRect adjustedSrcRect = srcRect;
    303303    adjustedSrcRect.scale(m_resolutionScale, m_resolutionScale);
    304     destContext->drawNativeImage(image.get(), m_data.m_backingStoreSize, colorSpace, destRect, adjustedSrcRect, 1, op, blendMode);
     304    destContext->drawNativeImage(image.get(), m_data.m_backingStoreSize, colorSpace, destRect, adjustedSrcRect, op, blendMode);
    305305}
    306306
  • trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp

    r168452 r171957  
    3939#else
    4040#include <CoreGraphics/CGImagePrivate.h>
    41 #include <CoreGraphics/CoreGraphics.h>
    42 #include <ImageIO/CGImageSourcePrivate.h>
    4341#include <ImageIO/ImageIO.h>
     42#include <wtf/NeverDestroyed.h>
    4443#include <wtf/RetainPtr.h>
     44#endif
     45
     46#if __has_include(<ImageIO/CGImageSourcePrivate.h>)
     47#import <ImageIO/CGImageSourcePrivate.h>
     48#else
     49const CFStringRef kCGImageSourceSubsampleFactor = CFSTR("kCGImageSourceSubsampleFactor");
    4550#endif
    4651
     
    7782ImageSource::ImageSource(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption)
    7883    : m_decoder(0)
    79 #if PLATFORM(IOS)
    80     , m_baseSubsampling(0)
    81     , m_isProgressive(false)
    82 #endif
    8384{
    8485    // FIXME: AlphaOption and GammaAndColorProfileOption are ignored.
     
    106107}
    107108
    108 #if !PLATFORM(IOS)
    109 static CFDictionaryRef imageSourceOptions(ImageSource::ShouldSkipMetadata skipMetaData)
    110 {
    111     static CFDictionaryRef options;
    112 
    113     if (!options) {
     109static CFDictionaryRef createImageSourceOptions(ImageSource::ShouldSkipMetadata skipMetaData, SubsamplingLevel subsamplingLevel)
     110{
     111    const CFBooleanRef imageSourceSkipMetadata = (skipMetaData == ImageSource::SkipMetadata) ? kCFBooleanTrue : kCFBooleanFalse;
     112   
     113    if (!subsamplingLevel) {
    114114        const unsigned numOptions = 3;
    115         const CFBooleanRef imageSourceSkipMetadata = (skipMetaData == ImageSource::SkipMetadata) ? kCFBooleanTrue : kCFBooleanFalse;
    116115        const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata };
    117116        const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, imageSourceSkipMetadata };
    118         options = CFDictionaryCreate(NULL, keys, values, numOptions,
    119             &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    120     }
     117        return CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
     118    }
     119
     120    short constrainedSubsamplingLevel = std::min<short>(3, std::max<short>(0, subsamplingLevel));
     121    int subsampleInt = 1 << constrainedSubsamplingLevel; // [0..3] => [1, 2, 4, 8]
     122
     123    RetainPtr<CFNumberRef> subsampleNumber = adoptCF(CFNumberCreate(nullptr,  kCFNumberIntType,  &subsampleInt));
     124    const CFIndex numOptions = 4;
     125    const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata, kCGImageSourceSubsampleFactor };
     126    const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, imageSourceSkipMetadata, subsampleNumber.get() };
     127    return CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
     128}
     129
     130static CFDictionaryRef imageSourceOptions(ImageSource::ShouldSkipMetadata skipMetadata = ImageSource::SkipMetadata, SubsamplingLevel subsamplingLevel = 0)
     131{
     132    if (subsamplingLevel)
     133        return createImageSourceOptions(skipMetadata, subsamplingLevel);
     134
     135    static CFDictionaryRef options = createImageSourceOptions(skipMetadata, 0);
    121136    return options;
    122137}
    123 #else
    124 CFDictionaryRef ImageSource::imageSourceOptions(ShouldSkipMetadata skipMetaData, int requestedSubsampling) const
    125 {
    126     static CFDictionaryRef options[4] = {nullptr, nullptr, nullptr, nullptr};
    127     int subsampling = std::min(3, m_isProgressive || requestedSubsampling < 0 ? 0 : (requestedSubsampling + m_baseSubsampling));
    128 
    129     if (!options[subsampling]) {
    130         int subsampleInt = 1 << subsampling; // [0..3] => [1, 2, 4, 8]
    131         RetainPtr<CFNumberRef> subsampleNumber = adoptCF(CFNumberCreate(nullptr,  kCFNumberIntType,  &subsampleInt));
    132         const CFIndex numOptions = 4;
    133         const CFBooleanRef imageSourceSkipMetaData = (skipMetaData == ImageSource::SkipMetadata) ? kCFBooleanTrue : kCFBooleanFalse;
    134         const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSubsampleFactor, kCGImageSourceSkipMetadata };
    135         const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, subsampleNumber.get(), imageSourceSkipMetaData };
    136         options[subsampling] = CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    137     }
    138     return options[subsampling];
    139 }
    140 #endif
    141138
    142139bool ImageSource::initialized() const
     
    183180}
    184181
     182SubsamplingLevel ImageSource::subsamplingLevelForScale(float scale) const
     183{
     184    // There are four subsampling levels: 0 = 1x, 1 = 0.5x, 2 = 0.25x, 3 = 0.125x.
     185    float clampedScale = std::max<float>(0.125, std::min<float>(1, scale));
     186    int result = ceilf(log2f(1 / clampedScale));
     187    ASSERT(result >=0 && result <= 3);
     188    return result;
     189}
     190
    185191bool ImageSource::isSizeAvailable()
    186192{
     
    190196    // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus!
    191197    if (imageSourceStatus >= kCGImageStatusIncomplete) {
    192         RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions(SkipMetadata)));
     198        RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()));
    193199        if (image0Properties) {
    194200            CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelWidth);
     
    213219}
    214220
    215 IntSize ImageSource::frameSizeAtIndex(size_t index, ImageOrientationDescription description) const
    216 {
    217     RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata)));
    218 
     221bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t) const
     222{
     223    RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()));
    219224    if (!properties)
    220         return IntSize();
    221 
    222     int w = 0, h = 0;
    223     CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
    224     if (num)
    225         CFNumberGetValue(num, kCFNumberIntType, &w);
    226     num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight);
    227     if (num)
    228         CFNumberGetValue(num, kCFNumberIntType, &h);
    229 
    230 #if PLATFORM(IOS)
    231     if (!m_isProgressive) {
    232         CFDictionaryRef jfifProperties = static_cast<CFDictionaryRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyJFIFDictionary));
    233         if (jfifProperties) {
    234             CFBooleanRef isProgCFBool = static_cast<CFBooleanRef>(CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive));
    235             if (isProgCFBool)
    236                 m_isProgressive = CFBooleanGetValue(isProgCFBool);
     225        return false;
     226
     227    CFDictionaryRef jfifProperties = static_cast<CFDictionaryRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyJFIFDictionary));
     228    if (jfifProperties) {
     229        CFBooleanRef isProgCFBool = static_cast<CFBooleanRef>(CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive));
     230        if (isProgCFBool) {
     231            bool isProgressive = CFBooleanGetValue(isProgCFBool);
    237232            // Workaround for <rdar://problem/5184655> - Hang rendering very large progressive JPEG. Decoding progressive
    238233            // images hangs for a very long time right now. Until this is fixed, don't sub-sample progressive images. This
    239234            // will cause them to fail our large image check and they won't be decoded.
    240235            // FIXME: Remove once underlying issue is fixed (<rdar://problem/5191418>)
     236            return !isProgressive;
    241237        }
    242238    }
    243239
    244     if ((m_baseSubsampling == 0) && !m_isProgressive) {
    245         IntSize subsampledSize(w, h);
    246         const int cMaximumImageSizeBeforeSubsampling = 5 * 1024 * 1024;
    247         while ((m_baseSubsampling < 3) && subsampledSize.width() * subsampledSize.height() > cMaximumImageSizeBeforeSubsampling) {
    248             // We know the size, but the actual image is very large and should be sub-sampled.
    249             // Increase the base subsampling and ask for the size again. If the image can be subsampled, the size will be
    250             // greatly reduced. 4x sub-sampling will make us support up to 320MP (5MP * 4^3) images, which should be plenty.
    251             // There's no callback from ImageIO when the size is available, so we do the check when we happen
    252             // to check the size and its non - zero.
    253             // Note: Some clients of this class don't call isSizeAvailable() so we can't rely on that.
    254             ++m_baseSubsampling;
    255             subsampledSize = frameSizeAtIndex(index, description.respectImageOrientation());
    256         }
    257         w = subsampledSize.width();
    258         h = subsampledSize.height();
    259     }
    260 #endif
     240    return true;
     241}
     242
     243IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageOrientationDescription description) const
     244{
     245    RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata, subsamplingLevel)));
     246
     247    if (!properties)
     248        return IntSize();
     249
     250    int width = 0;
     251    int height = 0;
     252    CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
     253    if (num)
     254        CFNumberGetValue(num, kCFNumberIntType, &width);
     255    num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight);
     256    if (num)
     257        CFNumberGetValue(num, kCFNumberIntType, &height);
    261258
    262259    if ((description.respectImageOrientation() == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight())
    263         return IntSize(h, w);
    264 
    265     return IntSize(w, h);
     260        return IntSize(height, width);
     261
     262    return IntSize(width, height);
    266263}
    267264
    268265ImageOrientation ImageSource::orientationAtIndex(size_t index) const
    269266{
    270     RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata)));
     267    RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()));
    271268    if (!properties)
    272269        return DefaultImageOrientation;
     
    275272}
    276273
    277 #if PLATFORM(IOS)
    278 IntSize ImageSource::originalSize(RespectImageOrientationEnum shouldRespectOrientation) const
    279 {
    280     frameSizeAtIndex(0, shouldRespectOrientation);
    281     RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions(SkipMetadata, -1)));
    282 
    283     if (!properties)
    284         return IntSize();
    285 
    286     int width = 0;
    287     int height = 0;
    288     CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
    289     if (number)
    290         CFNumberGetValue(number, kCFNumberIntType, &width);
    291     number = static_cast<CFNumberRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight));
    292     if (number)
    293         CFNumberGetValue(number, kCFNumberIntType, &height);
    294 
    295     if ((shouldRespectOrientation == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight())
    296         return IntSize(height, width);
    297 
    298     return IntSize(width, height);
    299 }
    300 #endif
    301 
    302274IntSize ImageSource::size(ImageOrientationDescription description) const
    303275{
    304     return frameSizeAtIndex(0, description);
     276    return frameSizeAtIndex(0, 0, description);
    305277}
    306278
    307279bool ImageSource::getHotSpot(IntPoint& hotSpot) const
    308280{
    309     RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions(SkipMetadata)));
     281    RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()));
    310282    if (!properties)
    311283        return false;
     
    343315        return cAnimationLoopOnce;
    344316
    345     RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_decoder, imageSourceOptions(SkipMetadata)));
     317    RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_decoder, imageSourceOptions()));
    346318    if (!properties)
    347319        return cAnimationLoopOnce;
     
    382354}
    383355
    384 CGImageRef ImageSource::createFrameAtIndex(size_t index, float* scale)
    385 {
    386     UNUSED_PARAM(scale);
    387 
     356CGImageRef ImageSource::createFrameAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
     357{
    388358    if (!initialized())
    389359        return 0;
    390360
    391 #if !PLATFORM(IOS)
    392     UNUSED_PARAM(scale);
    393     RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata)));
    394 #else
    395     // Subsampling can be 1, 2 or 3, which means quarter-, sixteenth- and sixty-fourth-size, respectively.
    396     // A zero or negative value means no subsampling.
    397     int subsampling = scale ? static_cast<int>(log2f(1.0f / std::max(0.1f, std::min(1.0f, *scale)))) : -1;
    398     RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata, subsampling)));
    399 
     361    RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata, subsamplingLevel)));
     362
     363#if PLATFORM(IOS)
    400364    // <rdar://problem/7371198> - CoreGraphics changed the default caching behaviour in iOS 4.0 to kCGImageCachingTransient
    401365    // which caused a performance regression for us since the images had to be resampled/recreated every time we called
     
    410374#pragma clang diagnostic pop
    411375#endif
    412     if (scale) {
    413         if (subsampling > 0)
    414             *scale = static_cast<float>(CGImageGetWidth(image.get())) / size(DoNotRespectImageOrientation).width();
    415         else {
    416             ASSERT(static_cast<int>(CGImageGetWidth(image.get())) == size(DoNotRespectImageOrientation).width());
    417             *scale = 1;
    418         }
    419     }
    420376#endif // !PLATFORM(IOS)
     377
    421378    CFStringRef imageUTI = CGImageSourceGetType(m_decoder);
    422379    static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image");
     
    486443    // for more information.
    487444    if (duration < 0.011f)
    488         return 0.100f;
     445        return 0.1f;
    489446    return duration;
    490447}
     
    511468}
    512469
    513 unsigned ImageSource::frameBytesAtIndex(size_t index) const
    514 {
    515     IntSize frameSize = frameSizeAtIndex(index, ImageOrientationDescription(RespectImageOrientation));
     470unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
     471{
     472    IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel, ImageOrientationDescription(RespectImageOrientation));
    516473    return frameSize.width() * frameSize.height() * 4;
    517474}
  • trunk/Source/WebCore/platform/graphics/mac/ImageMac.mm

    r165676 r171957  
    5858
    5959#if USE(APPKIT)
    60     m_nsImage = 0;
     60    m_nsImage = nullptr;
    6161#endif
    62     m_tiffRep = 0;
     62    m_tiffRep = nullptr;
    6363}
    6464
  • trunk/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp

    r158533 r171957  
    149149}
    150150
     151void BitmapImage::determineMinimumSubsamplingLevel() const
     152{
     153    m_minimumSubsamplingLevel = 0;
     154}
     155
    151156void BitmapImage::checkForSolidColor()
    152157{
Note: See TracChangeset for help on using the changeset viewer.