Diff
Modified: trunk/Source/WebCore/ChangeLog (172347 => 172348)
--- trunk/Source/WebCore/ChangeLog 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/ChangeLog 2014-08-08 18:55:51 UTC (rev 172348)
@@ -1,3 +1,126 @@
+2014-08-08 Simon Fraser <[email protected]>
+
+ 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.
+
+ Fix a couple of issues in the original pathc: remove a log, and ImageSource::allowSubsamplingOfFrameAtIndex()
+ return false.
+
+ * 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):
+
2014-08-08 Alex Christensen <[email protected]>
Progress towards using CMake on Mac.
Modified: trunk/Source/WebCore/WebCore.exp.in (172347 => 172348)
--- trunk/Source/WebCore/WebCore.exp.in 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/WebCore.exp.in 2014-08-08 18:55:51 UTC (rev 172348)
@@ -521,6 +521,7 @@
__ZN7WebCore15GraphicsContext11clearShadowEv
__ZN7WebCore15GraphicsContext12setFillColorERKNS_5ColorENS_10ColorSpaceE
__ZN7WebCore15GraphicsContext14setStrokeColorERKNS_5ColorENS_10ColorSpaceE
+__ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_NS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE
__ZN7WebCore15GraphicsContext15setFillGradientEN3WTF10PassRefPtrINS_8GradientEEE
__ZN7WebCore15GraphicsContext18setShouldAntialiasEb
__ZN7WebCore15GraphicsContext19setIsCALayerContextEb
@@ -2240,7 +2241,6 @@
__ZN7WebCore13getRawCookiesERKNS_21NetworkStorageSessionERKNS_3URLES5_RN3WTF6VectorINS_6CookieELm0ENS6_15CrashOnOverflowEEE
__ZN7WebCore13toDeviceSpaceERKNS_9FloatRectEP8NSWindow
__ZN7WebCore14cookiesEnabledERKNS_21NetworkStorageSessionERKNS_3URLES5_
-__ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_fNS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE
__ZN7WebCore15GraphicsContextC1EP9CGContext
__ZN7WebCore15ResourceRequest41updateFromDelegatePreservingOldPropertiesERKS0_
__ZN7WebCore16FontPlatformDataC1EP6NSFontfbbbNS_15FontOrientationENS_16FontWidthVariantE
@@ -2591,7 +2591,6 @@
__ZN7WebCore15DatabaseTracker7trackerEv
__ZN7WebCore15GraphicsContext12drawBidiTextERKNS_4FontERKNS_7TextRunERKNS_10FloatPointENS1_24CustomFontNotReadyActionEPNS_10BidiStatusEi
__ZN7WebCore15GraphicsContext15drawLineForTextERKNS_10FloatPointEfbb
-__ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_fNS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE
__ZN7WebCore15GraphicsContext22setEmojiDrawingEnabledEb
__ZN7WebCore15GraphicsContext23setIsAcceleratedContextEb
__ZN7WebCore15GraphicsContextC1EP9CGContextb
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (172347 => 172348)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2014-08-08 18:55:51 UTC (rev 172348)
@@ -473,6 +473,7 @@
0F1774801378B772009DA76A /* ScrollAnimatorIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F17747E1378B771009DA76A /* ScrollAnimatorIOS.h */; };
0F1774811378B772009DA76A /* ScrollAnimatorIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F17747F1378B772009DA76A /* ScrollAnimatorIOS.mm */; };
0F29C16E1300C2E2002D794E /* AccessibilityAllInOne.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F29C16D1300C2E2002D794E /* AccessibilityAllInOne.cpp */; };
+ 0F3C725E1974874B00AEDD0C /* ImageSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3C725D1974874B00AEDD0C /* ImageSource.cpp */; };
0F3DD44F12F5EA1B000D9190 /* ShadowBlur.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3DD44D12F5EA1B000D9190 /* ShadowBlur.cpp */; };
0F3DD45012F5EA1B000D9190 /* ShadowBlur.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3DD44E12F5EA1B000D9190 /* ShadowBlur.h */; };
0F3F0E59157030C3006DA57F /* RenderGeometryMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3F0E57157030C3006DA57F /* RenderGeometryMap.cpp */; };
@@ -7407,6 +7408,7 @@
0F17747E1378B771009DA76A /* ScrollAnimatorIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScrollAnimatorIOS.h; path = ios/ScrollAnimatorIOS.h; sourceTree = "<group>"; };
0F17747F1378B772009DA76A /* ScrollAnimatorIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ScrollAnimatorIOS.mm; path = ios/ScrollAnimatorIOS.mm; sourceTree = "<group>"; };
0F29C16D1300C2E2002D794E /* AccessibilityAllInOne.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityAllInOne.cpp; sourceTree = "<group>"; };
+ 0F3C725D1974874B00AEDD0C /* ImageSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageSource.cpp; sourceTree = "<group>"; };
0F3DD44D12F5EA1B000D9190 /* ShadowBlur.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShadowBlur.cpp; sourceTree = "<group>"; };
0F3DD44E12F5EA1B000D9190 /* ShadowBlur.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowBlur.h; sourceTree = "<group>"; };
0F3F0E57157030C3006DA57F /* RenderGeometryMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderGeometryMap.cpp; sourceTree = "<group>"; };
@@ -20459,6 +20461,7 @@
A8748D6612CC3763001FBA41 /* ImageOrientation.h */,
49291E4A134172C800E753DE /* ImageRenderingMode.h */,
B27535430B053814002CE64F /* ImageSource.h */,
+ 0F3C725D1974874B00AEDD0C /* ImageSource.cpp */,
07941793166EA04E009416C2 /* InbandTextTrackPrivate.h */,
07CE77D416712A6A00C55A47 /* InbandTextTrackPrivateClient.h */,
2D46F04D17B96FBD005647F0 /* IntPoint.cpp */,
@@ -29402,6 +29405,7 @@
97BC6A441505F081001B74AC /* SQLResultSetRowList.cpp in Sources */,
97BC6A471505F081001B74AC /* SQLStatement.cpp in Sources */,
FE8A674716CDD19E00930BF8 /* SQLStatementBackend.cpp in Sources */,
+ 0F3C725E1974874B00AEDD0C /* ImageSource.cpp in Sources */,
97BC6A4D1505F081001B74AC /* SQLStatementSync.cpp in Sources */,
97BC6A4F1505F081001B74AC /* SQLTransaction.cpp in Sources */,
FEE1811316C319E800084849 /* SQLTransactionBackend.cpp in Sources */,
Modified: trunk/Source/WebCore/loader/cache/CachedImage.cpp (172347 => 172348)
--- trunk/Source/WebCore/loader/cache/CachedImage.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/loader/cache/CachedImage.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -289,16 +289,7 @@
}
#else
if (m_image->isBitmapImage() && (renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation))
-#if !PLATFORM(IOS)
imageSize = LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
-#else
- {
- // On iOS, the image may have been subsampled to accommodate our size restrictions. However
- // we should tell the renderer what the original size was.
- imageSize = LayoutSize(toBitmapImage(m_image.get())->originalSizeRespectingOrientation());
- } else if (m_image->isBitmapImage())
- imageSize = LayoutSize(toBitmapImage(m_image.get())->originalSize());
-#endif // !PLATFORM(IOS)
#endif // ENABLE(CSS_IMAGE_ORIENTATION)
else if (m_image->isSVGImage() && sizeType == UsedSize) {
@@ -352,6 +343,7 @@
// Create the image if it doesn't yet exist.
if (m_image)
return;
+
#if USE(CG) && !USE(WEBKIT_IMAGE_DECODERS)
else if (m_response.mimeType() == "application/pdf")
m_image = PDFDocumentImage::create(this);
@@ -360,8 +352,10 @@
RefPtr<SVGImage> svgImage = SVGImage::create(this);
m_svgImageCache = std::make_unique<SVGImageCache>(svgImage.get());
m_image = svgImage.release();
- } else
+ } else {
m_image = BitmapImage::create(this);
+ toBitmapImage(m_image.get())->setAllowSubsampling(m_loader && m_loader->frameLoader()->frame().settings().imageSubsamplingEnabled());
+ }
if (m_image) {
// Send queued container size requests.
@@ -518,8 +512,6 @@
bool CachedImage::currentFrameKnownToBeOpaque(const RenderElement* renderer)
{
Image* image = imageForRenderer(renderer);
- if (image->isBitmapImage())
- image->nativeImageForCurrentFrame(); // force decode
return image->currentFrameKnownToBeOpaque();
}
Modified: trunk/Source/WebCore/loader/cache/CachedImage.h (172347 => 172348)
--- trunk/Source/WebCore/loader/cache/CachedImage.h 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/loader/cache/CachedImage.h 2014-08-08 18:55:51 UTC (rev 172348)
@@ -59,7 +59,7 @@
Image* image(); // Returns the nullImage() if the image is not available yet.
Image* imageForRenderer(const RenderObject*); // Returns the nullImage() if the image is not available yet.
bool hasImage() const { return m_image.get(); }
- bool currentFrameKnownToBeOpaque(const RenderElement*); // Side effect: ensures decoded image is in cache, therefore should only be called when about to draw the image.
+ bool currentFrameKnownToBeOpaque(const RenderElement*);
std::pair<Image*, float> brokenImage(float deviceScaleFactor) const; // Returns an image and the image's resolution scale factor.
bool willPaintBrokenImage() const;
Modified: trunk/Source/WebCore/page/Settings.cpp (172347 => 172348)
--- trunk/Source/WebCore/page/Settings.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/page/Settings.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -127,6 +127,7 @@
static const bool defaultMediaPlaybackAllowsInline = false;
static const bool defaultMediaPlaybackRequiresUserGesture = true;
static const bool defaultShouldRespectImageOrientation = true;
+static const bool defaultImageSubsamplingEnabled = true;
static const bool defaultScrollingTreeIncludesFrames = true;
#else
static const bool defaultFixedPositionCreatesStackingContext = false;
@@ -135,6 +136,7 @@
static const bool defaultMediaPlaybackAllowsInline = true;
static const bool defaultMediaPlaybackRequiresUserGesture = false;
static const bool defaultShouldRespectImageOrientation = false;
+static const bool defaultImageSubsamplingEnabled = false;
static const bool defaultScrollingTreeIncludesFrames = false;
#endif
Modified: trunk/Source/WebCore/page/Settings.in (172347 => 172348)
--- trunk/Source/WebCore/page/Settings.in 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/page/Settings.in 2014-08-08 18:55:51 UTC (rev 172348)
@@ -141,6 +141,7 @@
needsIsLoadingInAPISenseQuirk initial=false
shouldRespectImageOrientation initial=defaultShouldRespectImageOrientation
+imageSubsamplingEnabled initial=defaultImageSubsamplingEnabled
wantsBalancedSetDefersLoadingBehavior initial=false
requestAnimationFrameEnabled initial=true
deviceSupportsTouch initial=false
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -44,12 +44,12 @@
namespace WebCore {
-// FIXME: We should better integrate the iOS and non-iOS code in this class. Unlike other ports, the
-// iOS port caches the metadata for a frame without decoding the image.
BitmapImage::BitmapImage(ImageObserver* observer)
: Image(observer)
+ , m_minimumSubsamplingLevel(0)
+ , m_imageOrientation(OriginTopLeft)
+ , m_shouldRespectImageOrientation(false)
, m_currentFrame(0)
- , m_frames(0)
, m_repetitionCount(cAnimationNone)
, m_repetitionCountStatus(Unknown)
, m_repetitionsComplete(0)
@@ -61,6 +61,9 @@
// FIXME: We should expose a setting to enable/disable progressive loading remove the PLATFORM(IOS)-guard.
, m_progressiveLoadChunkTime(0)
, m_progressiveLoadChunkCount(0)
+ , m_allowSubsampling(true)
+#else
+ , m_allowSubsampling(false)
#endif
, m_isSolidColor(false)
, m_checkedForSolidColor(false)
@@ -80,6 +83,17 @@
stopAnimation();
}
+bool BitmapImage::haveFrameAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return false;
+
+ if (index >= m_frames.size())
+ return false;
+
+ return m_frames[index].m_frame;
+}
+
bool BitmapImage::hasSingleSecurityOrigin() const
{
return true;
@@ -152,11 +166,7 @@
imageObserver()->decodedSizeChanged(this, -safeCast<int>(frameBytesCleared));
}
-#if PLATFORM(IOS)
-void BitmapImage::cacheFrame(size_t index, float scaleHint)
-#else
-void BitmapImage::cacheFrame(size_t index)
-#endif
+void BitmapImage::cacheFrame(size_t index, SubsamplingLevel subsamplingLevel, ImageFrameCaching frameCaching)
{
size_t numFrames = frameCount();
ASSERT(m_decodedSize == 0 || numFrames > 1);
@@ -164,26 +174,27 @@
if (m_frames.size() < numFrames)
m_frames.grow(numFrames);
-#if PLATFORM(IOS)
- m_frames[index].m_frame = m_source.createFrameAtIndex(index, &scaleHint);
- m_frames[index].m_subsamplingScale = scaleHint;
-#else
- m_frames[index].m_frame = m_source.createFrameAtIndex(index);
-#endif
- if (numFrames == 1 && m_frames[index].m_frame)
- checkForSolidColor();
+ if (frameCaching == CacheMetadataAndFrame) {
+ m_frames[index].m_frame = m_source.createFrameAtIndex(index, subsamplingLevel);
+ m_frames[index].m_subsamplingLevel = subsamplingLevel;
+ if (numFrames == 1 && m_frames[index].m_frame)
+ checkForSolidColor();
+ }
m_frames[index].m_orientation = m_source.orientationAtIndex(index);
m_frames[index].m_haveMetadata = true;
m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index);
+
if (repetitionCount(false) != cAnimationNone)
m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
+
m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
- m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index);
+ m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index, subsamplingLevel);
- const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size);
- if (frameSize != m_size)
+ const IntSize frameSize(index ? m_source.frameSizeAtIndex(index, subsamplingLevel) : m_size);
+ if (!subsamplingLevel && frameSize != m_size)
m_hasUniformFrameSize = false;
+
if (m_frames[index].m_frame) {
int deltaBytes = safeCast<int>(m_frames[index].m_frameBytes);
m_decodedSize += deltaBytes;
@@ -196,30 +207,15 @@
}
}
-#if PLATFORM(IOS)
-void BitmapImage::cacheFrameInfo(size_t index)
-{
- size_t numFrames = frameCount();
-
- if (m_frames.size() < numFrames)
- m_frames.resize(numFrames);
-
- ASSERT(!m_frames[index].m_haveInfo);
-
- if (shouldAnimate())
- m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
- m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
- m_frames[index].m_haveInfo = true;
-}
-#endif
-
void BitmapImage::didDecodeProperties() const
{
if (m_decodedSize)
return;
+
size_t updatedSize = m_source.bytesDecodedToDetermineProperties();
if (m_decodedPropertiesSize == updatedSize)
return;
+
int deltaBytes = updatedSize - m_decodedPropertiesSize;
#if !ASSERT_DISABLED
bool overflow = updatedSize > m_decodedPropertiesSize && deltaBytes < 0;
@@ -238,13 +234,13 @@
m_size = m_source.size(description);
m_sizeRespectingOrientation = m_source.size(ImageOrientationDescription(RespectImageOrientation, description.imageOrientation()));
+
m_imageOrientation = static_cast<unsigned>(description.imageOrientation());
m_shouldRespectImageOrientation = static_cast<unsigned>(description.respectImageOrientation());
-#if PLATFORM(IOS)
- m_originalSize = m_source.originalSize();
- m_originalSizeRespectingOrientation = m_source.originalSize(RespectImageOrientation);
-#endif
+
m_haveSize = true;
+
+ determineMinimumSubsamplingLevel();
didDecodeProperties();
}
@@ -260,29 +256,6 @@
return m_sizeRespectingOrientation;
}
-#if PLATFORM(IOS)
-FloatSize BitmapImage::originalSize() const
-{
- updateSize();
- return m_originalSize;
-}
-
-IntSize BitmapImage::originalSizeRespectingOrientation() const
-{
- updateSize();
- return m_originalSizeRespectingOrientation;
-}
-#endif
-
-IntSize BitmapImage::currentFrameSize() const
-{
- if (!m_currentFrame || m_hasUniformFrameSize)
- return IntSize(size());
- IntSize frameSize = m_source.frameSizeAtIndex(m_currentFrame);
- didDecodeProperties();
- return frameSize;
-}
-
bool BitmapImage::getHotSpot(IntPoint& hotSpot) const
{
bool result = m_source.getHotSpot(hotSpot);
@@ -323,6 +296,7 @@
}
destroyMetadataAndNotify(frameBytesCleared);
#else
+ // FIXME: why is this different for iOS?
int deltaBytes = 0;
if (!m_frames.isEmpty()) {
int bytes = m_frames[m_frames.size() - 1].m_frameBytes;
@@ -390,85 +364,58 @@
return m_sizeAvailable;
}
-#if !PLATFORM(IOS)
-bool BitmapImage::ensureFrameIsCached(size_t index)
+bool BitmapImage::ensureFrameIsCached(size_t index, ImageFrameCaching frameCaching)
{
if (index >= frameCount())
return false;
- if (index >= m_frames.size() || !m_frames[index].m_frame)
- cacheFrame(index);
- return true;
-}
-#else
-bool BitmapImage::ensureFrameInfoIsCached(size_t index)
-{
- if (index >= frameCount())
- return false;
+ if (index >= m_frames.size()
+ || (frameCaching == CacheMetadataAndFrame && !m_frames[index].m_frame)
+ || (frameCaching == CacheMetadataOnly && !m_frames[index].m_haveMetadata))
+ cacheFrame(index, 0, frameCaching);
- if (index >= m_frames.size() || !m_frames[index].m_haveInfo)
- cacheFrameInfo(index);
return true;
}
-#endif
-PassNativeImagePtr BitmapImage::frameAtIndex(size_t index)
+PassNativeImagePtr BitmapImage::frameAtIndex(size_t index, float presentationScaleHint)
{
-#if PLATFORM(IOS)
- return frameAtIndex(index, 1.0f);
-#else
- if (!ensureFrameIsCached(index))
- return nullptr;
- return m_frames[index].m_frame;
-#endif
-}
-
-#if PLATFORM(IOS)
-PassNativeImagePtr BitmapImage::frameAtIndex(size_t index, float scaleHint)
-{
if (index >= frameCount())
return nullptr;
- if (index >= m_frames.size() || !m_frames[index].m_frame)
- cacheFrame(index, scaleHint);
- else if (std::min(1.0f, scaleHint) > m_frames[index].m_subsamplingScale) {
+ SubsamplingLevel subsamplingLevel = std::min(m_source.subsamplingLevelForScale(presentationScaleHint), m_minimumSubsamplingLevel);
+
+ // We may have cached a frame with a higher subsampling level, in which case we need to
+ // re-decode with a lower level.
+ if (index < m_frames.size() && m_frames[index].m_frame && subsamplingLevel < m_frames[index].m_subsamplingLevel) {
// If the image is already cached, but at too small a size, re-decode a larger version.
int sizeChange = -m_frames[index].m_frameBytes;
- ASSERT(static_cast<int>(m_decodedSize) + sizeChange >= 0);
m_frames[index].clear(true);
invalidatePlatformData();
m_decodedSize += sizeChange;
if (imageObserver())
imageObserver()->decodedSizeChanged(this, sizeChange);
-
- cacheFrame(index, scaleHint);
}
+
+ // If we haven't fetched a frame yet, do so.
+ if (index >= m_frames.size() || !m_frames[index].m_frame)
+ cacheFrame(index, subsamplingLevel, CacheMetadataAndFrame);
+
return m_frames[index].m_frame;
}
-#endif
bool BitmapImage::frameIsCompleteAtIndex(size_t index)
{
-#if PLATFORM(IOS)
- // FIXME: cacheFrameInfo does not set m_isComplete. Should it?
- if (!ensureFrameInfoIsCached(index))
+ if (!ensureFrameIsCached(index, CacheMetadataOnly))
return false;
-#else
- if (!ensureFrameIsCached(index))
- return false;
-#endif
+
return m_frames[index].m_isComplete;
}
float BitmapImage::frameDurationAtIndex(size_t index)
{
-#if PLATFORM(IOS)
- if (!ensureFrameInfoIsCached(index))
+ if (!ensureFrameIsCached(index, CacheMetadataOnly))
return 0;
-#else
- if (!ensureFrameIsCached(index))
- return 0;
-#endif
+
return m_frames[index].m_duration;
}
@@ -479,13 +426,9 @@
bool BitmapImage::frameHasAlphaAtIndex(size_t index)
{
-#if PLATFORM(IOS)
- if (!ensureFrameInfoIsCached(index))
- return true; // FIXME: Why would an invalid index return true here?
-#else
- if (m_frames.size() <= index)
+ if (!ensureFrameIsCached(index, CacheMetadataOnly))
return true;
-#endif
+
if (m_frames[index].m_haveMetadata)
return m_frames[index].m_hasAlpha;
@@ -499,14 +442,8 @@
ImageOrientation BitmapImage::frameOrientationAtIndex(size_t index)
{
-#if PLATFORM(IOS)
- // FIXME: cacheFrameInfo does not set m_orientation. Should it?
- if (!ensureFrameInfoIsCached(index))
+ if (!ensureFrameIsCached(index, CacheMetadataOnly))
return DefaultImageOrientation;
-#else
- if (!ensureFrameIsCached(index))
- return DefaultImageOrientation;
-#endif
if (m_frames[index].m_haveMetadata)
return m_frames[index].m_orientation;
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.h 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h 2014-08-08 18:55:51 UTC (rev 172348)
@@ -70,10 +70,7 @@
FrameData()
: m_frame(0)
, m_orientation(DefaultImageOrientation)
-#if PLATFORM(IOS)
- , m_subsamplingScale(0)
- , m_haveInfo(false)
-#endif
+ , m_subsamplingLevel(0)
, m_duration(0)
, m_haveMetadata(false)
, m_isComplete(false)
@@ -93,10 +90,7 @@
NativeImagePtr m_frame;
ImageOrientation m_orientation;
-#if PLATFORM(IOS)
- float m_subsamplingScale;
- bool m_haveInfo;
-#endif
+ SubsamplingLevel m_subsamplingLevel;
float m_duration;
bool m_haveMetadata : 1;
bool m_isComplete : 1;
@@ -108,9 +102,6 @@
// BitmapImage Class
// =================================================
-// FIXME: We should better integrate the iOS and non-iOS code in this class. Unlike other ports, the
-// iOS port caches the metadata for a frame without decoding the image.
-
class BitmapImage final : public Image {
friend class GeneratedImage;
friend class CrossfadeGeneratedImage;
@@ -137,11 +128,7 @@
// FloatSize due to override.
virtual FloatSize size() const override;
IntSize sizeRespectingOrientation(ImageOrientationDescription = ImageOrientationDescription()) const;
-#if PLATFORM(IOS)
- virtual FloatSize originalSize() const override;
- IntSize originalSizeRespectingOrientation() const;
-#endif
- IntSize currentFrameSize() const;
+
virtual bool getHotSpot(IntPoint&) const override;
unsigned decodedSize() const { return m_decodedSize; }
@@ -194,8 +181,12 @@
bool canAnimate();
+ bool allowSubsampling() const { return m_allowSubsampling; }
+ void setAllowSubsampling(bool allowSubsampling) { m_allowSubsampling = allowSubsampling; }
+
private:
void updateSize(ImageOrientationDescription = ImageOrientationDescription()) const;
+ void determineMinimumSubsamplingLevel() const;
protected:
enum RepetitionCountStatus {
@@ -218,30 +209,24 @@
#endif
size_t currentFrame() const { return m_currentFrame; }
-#if PLATFORM(IOS)
- PassNativeImagePtr frameAtIndex(size_t, float scaleHint);
- PassNativeImagePtr copyUnscaledFrameAtIndex(size_t);
-#endif
size_t frameCount();
- PassNativeImagePtr frameAtIndex(size_t);
+
+ PassNativeImagePtr frameAtIndex(size_t, float presentationScaleHint = 1);
+ PassNativeImagePtr copyUnscaledFrameAtIndex(size_t);
+
+ bool haveFrameAtIndex(size_t);
+
bool frameIsCompleteAtIndex(size_t);
float frameDurationAtIndex(size_t);
bool frameHasAlphaAtIndex(size_t);
ImageOrientation frameOrientationAtIndex(size_t);
// Decodes and caches a frame. Never accessed except internally.
-#if PLATFORM(IOS)
- void cacheFrame(size_t index, float scaleHint);
+ enum ImageFrameCaching { CacheMetadataOnly, CacheMetadataAndFrame };
+ void cacheFrame(size_t index, SubsamplingLevel, ImageFrameCaching = CacheMetadataAndFrame);
- // Cache frame metadata without decoding image.
- void cacheFrameInfo(size_t index);
// Called before accessing m_frames[index] for info without decoding. Returns false on index out of bounds.
- bool ensureFrameInfoIsCached(size_t index);
-#else
- void cacheFrame(size_t index);
- // Called before accessing m_frames[index]. Returns false on index out of bounds.
- bool ensureFrameIsCached(size_t index);
-#endif
+ bool ensureFrameIsCached(size_t index, ImageFrameCaching = CacheMetadataAndFrame);
// Called to invalidate cached data. When |destroyAll| is true, we wipe out
// the entire frame buffer cache and tell the image source to destroy
@@ -301,13 +286,12 @@
ImageSource m_source;
mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image).
mutable IntSize m_sizeRespectingOrientation;
+
+ mutable SubsamplingLevel m_minimumSubsamplingLevel;
+
mutable unsigned m_imageOrientation : 4; // ImageOrientationEnum
mutable unsigned m_shouldRespectImageOrientation : 1; // RespectImageOrientationEnum
-#if PLATFORM(IOS)
- mutable IntSize m_originalSize; // The size of the unsubsampled image.
- mutable IntSize m_originalSizeRespectingOrientation;
-#endif
size_t m_currentFrame; // The index of the current frame of animation.
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.
@@ -336,6 +320,7 @@
uint16_t m_progressiveLoadChunkCount;
#endif
+ bool m_allowSubsampling : 1; // Whether we should attempt subsampling if this image is very large.
bool m_isSolidColor : 1; // Whether or not we are a 1x1 solid image.
bool m_checkedForSolidColor : 1; // Whether we've checked the frame for solid color.
Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.h (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/GraphicsContext.h 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.h 2014-08-08 18:55:51 UTC (rev 172348)
@@ -283,7 +283,7 @@
void applyFillPattern();
void drawPath(const Path&);
- void drawNativeImage(PassNativeImagePtr, const FloatSize& selfSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, float scale = 1, CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, ImageOrientation = DefaultImageOrientation);
+ void drawNativeImage(PassNativeImagePtr, const FloatSize& selfSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, ImageOrientation = DefaultImageOrientation);
// Allow font smoothing (LCD antialiasing). Not part of the graphics state.
void setAllowsFontSmoothing(bool);
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -29,6 +29,8 @@
#include "config.h"
#include "ImageSource.h"
+#if !USE(CG)
+
#include "ImageDecoder.h"
#include "ImageOrientation.h"
@@ -94,6 +96,16 @@
return m_decoder ? m_decoder->filenameExtension() : String();
}
+SubsamplingLevel ImageSource::subsamplingLevelForScale(float) const
+{
+ return 0;
+}
+
+bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t) const
+{
+ return false;
+}
+
bool ImageSource::isSizeAvailable()
{
return m_decoder && m_decoder->isSizeAvailable();
@@ -101,10 +113,10 @@
IntSize ImageSource::size(ImageOrientationDescription description) const
{
- return frameSizeAtIndex(0, description);
+ return frameSizeAtIndex(0, 0, description);
}
-IntSize ImageSource::frameSizeAtIndex(size_t index, ImageOrientationDescription description) const
+IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel, ImageOrientationDescription description) const
{
if (!m_decoder)
return IntSize();
@@ -136,10 +148,8 @@
return m_decoder ? m_decoder->frameCount() : 0;
}
-PassNativeImagePtr ImageSource::createFrameAtIndex(size_t index, float* scale)
+PassNativeImagePtr ImageSource::createFrameAtIndex(size_t index, SubsamplingLevel)
{
- UNUSED_PARAM(scale);
-
if (!m_decoder)
return 0;
@@ -197,7 +207,7 @@
return buffer && buffer->status() == ImageFrame::FrameComplete;
}
-unsigned ImageSource::frameBytesAtIndex(size_t index) const
+unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel) const
{
if (!m_decoder)
return 0;
@@ -205,3 +215,5 @@
}
}
+
+#endif // USE(CG)
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/ImageSource.h 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h 2014-08-08 18:55:51 UTC (rev 172348)
@@ -77,6 +77,9 @@
const int cAnimationLoopInfinite = -1;
const int cAnimationNone = -2;
+// SubsamplingLevel. 0 is no subsampling, 1 is half dimensions on each axis etc.
+typedef short SubsamplingLevel;
+
class ImageSource {
WTF_MAKE_NONCOPYABLE(ImageSource);
public:
@@ -131,15 +134,15 @@
void setData(SharedBuffer* data, bool allDataReceived);
String filenameExtension() const;
+ SubsamplingLevel subsamplingLevelForScale(float) const;
+ bool allowSubsamplingOfFrameAtIndex(size_t) const;
+
bool isSizeAvailable();
+ // Always original size, without subsampling.
IntSize size(ImageOrientationDescription = ImageOrientationDescription()) const;
- IntSize frameSizeAtIndex(size_t, ImageOrientationDescription = ImageOrientationDescription()) const;
+ // Size of optionally subsampled frame.
+ IntSize frameSizeAtIndex(size_t, SubsamplingLevel = 0, ImageOrientationDescription = ImageOrientationDescription()) const;
-#if PLATFORM(IOS)
- IntSize originalSize(RespectImageOrientationEnum = DoNotRespectImageOrientation) const;
- bool isSubsampled() const { return m_baseSubsampling; }
-#endif
-
bool getHotSpot(IntPoint&) const;
size_t bytesDecodedToDetermineProperties() const;
@@ -150,7 +153,7 @@
// Callers should not call this after calling clear() with a higher index;
// see comments on clear() above.
- PassNativeImagePtr createFrameAtIndex(size_t, float* scale = 0);
+ PassNativeImagePtr createFrameAtIndex(size_t, SubsamplingLevel = 0);
float frameDurationAtIndex(size_t);
bool frameHasAlphaAtIndex(size_t); // Whether or not the frame actually used any alpha.
@@ -159,7 +162,7 @@
// Return the number of bytes in the decoded frame. If the frame is not yet
// decoded then return 0.
- unsigned frameBytesAtIndex(size_t) const;
+ unsigned frameBytesAtIndex(size_t, SubsamplingLevel = 0) const;
#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
static unsigned maxPixelsPerDecodedImage() { return s_maxPixelsPerDecodedImage; }
@@ -176,11 +179,6 @@
#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
static unsigned s_maxPixelsPerDecodedImage;
#endif
-#if PLATFORM(IOS)
- mutable int m_baseSubsampling;
- mutable bool m_isProgressive;
- CFDictionaryRef imageSourceOptions(ShouldSkipMetadata, int subsampling = 0) const;
-#endif
};
}
Modified: trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -119,6 +119,11 @@
imageObserver()->didDraw(this);
}
+void BitmapImage::determineMinimumSubsamplingLevel() const
+{
+ m_minimumSubsamplingLevel = 0;
+}
+
void BitmapImage::checkForSolidColor()
{
m_isSolidColor = false;
Modified: trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -29,6 +29,7 @@
#if USE(CG)
#include "FloatConversion.h"
+#include "GeometryUtilities.h"
#include "GraphicsContextCG.h"
#include "ImageObserver.h"
#include "SubimageCacheWithTimer.h"
@@ -58,13 +59,8 @@
m_haveMetadata = false;
m_orientation = DefaultImageOrientation;
+ m_subsamplingLevel = 0;
-#if PLATFORM(IOS)
- m_frameBytes = 0;
- m_subsamplingScale = 1;
- m_haveInfo = false;
-#endif
-
if (m_frame) {
#if CACHE_SUBIMAGES
subimageCache().clearImage(m_frame);
@@ -78,8 +74,10 @@
BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
: Image(observer)
+ , m_minimumSubsamplingLevel(0)
+ , m_imageOrientation(OriginTopLeft)
+ , m_shouldRespectImageOrientation(false)
, m_currentFrame(0)
- , m_frames(0)
, m_repetitionCount(cAnimationNone)
, m_repetitionCountStatus(Unknown)
, m_repetitionsComplete(0)
@@ -103,50 +101,62 @@
// Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0.
m_sizeRespectingOrientation = m_size;
-#if PLATFORM(IOS)
- m_originalSize = m_size;
- m_originalSizeRespectingOrientation = m_size;
-#endif
-
m_frames.grow(1);
m_frames[0].m_frame = CGImageRetain(cgImage);
m_frames[0].m_hasAlpha = true;
m_frames[0].m_haveMetadata = true;
-#if PLATFORM(IOS)
- m_frames[0].m_subsamplingScale = 1;
-#endif
-
checkForSolidColor();
}
-// Drawing Routines
+void BitmapImage::determineMinimumSubsamplingLevel() const
+{
+ if (!m_allowSubsampling)
+ return;
+ if (!m_source.allowSubsamplingOfFrameAtIndex(0))
+ return;
+
+ // Values chosen to be appropriate for iOS.
+ const int cMaximumImageAreaBeforeSubsampling = 5 * 1024 * 1024;
+ const SubsamplingLevel maxSubsamplingLevel = 3;
+
+ SubsamplingLevel currentLevel = 0;
+ for ( ; currentLevel <= maxSubsamplingLevel; ++currentLevel) {
+ IntSize frameSize = m_source.frameSizeAtIndex(0, currentLevel);
+ if (frameSize.area() < cMaximumImageAreaBeforeSubsampling)
+ break;
+ }
+
+ m_minimumSubsamplingLevel = currentLevel;
+}
+
void BitmapImage::checkForSolidColor()
{
m_checkedForSolidColor = true;
- if (frameCount() > 1) {
- m_isSolidColor = false;
+ m_isSolidColor = false;
+
+ if (frameCount() > 1)
return;
+
+ if (!haveFrameAtIndex(0)) {
+ IntSize size = m_source.frameSizeAtIndex(0, 0);
+ if (size.width() != 1 || size.height() != 1)
+ return;
+
+ if (!ensureFrameIsCached(0))
+ return;
}
-#if !PLATFORM(IOS)
- CGImageRef image = frameAtIndex(0);
-#else
- // Note, checkForSolidColor() may be called from frameAtIndex(). On iOS frameAtIndex() gets passed a scaleHint
- // argument which it uses to tell CG to create a scaled down image. Since we don't know the scaleHint here, if
- // we call frameAtIndex() again, we would pass it the default scale of 1 and would end up recreating the image.
- // So we do a quick check and call frameAtIndex(0) only if we haven't yet created an image.
CGImageRef image = nullptr;
if (m_frames.size())
image = m_frames[0].m_frame;
if (!image)
- image = frameAtIndex(0);
-#endif
+ return;
// Currently we only check for solid color in the important special case of a 1x1 image.
- if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) {
+ if (CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) {
unsigned char pixel[4]; // RGBA
RetainPtr<CGContextRef> bitmapContext = adoptCF(CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), deviceRGBColorSpaceRef(),
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big));
@@ -198,30 +208,23 @@
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription description)
{
- CGImageRef image;
- FloatRect srcRectForCurrentFrame = srcRect;
-
#if PLATFORM(IOS)
- if (m_originalSize != m_size && !m_originalSize.isEmpty())
- srcRectForCurrentFrame.scale(m_size.width() / static_cast<float>(m_originalSize.width()), m_size.height() / static_cast<float>(m_originalSize.height()));
-
startAnimation(DoNotCatchUp);
+#else
+ startAnimation();
+#endif
- CGRect transformedDestinationRect = CGRectApplyAffineTransform(destRect, CGContextGetCTM(ctxt->platformContext()));
- RetainPtr<CGImageRef> imagePossiblyCopied;
+ RetainPtr<CGImageRef> image;
// Never use subsampled images for drawing into PDF contexts.
- if (CGContextGetType(ctxt->platformContext()) == kCGContextTypePDF)
- imagePossiblyCopied = adoptCF(copyUnscaledFrameAtIndex(m_currentFrame));
- else
- imagePossiblyCopied = frameAtIndex(m_currentFrame, std::min<float>(1.0f, std::max(transformedDestinationRect.size.width / srcRectForCurrentFrame.width(), transformedDestinationRect.size.height / srcRectForCurrentFrame.height())));
+ if (wkCGContextIsPDFContext(ctxt->platformContext()))
+ image = adoptCF(copyUnscaledFrameAtIndex(m_currentFrame));
+ else {
+ CGRect transformedDestinationRect = CGRectApplyAffineTransform(destRect, CGContextGetCTM(ctxt->platformContext()));
+ float subsamplingScale = std::min<float>(1, std::max(transformedDestinationRect.size.width / srcRect.width(), transformedDestinationRect.size.height / srcRect.height()));
- image = imagePossiblyCopied.get();
-#else
- startAnimation();
+ image = frameAtIndex(m_currentFrame, subsamplingScale);
+ }
- image = frameAtIndex(m_currentFrame);
-#endif
-
if (!image) // If it's too early we won't have an image yet.
return;
@@ -230,37 +233,40 @@
return;
}
- float scale = 1;
-#if PLATFORM(IOS)
- scale = m_frames[m_currentFrame].m_subsamplingScale;
-#endif
- FloatSize selfSize = currentFrameSize();
+ // Subsampling may have given us an image that is smaller than size().
+ IntSize imageSize(CGImageGetWidth(image.get()), CGImageGetHeight(image.get()));
+
+ // srcRect is in the coordinates of the unsubsampled image, so we have to map it to the subsampled image.
+ FloatRect scaledSrcRect = srcRect;
+ if (imageSize != m_size) {
+ FloatRect originalImageBounds(FloatPoint(), m_size);
+ FloatRect subsampledImageBounds(FloatPoint(), imageSize);
+ scaledSrcRect = mapRect(srcRect, originalImageBounds, subsampledImageBounds);
+ }
+
ImageOrientation orientation;
-
if (description.respectImageOrientation() == RespectImageOrientation)
orientation = frameOrientationAtIndex(m_currentFrame);
- ctxt->drawNativeImage(image, selfSize, styleColorSpace, destRect, srcRectForCurrentFrame, scale, compositeOp, blendMode, orientation);
+ ctxt->drawNativeImage(image.get(), imageSize, styleColorSpace, destRect, scaledSrcRect, compositeOp, blendMode, orientation);
if (imageObserver())
imageObserver()->didDraw(this);
}
-#if PLATFORM(IOS)
PassNativeImagePtr BitmapImage::copyUnscaledFrameAtIndex(size_t index)
{
if (index >= frameCount())
return nullptr;
if (index >= m_frames.size() || !m_frames[index].m_frame)
- cacheFrame(index, 1);
+ cacheFrame(index, 0);
- if (m_frames[index].m_subsamplingScale == 1 && !m_source.isSubsampled())
+ if (!m_frames[index].m_subsamplingLevel)
return CGImageRetain(m_frames[index].m_frame);
return m_source.createFrameAtIndex(index);
}
-#endif
}
Modified: trunk/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -332,17 +332,8 @@
decoder.setData(m_image->data(), true);
if (!decoder.frameCount())
return false;
-#if PLATFORM(IOS)
- float scaleHint = 1;
- if (m_image->isBitmapImage()) {
- FloatSize originalSize = toBitmapImage(m_image)->originalSize();
- if (!originalSize.isEmpty())
- scaleHint = std::min<float>(1, std::max(m_image->size().width() / originalSize.width(), m_image->size().width() / originalSize.height()));
- }
- m_decodedImage = adoptCF(decoder.createFrameAtIndex(0, &scaleHint));
-#else
+
m_decodedImage = adoptCF(decoder.createFrameAtIndex(0));
-#endif
m_cgImage = m_decodedImage.get();
} else
m_cgImage = m_image->nativeImageForCurrentFrame();
@@ -545,7 +536,7 @@
context->scale(FloatSize(1, -1));
context->translate(0, -imageHeight);
context->setImageInterpolationQuality(InterpolationNone);
- context->drawNativeImage(cgImage.get(), imageSize, ColorSpaceDeviceRGB, canvasRect, FloatRect(FloatPoint(), imageSize), 1, CompositeCopy);
+ context->drawNativeImage(cgImage.get(), imageSize, ColorSpaceDeviceRGB, canvasRect, FloatRect(FloatPoint(), imageSize), CompositeCopy);
}
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -169,18 +169,11 @@
m_data->m_userToDeviceTransformKnownToBeIdentity = false;
}
-void GraphicsContext::drawNativeImage(PassNativeImagePtr imagePtr, const FloatSize& imageSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, float scale, CompositeOperator op, BlendMode blendMode, ImageOrientation orientation)
+void GraphicsContext::drawNativeImage(PassNativeImagePtr imagePtr, const FloatSize& imageSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, ImageOrientation orientation)
{
RetainPtr<CGImageRef> image(imagePtr);
float currHeight = orientation.usesWidthAsHeight() ? CGImageGetWidth(image.get()) : CGImageGetHeight(image.get());
-#if PLATFORM(IOS)
- // Unapply the scaling since we are getting this from a scaled bitmap.
- currHeight /= scale;
-#else
- UNUSED_PARAM(scale);
-#endif
-
if (currHeight <= srcRect.y())
return;
@@ -221,9 +214,6 @@
subimageRect.setHeight(ceilf(subimageRect.height() + topPadding));
adjustedDestRect.setHeight(subimageRect.height() / yScale);
-#if PLATFORM(IOS)
- subimageRect.scale(scale, scale);
-#endif
#if CACHE_SUBIMAGES
image = subimageCache().getSubimage(image.get(), subimageRect);
#else
Modified: trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -301,7 +301,7 @@
FloatRect adjustedSrcRect = srcRect;
adjustedSrcRect.scale(m_resolutionScale, m_resolutionScale);
- destContext->drawNativeImage(image.get(), m_data.m_backingStoreSize, colorSpace, destRect, adjustedSrcRect, 1, op, blendMode);
+ destContext->drawNativeImage(image.get(), m_data.m_backingStoreSize, colorSpace, destRect, adjustedSrcRect, op, blendMode);
}
void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode)
Modified: trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -38,12 +38,17 @@
#include <ApplicationServices/ApplicationServices.h>
#else
#include <CoreGraphics/CGImagePrivate.h>
-#include <CoreGraphics/CoreGraphics.h>
-#include <ImageIO/CGImageSourcePrivate.h>
#include <ImageIO/ImageIO.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/RetainPtr.h>
#endif
+#if __has_include(<ImageIO/CGImageSourcePrivate.h>)
+#import <ImageIO/CGImageSourcePrivate.h>
+#else
+const CFStringRef kCGImageSourceSubsampleFactor = CFSTR("kCGImageSourceSubsampleFactor");
+#endif
+
namespace WebCore {
const CFStringRef WebCoreCGImagePropertyAPNGUnclampedDelayTime = CFSTR("UnclampedDelayTime");
@@ -76,10 +81,6 @@
ImageSource::ImageSource(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption)
: m_decoder(0)
-#if PLATFORM(IOS)
- , m_baseSubsampling(0)
- , m_isProgressive(false)
-#endif
{
// FIXME: AlphaOption and GammaAndColorProfileOption are ignored.
}
@@ -105,39 +106,35 @@
setData(data, allDataReceived);
}
-#if !PLATFORM(IOS)
-static CFDictionaryRef imageSourceOptions(ImageSource::ShouldSkipMetadata skipMetaData)
+static CFDictionaryRef createImageSourceOptions(ImageSource::ShouldSkipMetadata skipMetaData, SubsamplingLevel subsamplingLevel)
{
- static CFDictionaryRef options;
-
- if (!options) {
+ const CFBooleanRef imageSourceSkipMetadata = (skipMetaData == ImageSource::SkipMetadata) ? kCFBooleanTrue : kCFBooleanFalse;
+
+ if (!subsamplingLevel) {
const unsigned numOptions = 3;
- const CFBooleanRef imageSourceSkipMetadata = (skipMetaData == ImageSource::SkipMetadata) ? kCFBooleanTrue : kCFBooleanFalse;
const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata };
const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, imageSourceSkipMetadata };
- options = CFDictionaryCreate(NULL, keys, values, numOptions,
- &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ return CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
- return options;
+
+ short constrainedSubsamplingLevel = std::min<short>(3, std::max<short>(0, subsamplingLevel));
+ int subsampleInt = 1 << constrainedSubsamplingLevel; // [0..3] => [1, 2, 4, 8]
+
+ RetainPtr<CFNumberRef> subsampleNumber = adoptCF(CFNumberCreate(nullptr, kCFNumberIntType, &subsampleInt));
+ const CFIndex numOptions = 4;
+ const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata, kCGImageSourceSubsampleFactor };
+ const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, imageSourceSkipMetadata, subsampleNumber.get() };
+ return CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
-#else
-CFDictionaryRef ImageSource::imageSourceOptions(ShouldSkipMetadata skipMetaData, int requestedSubsampling) const
+
+static CFDictionaryRef imageSourceOptions(ImageSource::ShouldSkipMetadata skipMetadata = ImageSource::SkipMetadata, SubsamplingLevel subsamplingLevel = 0)
{
- static CFDictionaryRef options[4] = {nullptr, nullptr, nullptr, nullptr};
- int subsampling = std::min(3, m_isProgressive || requestedSubsampling < 0 ? 0 : (requestedSubsampling + m_baseSubsampling));
+ if (subsamplingLevel)
+ return createImageSourceOptions(skipMetadata, subsamplingLevel);
- if (!options[subsampling]) {
- int subsampleInt = 1 << subsampling; // [0..3] => [1, 2, 4, 8]
- RetainPtr<CFNumberRef> subsampleNumber = adoptCF(CFNumberCreate(nullptr, kCFNumberIntType, &subsampleInt));
- const CFIndex numOptions = 4;
- const CFBooleanRef imageSourceSkipMetaData = (skipMetaData == ImageSource::SkipMetadata) ? kCFBooleanTrue : kCFBooleanFalse;
- const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSubsampleFactor, kCGImageSourceSkipMetadata };
- const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, subsampleNumber.get(), imageSourceSkipMetaData };
- options[subsampling] = CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- }
- return options[subsampling];
+ static CFDictionaryRef options = createImageSourceOptions(skipMetadata, 0);
+ return options;
}
-#endif
bool ImageSource::initialized() const
{
@@ -182,6 +179,15 @@
return WebCore::preferredExtensionForImageSourceType(imageSourceType);
}
+SubsamplingLevel ImageSource::subsamplingLevelForScale(float scale) const
+{
+ // There are four subsampling levels: 0 = 1x, 1 = 0.5x, 2 = 0.25x, 3 = 0.125x.
+ float clampedScale = std::max<float>(0.125, std::min<float>(1, scale));
+ int result = ceilf(log2f(1 / clampedScale));
+ ASSERT(result >=0 && result <= 3);
+ return result;
+}
+
bool ImageSource::isSizeAvailable()
{
bool result = false;
@@ -189,7 +195,7 @@
// Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus!
if (imageSourceStatus >= kCGImageStatusIncomplete) {
- RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions(SkipMetadata)));
+ RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()));
if (image0Properties) {
CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelWidth);
CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelHeight);
@@ -212,101 +218,67 @@
return ImageOrientation::fromEXIFValue(exifValue);
}
-IntSize ImageSource::frameSizeAtIndex(size_t index, ImageOrientationDescription description) const
+bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t) const
{
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata)));
-
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()));
if (!properties)
- return IntSize();
+ return false;
- int w = 0, h = 0;
- CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
- if (num)
- CFNumberGetValue(num, kCFNumberIntType, &w);
- num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight);
- if (num)
- CFNumberGetValue(num, kCFNumberIntType, &h);
-
-#if PLATFORM(IOS)
- if (!m_isProgressive) {
- CFDictionaryRef jfifProperties = static_cast<CFDictionaryRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyJFIFDictionary));
- if (jfifProperties) {
- CFBooleanRef isProgCFBool = static_cast<CFBooleanRef>(CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive));
- if (isProgCFBool)
- m_isProgressive = CFBooleanGetValue(isProgCFBool);
+ CFDictionaryRef jfifProperties = static_cast<CFDictionaryRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyJFIFDictionary));
+ if (jfifProperties) {
+ CFBooleanRef isProgCFBool = static_cast<CFBooleanRef>(CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive));
+ if (isProgCFBool) {
+ bool isProgressive = CFBooleanGetValue(isProgCFBool);
// Workaround for <rdar://problem/5184655> - Hang rendering very large progressive JPEG. Decoding progressive
// images hangs for a very long time right now. Until this is fixed, don't sub-sample progressive images. This
// will cause them to fail our large image check and they won't be decoded.
// FIXME: Remove once underlying issue is fixed (<rdar://problem/5191418>)
+ return !isProgressive;
}
}
- if ((m_baseSubsampling == 0) && !m_isProgressive) {
- IntSize subsampledSize(w, h);
- const int cMaximumImageSizeBeforeSubsampling = 5 * 1024 * 1024;
- while ((m_baseSubsampling < 3) && subsampledSize.width() * subsampledSize.height() > cMaximumImageSizeBeforeSubsampling) {
- // We know the size, but the actual image is very large and should be sub-sampled.
- // Increase the base subsampling and ask for the size again. If the image can be subsampled, the size will be
- // greatly reduced. 4x sub-sampling will make us support up to 320MP (5MP * 4^3) images, which should be plenty.
- // There's no callback from ImageIO when the size is available, so we do the check when we happen
- // to check the size and its non - zero.
- // Note: Some clients of this class don't call isSizeAvailable() so we can't rely on that.
- ++m_baseSubsampling;
- subsampledSize = frameSizeAtIndex(index, description.respectImageOrientation());
- }
- w = subsampledSize.width();
- h = subsampledSize.height();
- }
-#endif
-
- if ((description.respectImageOrientation() == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight())
- return IntSize(h, w);
-
- return IntSize(w, h);
+ return true;
}
-ImageOrientation ImageSource::orientationAtIndex(size_t index) const
+IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageOrientationDescription description) const
{
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata)));
- if (!properties)
- return DefaultImageOrientation;
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata, subsamplingLevel)));
- return orientationFromProperties(properties.get());
-}
-
-#if PLATFORM(IOS)
-IntSize ImageSource::originalSize(RespectImageOrientationEnum shouldRespectOrientation) const
-{
- frameSizeAtIndex(0, shouldRespectOrientation);
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions(SkipMetadata, -1)));
-
if (!properties)
return IntSize();
int width = 0;
int height = 0;
- CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
- if (number)
- CFNumberGetValue(number, kCFNumberIntType, &width);
- number = static_cast<CFNumberRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight));
- if (number)
- CFNumberGetValue(number, kCFNumberIntType, &height);
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &width);
+ num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &height);
- if ((shouldRespectOrientation == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight())
+ if ((description.respectImageOrientation() == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight())
return IntSize(height, width);
return IntSize(width, height);
}
-#endif
+ImageOrientation ImageSource::orientationAtIndex(size_t index) const
+{
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()));
+ if (!properties)
+ return DefaultImageOrientation;
+
+ return orientationFromProperties(properties.get());
+}
+
IntSize ImageSource::size(ImageOrientationDescription description) const
{
- return frameSizeAtIndex(0, description);
+ return frameSizeAtIndex(0, 0, description);
}
bool ImageSource::getHotSpot(IntPoint& hotSpot) const
{
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions(SkipMetadata)));
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()));
if (!properties)
return false;
@@ -342,7 +314,7 @@
if (!initialized())
return cAnimationLoopOnce;
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_decoder, imageSourceOptions(SkipMetadata)));
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_decoder, imageSourceOptions()));
if (!properties)
return cAnimationLoopOnce;
@@ -381,22 +353,14 @@
return m_decoder ? CGImageSourceGetCount(m_decoder) : 0;
}
-CGImageRef ImageSource::createFrameAtIndex(size_t index, float* scale)
+CGImageRef ImageSource::createFrameAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
{
- UNUSED_PARAM(scale);
-
if (!initialized())
return 0;
-#if !PLATFORM(IOS)
- UNUSED_PARAM(scale);
- RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata)));
-#else
- // Subsampling can be 1, 2 or 3, which means quarter-, sixteenth- and sixty-fourth-size, respectively.
- // A zero or negative value means no subsampling.
- int subsampling = scale ? static_cast<int>(log2f(1.0f / std::max(0.1f, std::min(1.0f, *scale)))) : -1;
- RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata, subsampling)));
+ RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata, subsamplingLevel)));
+#if PLATFORM(IOS)
// <rdar://problem/7371198> - CoreGraphics changed the default caching behaviour in iOS 4.0 to kCGImageCachingTransient
// which caused a performance regression for us since the images had to be resampled/recreated every time we called
// CGContextDrawImage. We now tell CG to cache the drawn images. See also <rdar://problem/14366755> -
@@ -409,15 +373,8 @@
#if COMPILER(CLANG)
#pragma clang diagnostic pop
#endif
- if (scale) {
- if (subsampling > 0)
- *scale = static_cast<float>(CGImageGetWidth(image.get())) / size(DoNotRespectImageOrientation).width();
- else {
- ASSERT(static_cast<int>(CGImageGetWidth(image.get())) == size(DoNotRespectImageOrientation).width());
- *scale = 1;
- }
- }
#endif // !PLATFORM(IOS)
+
CFStringRef imageUTI = CGImageSourceGetType(m_decoder);
static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image");
if (!imageUTI || !CFEqual(imageUTI, xbmUTI))
@@ -485,7 +442,7 @@
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
// for more information.
if (duration < 0.011f)
- return 0.100f;
+ return 0.1f;
return duration;
}
@@ -510,9 +467,9 @@
return true;
}
-unsigned ImageSource::frameBytesAtIndex(size_t index) const
+unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
{
- IntSize frameSize = frameSizeAtIndex(index, ImageOrientationDescription(RespectImageOrientation));
+ IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel, ImageOrientationDescription(RespectImageOrientation));
return frameSize.width() * frameSize.height() * 4;
}
Modified: trunk/Source/WebCore/platform/graphics/mac/ImageMac.mm (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/mac/ImageMac.mm 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/mac/ImageMac.mm 2014-08-08 18:55:51 UTC (rev 172348)
@@ -57,9 +57,9 @@
return;
#if USE(APPKIT)
- m_nsImage = 0;
+ m_nsImage = nullptr;
#endif
- m_tiffRep = 0;
+ m_tiffRep = nullptr;
}
PassRefPtr<Image> Image::loadPlatformResource(const char *name)
Modified: trunk/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp (172347 => 172348)
--- trunk/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp 2014-08-08 18:28:55 UTC (rev 172347)
+++ trunk/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp 2014-08-08 18:55:51 UTC (rev 172348)
@@ -148,6 +148,11 @@
bmp->drawPattern(ctxt, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, m_source.size());
}
+void BitmapImage::determineMinimumSubsamplingLevel() const
+{
+ m_minimumSubsamplingLevel = 0;
+}
+
void BitmapImage::checkForSolidColor()
{
if (m_checkedForSolidColor)