Changeset 171957 in webkit
- Timestamp:
- Aug 1, 2014 4:22:44 PM (10 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 20 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r171956 r171957 1 2014-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 1 121 2014-08-01 Andreas Kling <akling@apple.com> 2 122 -
trunk/Source/WebCore/WebCore.exp.in
r171891 r171957 522 522 __ZN7WebCore15GraphicsContext12setFillColorERKNS_5ColorENS_10ColorSpaceE 523 523 __ZN7WebCore15GraphicsContext14setStrokeColorERKNS_5ColorENS_10ColorSpaceE 524 __ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_NS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE 524 525 __ZN7WebCore15GraphicsContext15setFillGradientEN3WTF10PassRefPtrINS_8GradientEEE 525 526 __ZN7WebCore15GraphicsContext18setShouldAntialiasEb … … 2238 2239 __ZN7WebCore13toDeviceSpaceERKNS_9FloatRectEP8NSWindow 2239 2240 __ZN7WebCore14cookiesEnabledERKNS_21NetworkStorageSessionERKNS_3URLES5_ 2240 __ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_fNS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE2241 2241 __ZN7WebCore15GraphicsContextC1EP9CGContext 2242 2242 __ZN7WebCore15ResourceRequest41updateFromDelegatePreservingOldPropertiesERKS0_ … … 2589 2589 __ZN7WebCore15GraphicsContext12drawBidiTextERKNS_4FontERKNS_7TextRunERKNS_10FloatPointENS1_24CustomFontNotReadyActionEPNS_10BidiStatusEi 2590 2590 __ZN7WebCore15GraphicsContext15drawLineForTextERKNS_10FloatPointEfbb 2591 __ZN7WebCore15GraphicsContext15drawNativeImageEP7CGImageRKNS_9FloatSizeENS_10ColorSpaceERKNS_9FloatRectES9_fNS_17CompositeOperatorENS_9BlendModeENS_16ImageOrientationE2592 2591 __ZN7WebCore15GraphicsContext22setEmojiDrawingEnabledEb 2593 2592 __ZN7WebCore15GraphicsContext23setIsAcceleratedContextEb -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r171824 r171957 474 474 0F1774811378B772009DA76A /* ScrollAnimatorIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F17747F1378B772009DA76A /* ScrollAnimatorIOS.mm */; }; 475 475 0F29C16E1300C2E2002D794E /* AccessibilityAllInOne.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F29C16D1300C2E2002D794E /* AccessibilityAllInOne.cpp */; }; 476 0F3C725E1974874B00AEDD0C /* ImageSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3C725D1974874B00AEDD0C /* ImageSource.cpp */; }; 476 477 0F3DD44F12F5EA1B000D9190 /* ShadowBlur.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3DD44D12F5EA1B000D9190 /* ShadowBlur.cpp */; }; 477 478 0F3DD45012F5EA1B000D9190 /* ShadowBlur.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3DD44E12F5EA1B000D9190 /* ShadowBlur.h */; }; … … 7415 7416 0F17747F1378B772009DA76A /* ScrollAnimatorIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ScrollAnimatorIOS.mm; path = ios/ScrollAnimatorIOS.mm; sourceTree = "<group>"; }; 7416 7417 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>"; }; 7417 7419 0F3DD44D12F5EA1B000D9190 /* ShadowBlur.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShadowBlur.cpp; sourceTree = "<group>"; }; 7418 7420 0F3DD44E12F5EA1B000D9190 /* ShadowBlur.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowBlur.h; sourceTree = "<group>"; }; … … 20491 20493 49291E4A134172C800E753DE /* ImageRenderingMode.h */, 20492 20494 B27535430B053814002CE64F /* ImageSource.h */, 20495 0F3C725D1974874B00AEDD0C /* ImageSource.cpp */, 20493 20496 07941793166EA04E009416C2 /* InbandTextTrackPrivate.h */, 20494 20497 07CE77D416712A6A00C55A47 /* InbandTextTrackPrivateClient.h */, … … 29439 29442 97BC6A471505F081001B74AC /* SQLStatement.cpp in Sources */, 29440 29443 FE8A674716CDD19E00930BF8 /* SQLStatementBackend.cpp in Sources */, 29444 0F3C725E1974874B00AEDD0C /* ImageSource.cpp in Sources */, 29441 29445 97BC6A4D1505F081001B74AC /* SQLStatementSync.cpp in Sources */, 29442 29446 97BC6A4F1505F081001B74AC /* SQLTransaction.cpp in Sources */, -
trunk/Source/WebCore/loader/cache/CachedImage.cpp
r171743 r171957 290 290 #else 291 291 if (m_image->isBitmapImage() && (renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation)) 292 #if !PLATFORM(IOS)293 292 imageSize = LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation()); 294 #else295 {296 // On iOS, the image may have been subsampled to accommodate our size restrictions. However297 // 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)302 293 #endif // ENABLE(CSS_IMAGE_ORIENTATION) 303 294 … … 353 344 if (m_image) 354 345 return; 346 355 347 #if USE(CG) && !USE(WEBKIT_IMAGE_DECODERS) 356 348 else if (m_response.mimeType() == "application/pdf") … … 361 353 m_svgImageCache = std::make_unique<SVGImageCache>(svgImage.get()); 362 354 m_image = svgImage.release(); 363 } else 355 } else { 364 356 m_image = BitmapImage::create(this); 357 toBitmapImage(m_image.get())->setAllowSubsampling(m_loader && m_loader->frameLoader()->frame().settings().imageSubsamplingEnabled()); 358 } 365 359 366 360 if (m_image) { … … 519 513 { 520 514 Image* image = imageForRenderer(renderer); 521 if (image->isBitmapImage())522 image->nativeImageForCurrentFrame(); // force decode523 515 return image->currentFrameKnownToBeOpaque(); 524 516 } -
trunk/Source/WebCore/loader/cache/CachedImage.h
r166665 r171957 60 60 Image* imageForRenderer(const RenderObject*); // Returns the nullImage() if the image is not available yet. 61 61 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*); 63 63 64 64 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 128 128 static const bool defaultMediaPlaybackRequiresUserGesture = true; 129 129 static const bool defaultShouldRespectImageOrientation = true; 130 static const bool defaultImageSubsamplingEnabled = true; 130 131 static const bool defaultScrollingTreeIncludesFrames = true; 131 132 #else … … 136 137 static const bool defaultMediaPlaybackRequiresUserGesture = false; 137 138 static const bool defaultShouldRespectImageOrientation = false; 139 static const bool defaultImageSubsamplingEnabled = false; 138 140 static const bool defaultScrollingTreeIncludesFrames = false; 139 141 #endif -
trunk/Source/WebCore/page/Settings.in
r171001 r171957 142 142 143 143 shouldRespectImageOrientation initial=defaultShouldRespectImageOrientation 144 imageSubsamplingEnabled initial=defaultImageSubsamplingEnabled 144 145 wantsBalancedSetDefersLoadingBehavior initial=false 145 146 requestAnimationFrameEnabled initial=true -
trunk/Source/WebCore/platform/graphics/BitmapImage.cpp
r171119 r171957 45 45 namespace WebCore { 46 46 47 // FIXME: We should better integrate the iOS and non-iOS code in this class. Unlike other ports, the48 // iOS port caches the metadata for a frame without decoding the image.49 47 BitmapImage::BitmapImage(ImageObserver* observer) 50 48 : Image(observer) 49 , m_minimumSubsamplingLevel(0) 50 , m_imageOrientation(OriginTopLeft) 51 , m_shouldRespectImageOrientation(false) 51 52 , m_currentFrame(0) 52 , m_frames(0)53 53 , m_repetitionCount(cAnimationNone) 54 54 , m_repetitionCountStatus(Unknown) … … 62 62 , m_progressiveLoadChunkTime(0) 63 63 , m_progressiveLoadChunkCount(0) 64 , m_allowSubsampling(true) 65 #else 66 , m_allowSubsampling(false) 64 67 #endif 65 68 , m_isSolidColor(false) … … 79 82 invalidatePlatformData(); 80 83 stopAnimation(); 84 } 85 86 bool 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; 81 95 } 82 96 … … 153 167 } 154 168 155 #if PLATFORM(IOS) 156 void BitmapImage::cacheFrame(size_t index, float scaleHint) 157 #else 158 void BitmapImage::cacheFrame(size_t index) 159 #endif 169 void BitmapImage::cacheFrame(size_t index, SubsamplingLevel subsamplingLevel, ImageFrameCaching frameCaching) 160 170 { 161 171 size_t numFrames = frameCount(); … … 165 175 m_frames.grow(numFrames); 166 176 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 } 175 183 176 184 m_frames[index].m_orientation = m_source.orientationAtIndex(index); 177 185 m_frames[index].m_haveMetadata = true; 178 186 m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index); 187 179 188 if (repetitionCount(false) != cAnimationNone) 180 189 m_frames[index].m_duration = m_source.frameDurationAtIndex(index); 190 181 191 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) 186 196 m_hasUniformFrameSize = false; 197 187 198 if (m_frames[index].m_frame) { 188 199 int deltaBytes = safeCast<int>(m_frames[index].m_frameBytes); … … 197 208 } 198 209 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 #endif215 216 210 void BitmapImage::didDecodeProperties() const 217 211 { 218 212 if (m_decodedSize) 219 213 return; 214 220 215 size_t updatedSize = m_source.bytesDecodedToDetermineProperties(); 221 216 if (m_decodedPropertiesSize == updatedSize) 222 217 return; 218 223 219 int deltaBytes = updatedSize - m_decodedPropertiesSize; 224 220 #if !ASSERT_DISABLED … … 239 235 m_size = m_source.size(description); 240 236 m_sizeRespectingOrientation = m_source.size(ImageOrientationDescription(RespectImageOrientation, description.imageOrientation())); 237 241 238 m_imageOrientation = static_cast<unsigned>(description.imageOrientation()); 242 239 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 247 241 m_haveSize = true; 242 243 determineMinimumSubsamplingLevel(); 248 244 didDecodeProperties(); 249 245 } … … 259 255 updateSize(description); 260 256 return m_sizeRespectingOrientation; 261 }262 263 #if PLATFORM(IOS)264 FloatSize BitmapImage::originalSize() const265 {266 updateSize();267 return m_originalSize;268 }269 270 IntSize BitmapImage::originalSizeRespectingOrientation() const271 {272 updateSize();273 return m_originalSizeRespectingOrientation;274 }275 #endif276 277 IntSize BitmapImage::currentFrameSize() const278 {279 if (!m_currentFrame || m_hasUniformFrameSize)280 return IntSize(size());281 IntSize frameSize = m_source.frameSizeAtIndex(m_currentFrame);282 didDecodeProperties();283 return frameSize;284 257 } 285 258 … … 324 297 destroyMetadataAndNotify(frameBytesCleared); 325 298 #else 299 // FIXME: why is this different for iOS? 326 300 int deltaBytes = 0; 327 301 if (!m_frames.isEmpty()) { … … 391 365 } 392 366 393 #if !PLATFORM(IOS) 394 bool BitmapImage::ensureFrameIsCached(size_t index) 367 bool BitmapImage::ensureFrameIsCached(size_t index, ImageFrameCaching frameCaching) 395 368 { 396 369 if (index >= frameCount()) 397 370 return false; 398 371 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 401 377 return true; 402 378 } 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 380 PassNativeImagePtr BitmapImage::frameAtIndex(size_t index, float presentationScaleHint) 428 381 { 429 382 if (index >= frameCount()) 430 383 return nullptr; 431 384 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) { 435 390 // If the image is already cached, but at too small a size, re-decode a larger version. 436 391 int sizeChange = -m_frames[index].m_frameBytes; 437 ASSERT(static_cast<int>(m_decodedSize) + sizeChange >= 0);438 392 m_frames[index].clear(true); 439 393 invalidatePlatformData(); 440 394 m_decodedSize += sizeChange; 395 WTFLogAlways("BitmapImage %p frameAtIndex recaching, m_decodedSize now %u (size change %d)", this, m_decodedSize, sizeChange); 441 396 if (imageObserver()) 442 397 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 446 404 return m_frames[index].m_frame; 447 405 } 448 #endif449 406 450 407 bool BitmapImage::frameIsCompleteAtIndex(size_t index) 451 408 { 452 #if PLATFORM(IOS) 453 // FIXME: cacheFrameInfo does not set m_isComplete. Should it? 454 if (!ensureFrameInfoIsCached(index)) 409 if (!ensureFrameIsCached(index, CacheMetadataOnly)) 455 410 return false; 456 #else 457 if (!ensureFrameIsCached(index)) 458 return false; 459 #endif 411 460 412 return m_frames[index].m_isComplete; 461 413 } … … 463 415 float BitmapImage::frameDurationAtIndex(size_t index) 464 416 { 465 #if PLATFORM(IOS) 466 if (!ensureFrameInfoIsCached(index)) 417 if (!ensureFrameIsCached(index, CacheMetadataOnly)) 467 418 return 0; 468 #else 469 if (!ensureFrameIsCached(index)) 470 return 0; 471 #endif 419 472 420 return m_frames[index].m_duration; 473 421 } … … 480 428 bool BitmapImage::frameHasAlphaAtIndex(size_t index) 481 429 { 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)) 487 431 return true; 488 #endif 432 489 433 if (m_frames[index].m_haveMetadata) 490 434 return m_frames[index].m_hasAlpha; … … 500 444 ImageOrientation BitmapImage::frameOrientationAtIndex(size_t index) 501 445 { 502 #if PLATFORM(IOS) 503 // FIXME: cacheFrameInfo does not set m_orientation. Should it? 504 if (!ensureFrameInfoIsCached(index)) 446 if (!ensureFrameIsCached(index, CacheMetadataOnly)) 505 447 return DefaultImageOrientation; 506 #else507 if (!ensureFrameIsCached(index))508 return DefaultImageOrientation;509 #endif510 448 511 449 if (m_frames[index].m_haveMetadata) -
trunk/Source/WebCore/platform/graphics/BitmapImage.h
r171119 r171957 71 71 : m_frame(0) 72 72 , m_orientation(DefaultImageOrientation) 73 #if PLATFORM(IOS) 74 , m_subsamplingScale(0) 75 , m_haveInfo(false) 76 #endif 73 , m_subsamplingLevel(0) 77 74 , m_duration(0) 78 75 , m_haveMetadata(false) … … 94 91 NativeImagePtr m_frame; 95 92 ImageOrientation m_orientation; 96 #if PLATFORM(IOS) 97 float m_subsamplingScale; 98 bool m_haveInfo; 99 #endif 93 SubsamplingLevel m_subsamplingLevel; 100 94 float m_duration; 101 95 bool m_haveMetadata : 1; … … 108 102 // BitmapImage Class 109 103 // ================================================= 110 111 // FIXME: We should better integrate the iOS and non-iOS code in this class. Unlike other ports, the112 // iOS port caches the metadata for a frame without decoding the image.113 104 114 105 class BitmapImage final : public Image { … … 138 129 virtual FloatSize size() const override; 139 130 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 145 132 virtual bool getHotSpot(IntPoint&) const override; 146 133 … … 195 182 bool canAnimate(); 196 183 184 bool allowSubsampling() const { return m_allowSubsampling; } 185 void setAllowSubsampling(bool allowSubsampling) { m_allowSubsampling = allowSubsampling; } 186 197 187 private: 198 188 void updateSize(ImageOrientationDescription = ImageOrientationDescription()) const; 189 void determineMinimumSubsamplingLevel() const; 199 190 200 191 protected: … … 219 210 220 211 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); 223 215 PassNativeImagePtr copyUnscaledFrameAtIndex(size_t); 224 #endif 225 size_t frameCount();226 PassNativeImagePtr frameAtIndex(size_t); 216 217 bool haveFrameAtIndex(size_t); 218 227 219 bool frameIsCompleteAtIndex(size_t); 228 220 float frameDurationAtIndex(size_t); … … 231 223 232 224 // 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 238 228 // 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); 245 230 246 231 // Called to invalidate cached data. When |destroyAll| is true, we wipe out … … 302 287 mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image). 303 288 mutable IntSize m_sizeRespectingOrientation; 289 290 mutable SubsamplingLevel m_minimumSubsamplingLevel; 291 304 292 mutable unsigned m_imageOrientation : 4; // ImageOrientationEnum 305 293 mutable unsigned m_shouldRespectImageOrientation : 1; // RespectImageOrientationEnum 306 294 307 #if PLATFORM(IOS)308 mutable IntSize m_originalSize; // The size of the unsubsampled image.309 mutable IntSize m_originalSizeRespectingOrientation;310 #endif311 295 size_t m_currentFrame; // The index of the current frame of animation. 312 296 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. … … 337 321 #endif 338 322 323 bool m_allowSubsampling : 1; // Whether we should attempt subsampling if this image is very large. 339 324 bool m_isSolidColor : 1; // Whether or not we are a 1x1 solid image. 340 325 bool m_checkedForSolidColor : 1; // Whether we've checked the frame for solid color. -
trunk/Source/WebCore/platform/graphics/GraphicsContext.h
r169534 r171957 284 284 void drawPath(const Path&); 285 285 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); 287 287 288 288 // Allow font smoothing (LCD antialiasing). Not part of the graphics state. -
trunk/Source/WebCore/platform/graphics/ImageSource.cpp
r165676 r171957 30 30 #include "ImageSource.h" 31 31 32 #if !USE(CG) 33 32 34 #include "ImageDecoder.h" 33 35 … … 95 97 } 96 98 99 SubsamplingLevel ImageSource::subsamplingLevelForScale(float) const 100 { 101 return 0; 102 } 103 104 bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t) const 105 { 106 return true; 107 } 108 97 109 bool ImageSource::isSizeAvailable() 98 110 { … … 102 114 IntSize ImageSource::size(ImageOrientationDescription description) const 103 115 { 104 return frameSizeAtIndex(0, description);105 } 106 107 IntSize ImageSource::frameSizeAtIndex(size_t index, ImageOrientationDescription description) const116 return frameSizeAtIndex(0, 0, description); 117 } 118 119 IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel, ImageOrientationDescription description) const 108 120 { 109 121 if (!m_decoder) … … 137 149 } 138 150 139 PassNativeImagePtr ImageSource::createFrameAtIndex(size_t index, float* scale) 140 { 141 UNUSED_PARAM(scale); 142 151 PassNativeImagePtr ImageSource::createFrameAtIndex(size_t index, SubsamplingLevel) 152 { 143 153 if (!m_decoder) 144 154 return 0; … … 198 208 } 199 209 200 unsigned ImageSource::frameBytesAtIndex(size_t index ) const210 unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel) const 201 211 { 202 212 if (!m_decoder) … … 206 216 207 217 } 218 219 #endif // USE(CG) -
trunk/Source/WebCore/platform/graphics/ImageSource.h
r168452 r171957 78 78 const int cAnimationNone = -2; 79 79 80 // SubsamplingLevel. 0 is no subsampling, 1 is half dimensions on each axis etc. 81 typedef short SubsamplingLevel; 82 80 83 class ImageSource { 81 84 WTF_MAKE_NONCOPYABLE(ImageSource); … … 132 135 String filenameExtension() const; 133 136 137 SubsamplingLevel subsamplingLevelForScale(float) const; 138 bool allowSubsamplingOfFrameAtIndex(size_t) const; 139 134 140 bool isSizeAvailable(); 141 // Always original size, without subsampling. 135 142 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; 142 145 143 146 bool getHotSpot(IntPoint&) const; … … 151 154 // Callers should not call this after calling clear() with a higher index; 152 155 // see comments on clear() above. 153 PassNativeImagePtr createFrameAtIndex(size_t, float* scale= 0);156 PassNativeImagePtr createFrameAtIndex(size_t, SubsamplingLevel = 0); 154 157 155 158 float frameDurationAtIndex(size_t); … … 160 163 // Return the number of bytes in the decoded frame. If the frame is not yet 161 164 // decoded then return 0. 162 unsigned frameBytesAtIndex(size_t ) const;165 unsigned frameBytesAtIndex(size_t, SubsamplingLevel = 0) const; 163 166 164 167 #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) … … 177 180 static unsigned s_maxPixelsPerDecodedImage; 178 181 #endif 179 #if PLATFORM(IOS)180 mutable int m_baseSubsampling;181 mutable bool m_isProgressive;182 CFDictionaryRef imageSourceOptions(ShouldSkipMetadata, int subsampling = 0) const;183 #endif184 182 }; 185 183 -
trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp
r165676 r171957 120 120 } 121 121 122 void BitmapImage::determineMinimumSubsamplingLevel() const 123 { 124 m_minimumSubsamplingLevel = 0; 125 } 126 122 127 void BitmapImage::checkForSolidColor() 123 128 { -
trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp
r171119 r171957 30 30 31 31 #include "FloatConversion.h" 32 #include "GeometryUtilities.h" 32 33 #include "GraphicsContextCG.h" 33 34 #include "ImageObserver.h" … … 59 60 60 61 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; 67 63 68 64 if (m_frame) { … … 79 75 BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer) 80 76 : Image(observer) 77 , m_minimumSubsamplingLevel(0) 78 , m_imageOrientation(OriginTopLeft) 79 , m_shouldRespectImageOrientation(false) 81 80 , m_currentFrame(0) 82 , m_frames(0)83 81 , m_repetitionCount(cAnimationNone) 84 82 , m_repetitionCountStatus(Unknown) … … 104 102 m_sizeRespectingOrientation = m_size; 105 103 106 #if PLATFORM(IOS)107 m_originalSize = m_size;108 m_originalSizeRespectingOrientation = m_size;109 #endif110 111 104 m_frames.grow(1); 112 105 m_frames[0].m_frame = CGImageRetain(cgImage); … … 114 107 m_frames[0].m_haveMetadata = true; 115 108 116 #if PLATFORM(IOS)117 m_frames[0].m_subsamplingScale = 1;118 #endif119 120 109 checkForSolidColor(); 121 110 } 122 111 123 // Drawing Routines 112 void 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 } 124 133 125 134 void BitmapImage::checkForSolidColor() 126 135 { 127 136 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 140 151 CGImageRef image = nullptr; 141 152 if (m_frames.size()) … … 143 154 144 155 if (!image) 145 image = frameAtIndex(0); 146 #endif 156 return; 147 157 148 158 // 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) { 150 160 unsigned char pixel[4]; // RGBA 151 161 RetainPtr<CGContextRef> bitmapContext = adoptCF(CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), deviceRGBColorSpaceRef(), … … 199 209 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription description) 200 210 { 201 CGImageRef image;202 FloatRect srcRectForCurrentFrame = srcRect;203 204 211 #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 208 212 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 else216 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();219 213 #else 220 214 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 } 224 227 225 228 if (!image) // If it's too early we won't have an image yet. … … 231 234 } 232 235 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 238 247 ImageOrientation orientation; 239 240 248 if (description.respectImageOrientation() == RespectImageOrientation) 241 249 orientation = frameOrientationAtIndex(m_currentFrame); 242 250 243 ctxt->drawNativeImage(image , selfSize, styleColorSpace, destRect, srcRectForCurrentFrame, scale, compositeOp, blendMode, orientation);251 ctxt->drawNativeImage(image.get(), imageSize, styleColorSpace, destRect, scaledSrcRect, compositeOp, blendMode, orientation); 244 252 245 253 if (imageObserver()) … … 247 255 } 248 256 249 #if PLATFORM(IOS)250 257 PassNativeImagePtr BitmapImage::copyUnscaledFrameAtIndex(size_t index) 251 258 { … … 256 263 cacheFrame(index, 1); 257 264 258 if ( m_frames[index].m_subsamplingScale == 1 && !m_source.isSubsampled())265 if (!m_frames[index].m_subsamplingLevel) 259 266 return CGImageRetain(m_frames[index].m_frame); 260 267 261 268 return m_source.createFrameAtIndex(index); 262 269 } 263 #endif264 270 265 271 } -
trunk/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
r171119 r171957 333 333 if (!decoder.frameCount()) 334 334 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 344 336 m_decodedImage = adoptCF(decoder.createFrameAtIndex(0)); 345 #endif346 337 m_cgImage = m_decodedImage.get(); 347 338 } else … … 546 537 context->translate(0, -imageHeight); 547 538 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); 549 540 } 550 541 -
trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
r169623 r171957 170 170 } 171 171 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)172 void GraphicsContext::drawNativeImage(PassNativeImagePtr imagePtr, const FloatSize& imageSize, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, ImageOrientation orientation) 173 173 { 174 174 RetainPtr<CGImageRef> image(imagePtr); 175 175 176 176 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 #else181 UNUSED_PARAM(scale);182 #endif183 184 177 if (currHeight <= srcRect.y()) 185 178 return; … … 222 215 adjustedDestRect.setHeight(subimageRect.height() / yScale); 223 216 224 #if PLATFORM(IOS)225 subimageRect.scale(scale, scale);226 #endif227 217 #if CACHE_SUBIMAGES 228 218 image = subimageCache().getSubimage(image.get(), subimageRect); -
trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp
r168577 r171957 302 302 FloatRect adjustedSrcRect = srcRect; 303 303 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); 305 305 } 306 306 -
trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp
r168452 r171957 39 39 #else 40 40 #include <CoreGraphics/CGImagePrivate.h> 41 #include <CoreGraphics/CoreGraphics.h>42 #include <ImageIO/CGImageSourcePrivate.h>43 41 #include <ImageIO/ImageIO.h> 42 #include <wtf/NeverDestroyed.h> 44 43 #include <wtf/RetainPtr.h> 44 #endif 45 46 #if __has_include(<ImageIO/CGImageSourcePrivate.h>) 47 #import <ImageIO/CGImageSourcePrivate.h> 48 #else 49 const CFStringRef kCGImageSourceSubsampleFactor = CFSTR("kCGImageSourceSubsampleFactor"); 45 50 #endif 46 51 … … 77 82 ImageSource::ImageSource(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption) 78 83 : m_decoder(0) 79 #if PLATFORM(IOS)80 , m_baseSubsampling(0)81 , m_isProgressive(false)82 #endif83 84 { 84 85 // FIXME: AlphaOption and GammaAndColorProfileOption are ignored. … … 106 107 } 107 108 108 #if !PLATFORM(IOS) 109 static CFDictionaryRef imageSourceOptions(ImageSource::ShouldSkipMetadata skipMetaData) 110 { 111 static CFDictionaryRef options; 112 113 if (!options) { 109 static CFDictionaryRef createImageSourceOptions(ImageSource::ShouldSkipMetadata skipMetaData, SubsamplingLevel subsamplingLevel) 110 { 111 const CFBooleanRef imageSourceSkipMetadata = (skipMetaData == ImageSource::SkipMetadata) ? kCFBooleanTrue : kCFBooleanFalse; 112 113 if (!subsamplingLevel) { 114 114 const unsigned numOptions = 3; 115 const CFBooleanRef imageSourceSkipMetadata = (skipMetaData == ImageSource::SkipMetadata) ? kCFBooleanTrue : kCFBooleanFalse;116 115 const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata }; 117 116 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 130 static 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); 121 136 return options; 122 137 } 123 #else124 CFDictionaryRef ImageSource::imageSourceOptions(ShouldSkipMetadata skipMetaData, int requestedSubsampling) const125 {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 #endif141 138 142 139 bool ImageSource::initialized() const … … 183 180 } 184 181 182 SubsamplingLevel 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 185 191 bool ImageSource::isSizeAvailable() 186 192 { … … 190 196 // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus! 191 197 if (imageSourceStatus >= kCGImageStatusIncomplete) { 192 RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions( SkipMetadata)));198 RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions())); 193 199 if (image0Properties) { 194 200 CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelWidth); … … 213 219 } 214 220 215 IntSize ImageSource::frameSizeAtIndex(size_t index, ImageOrientationDescription description) const 216 { 217 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata))); 218 221 bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t) const 222 { 223 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions())); 219 224 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); 237 232 // Workaround for <rdar://problem/5184655> - Hang rendering very large progressive JPEG. Decoding progressive 238 233 // images hangs for a very long time right now. Until this is fixed, don't sub-sample progressive images. This 239 234 // will cause them to fail our large image check and they won't be decoded. 240 235 // FIXME: Remove once underlying issue is fixed (<rdar://problem/5191418>) 236 return !isProgressive; 241 237 } 242 238 } 243 239 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 243 IntSize 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); 261 258 262 259 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); 266 263 } 267 264 268 265 ImageOrientation ImageSource::orientationAtIndex(size_t index) const 269 266 { 270 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions( SkipMetadata)));267 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions())); 271 268 if (!properties) 272 269 return DefaultImageOrientation; … … 275 272 } 276 273 277 #if PLATFORM(IOS)278 IntSize ImageSource::originalSize(RespectImageOrientationEnum shouldRespectOrientation) const279 {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 #endif301 302 274 IntSize ImageSource::size(ImageOrientationDescription description) const 303 275 { 304 return frameSizeAtIndex(0, description);276 return frameSizeAtIndex(0, 0, description); 305 277 } 306 278 307 279 bool ImageSource::getHotSpot(IntPoint& hotSpot) const 308 280 { 309 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions( SkipMetadata)));281 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions())); 310 282 if (!properties) 311 283 return false; … … 343 315 return cAnimationLoopOnce; 344 316 345 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_decoder, imageSourceOptions( SkipMetadata)));317 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_decoder, imageSourceOptions())); 346 318 if (!properties) 347 319 return cAnimationLoopOnce; … … 382 354 } 383 355 384 CGImageRef ImageSource::createFrameAtIndex(size_t index, float* scale) 385 { 386 UNUSED_PARAM(scale); 387 356 CGImageRef ImageSource::createFrameAtIndex(size_t index, SubsamplingLevel subsamplingLevel) 357 { 388 358 if (!initialized()) 389 359 return 0; 390 360 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) 400 364 // <rdar://problem/7371198> - CoreGraphics changed the default caching behaviour in iOS 4.0 to kCGImageCachingTransient 401 365 // which caused a performance regression for us since the images had to be resampled/recreated every time we called … … 410 374 #pragma clang diagnostic pop 411 375 #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 }420 376 #endif // !PLATFORM(IOS) 377 421 378 CFStringRef imageUTI = CGImageSourceGetType(m_decoder); 422 379 static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); … … 486 443 // for more information. 487 444 if (duration < 0.011f) 488 return 0.1 00f;445 return 0.1f; 489 446 return duration; 490 447 } … … 511 468 } 512 469 513 unsigned ImageSource::frameBytesAtIndex(size_t index ) const514 { 515 IntSize frameSize = frameSizeAtIndex(index, ImageOrientationDescription(RespectImageOrientation));470 unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const 471 { 472 IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel, ImageOrientationDescription(RespectImageOrientation)); 516 473 return frameSize.width() * frameSize.height() * 4; 517 474 } -
trunk/Source/WebCore/platform/graphics/mac/ImageMac.mm
r165676 r171957 58 58 59 59 #if USE(APPKIT) 60 m_nsImage = 0;60 m_nsImage = nullptr; 61 61 #endif 62 m_tiffRep = 0;62 m_tiffRep = nullptr; 63 63 } 64 64 -
trunk/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp
r158533 r171957 149 149 } 150 150 151 void BitmapImage::determineMinimumSubsamplingLevel() const 152 { 153 m_minimumSubsamplingLevel = 0; 154 } 155 151 156 void BitmapImage::checkForSolidColor() 152 157 {
Note: See TracChangeset
for help on using the changeset viewer.