| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) | 2 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) |
| 3 * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. | 3 * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "config.h" | 27 #include "config.h" |
| 28 #include "platform/graphics/BitmapImage.h" | 28 #include "platform/graphics/BitmapImage.h" |
| 29 | 29 |
| 30 #include "platform/Timer.h" | 30 #include "platform/Timer.h" |
| 31 #include "platform/TraceEvent.h" | 31 #include "platform/TraceEvent.h" |
| 32 #include "platform/geometry/FloatRect.h" | 32 #include "platform/geometry/FloatRect.h" |
| 33 #include "platform/graphics/GraphicsContextStateSaver.h" | 33 #include "platform/graphics/GraphicsContextStateSaver.h" |
| 34 #include "platform/graphics/ImageObserver.h" | 34 #include "platform/graphics/ImageObserver.h" |
| 35 #include "platform/graphics/skia/NativeImageSkia.h" | |
| 36 #include "platform/graphics/skia/SkiaUtils.h" | 35 #include "platform/graphics/skia/SkiaUtils.h" |
| 37 #include "wtf/PassRefPtr.h" | 36 #include "wtf/PassRefPtr.h" |
| 38 #include "wtf/text/WTFString.h" | 37 #include "wtf/text/WTFString.h" |
| 39 | 38 |
| 40 namespace blink { | 39 namespace blink { |
| 41 | 40 |
| 42 PassRefPtr<BitmapImage> BitmapImage::create(PassRefPtr<NativeImageSkia> nativeIm
age, ImageObserver* observer) | 41 PassRefPtr<BitmapImage> BitmapImage::create(const SkBitmap& bitmap, ImageObserve
r* observer) |
| 43 { | 42 { |
| 44 if (!nativeImage) { | 43 if (bitmap.isNull()) { |
| 45 return BitmapImage::create(observer); | 44 return BitmapImage::create(observer); |
| 46 } | 45 } |
| 47 | 46 |
| 48 return adoptRef(new BitmapImage(nativeImage, observer)); | 47 return adoptRef(new BitmapImage(bitmap, observer)); |
| 49 } | 48 } |
| 50 | 49 |
| 51 PassRefPtr<BitmapImage> BitmapImage::createWithOrientationForTesting(PassRefPtr<
NativeImageSkia> nativeImage, ImageOrientation orientation) | 50 PassRefPtr<BitmapImage> BitmapImage::createWithOrientationForTesting(const SkBit
map& bitmap, ImageOrientation orientation) |
| 52 { | 51 { |
| 53 RefPtr<BitmapImage> result = create(nativeImage); | 52 RefPtr<BitmapImage> result = create(bitmap); |
| 54 result->m_frames[0].m_orientation = orientation; | 53 result->m_frames[0].m_orientation = orientation; |
| 55 if (orientation.usesWidthAsHeight()) | 54 if (orientation.usesWidthAsHeight()) |
| 56 result->m_sizeRespectingOrientation = IntSize(result->m_size.height(), r
esult->m_size.width()); | 55 result->m_sizeRespectingOrientation = IntSize(result->m_size.height(), r
esult->m_size.width()); |
| 57 return result.release(); | 56 return result.release(); |
| 58 } | 57 } |
| 59 | 58 |
| 60 BitmapImage::BitmapImage(ImageObserver* observer) | 59 BitmapImage::BitmapImage(ImageObserver* observer) |
| 61 : Image(observer) | 60 : Image(observer) |
| 62 , m_currentFrame(0) | 61 , m_currentFrame(0) |
| 63 , m_frames() | 62 , m_frames() |
| 64 , m_frameTimer(0) | 63 , m_frameTimer(0) |
| 65 , m_repetitionCount(cAnimationNone) | 64 , m_repetitionCount(cAnimationNone) |
| 66 , m_repetitionCountStatus(Unknown) | 65 , m_repetitionCountStatus(Unknown) |
| 67 , m_repetitionsComplete(0) | 66 , m_repetitionsComplete(0) |
| 68 , m_desiredFrameStartTime(0) | 67 , m_desiredFrameStartTime(0) |
| 69 , m_frameCount(0) | 68 , m_frameCount(0) |
| 70 , m_animationPolicy(ImageAnimationPolicyAllowed) | 69 , m_animationPolicy(ImageAnimationPolicyAllowed) |
| 71 , m_isSolidColor(false) | 70 , m_isSolidColor(false) |
| 72 , m_checkedForSolidColor(false) | 71 , m_checkedForSolidColor(false) |
| 73 , m_animationFinished(false) | 72 , m_animationFinished(false) |
| 74 , m_allDataReceived(false) | 73 , m_allDataReceived(false) |
| 75 , m_haveSize(false) | 74 , m_haveSize(false) |
| 76 , m_sizeAvailable(false) | 75 , m_sizeAvailable(false) |
| 77 , m_hasUniformFrameSize(true) | 76 , m_hasUniformFrameSize(true) |
| 78 , m_haveFrameCount(false) | 77 , m_haveFrameCount(false) |
| 79 { | 78 { |
| 80 } | 79 } |
| 81 | 80 |
| 82 BitmapImage::BitmapImage(PassRefPtr<NativeImageSkia> nativeImage, ImageObserver*
observer) | 81 BitmapImage::BitmapImage(const SkBitmap& bitmap, ImageObserver* observer) |
| 83 : Image(observer) | 82 : Image(observer) |
| 84 , m_size(nativeImage->bitmap().width(), nativeImage->bitmap().height()) | 83 , m_size(bitmap.width(), bitmap.height()) |
| 85 , m_currentFrame(0) | 84 , m_currentFrame(0) |
| 86 , m_frames(0) | 85 , m_frames(0) |
| 87 , m_frameTimer(0) | 86 , m_frameTimer(0) |
| 88 , m_repetitionCount(cAnimationNone) | 87 , m_repetitionCount(cAnimationNone) |
| 89 , m_repetitionCountStatus(Unknown) | 88 , m_repetitionCountStatus(Unknown) |
| 90 , m_repetitionsComplete(0) | 89 , m_repetitionsComplete(0) |
| 91 , m_frameCount(1) | 90 , m_frameCount(1) |
| 92 , m_animationPolicy(ImageAnimationPolicyAllowed) | 91 , m_animationPolicy(ImageAnimationPolicyAllowed) |
| 93 , m_isSolidColor(false) | 92 , m_isSolidColor(false) |
| 94 , m_checkedForSolidColor(false) | 93 , m_checkedForSolidColor(false) |
| 95 , m_animationFinished(true) | 94 , m_animationFinished(true) |
| 96 , m_allDataReceived(true) | 95 , m_allDataReceived(true) |
| 97 , m_haveSize(true) | 96 , m_haveSize(true) |
| 98 , m_sizeAvailable(true) | 97 , m_sizeAvailable(true) |
| 99 , m_haveFrameCount(true) | 98 , m_haveFrameCount(true) |
| 100 { | 99 { |
| 101 // Since we don't have a decoder, we can't figure out the image orientation. | 100 // Since we don't have a decoder, we can't figure out the image orientation. |
| 102 // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0. | 101 // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0. |
| 103 m_sizeRespectingOrientation = m_size; | 102 m_sizeRespectingOrientation = m_size; |
| 104 | 103 |
| 105 m_frames.grow(1); | 104 m_frames.grow(1); |
| 106 m_frames[0].m_hasAlpha = !nativeImage->bitmap().isOpaque(); | 105 m_frames[0].m_hasAlpha = !bitmap.isOpaque(); |
| 107 m_frames[0].m_frame = nativeImage; | 106 m_frames[0].m_frame = bitmap; |
| 108 m_frames[0].m_haveMetadata = true; | 107 m_frames[0].m_haveMetadata = true; |
| 109 | 108 |
| 110 checkForSolidColor(); | 109 checkForSolidColor(); |
| 111 } | 110 } |
| 112 | 111 |
| 113 BitmapImage::~BitmapImage() | 112 BitmapImage::~BitmapImage() |
| 114 { | 113 { |
| 115 stopAnimation(); | 114 stopAnimation(); |
| 116 } | 115 } |
| 117 | 116 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 imageObserver()->decodedSizeChanged(this, -safeCast<int>(frameBytesClear
ed)); | 159 imageObserver()->decodedSizeChanged(this, -safeCast<int>(frameBytesClear
ed)); |
| 161 } | 160 } |
| 162 | 161 |
| 163 void BitmapImage::cacheFrame(size_t index) | 162 void BitmapImage::cacheFrame(size_t index) |
| 164 { | 163 { |
| 165 size_t numFrames = frameCount(); | 164 size_t numFrames = frameCount(); |
| 166 if (m_frames.size() < numFrames) | 165 if (m_frames.size() < numFrames) |
| 167 m_frames.grow(numFrames); | 166 m_frames.grow(numFrames); |
| 168 | 167 |
| 169 m_frames[index].m_frame = m_source.createFrameAtIndex(index); | 168 m_frames[index].m_frame = m_source.createFrameAtIndex(index); |
| 170 if (numFrames == 1 && m_frames[index].m_frame) | 169 if (numFrames == 1 && !m_frames[index].m_frame.isNull()) |
| 171 checkForSolidColor(); | 170 checkForSolidColor(); |
| 172 | 171 |
| 173 m_frames[index].m_orientation = m_source.orientationAtIndex(index); | 172 m_frames[index].m_orientation = m_source.orientationAtIndex(index); |
| 174 m_frames[index].m_haveMetadata = true; | 173 m_frames[index].m_haveMetadata = true; |
| 175 m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index); | 174 m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index); |
| 176 if (repetitionCount(false) != cAnimationNone) | 175 if (repetitionCount(false) != cAnimationNone) |
| 177 m_frames[index].m_duration = m_source.frameDurationAtIndex(index); | 176 m_frames[index].m_duration = m_source.frameDurationAtIndex(index); |
| 178 m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index); | 177 m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index); |
| 179 m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index); | 178 m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index); |
| 180 | 179 |
| 181 const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size); | 180 const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size); |
| 182 if (frameSize != m_size) | 181 if (frameSize != m_size) |
| 183 m_hasUniformFrameSize = false; | 182 m_hasUniformFrameSize = false; |
| 184 | 183 |
| 185 if (m_frames[index].m_frame) { | 184 if (!m_frames[index].m_frame.isNull()) { |
| 186 int deltaBytes = safeCast<int>(m_frames[index].m_frameBytes); | 185 int deltaBytes = safeCast<int>(m_frames[index].m_frameBytes); |
| 187 // The fully-decoded frame will subsume the partially decoded data used | 186 // The fully-decoded frame will subsume the partially decoded data used |
| 188 // to determine image properties. | 187 // to determine image properties. |
| 189 if (imageObserver()) | 188 if (imageObserver()) |
| 190 imageObserver()->decodedSizeChanged(this, deltaBytes); | 189 imageObserver()->decodedSizeChanged(this, deltaBytes); |
| 191 } | 190 } |
| 192 } | 191 } |
| 193 | 192 |
| 194 void BitmapImage::updateSize() const | 193 void BitmapImage::updateSize() const |
| 195 { | 194 { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 return m_source.hasColorProfile(); | 264 return m_source.hasColorProfile(); |
| 266 } | 265 } |
| 267 | 266 |
| 268 String BitmapImage::filenameExtension() const | 267 String BitmapImage::filenameExtension() const |
| 269 { | 268 { |
| 270 return m_source.filenameExtension(); | 269 return m_source.filenameExtension(); |
| 271 } | 270 } |
| 272 | 271 |
| 273 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const Fl
oatRect& srcRect, SkXfermode::Mode compositeOp, RespectImageOrientationEnum shou
ldRespectImageOrientation) | 272 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const Fl
oatRect& srcRect, SkXfermode::Mode compositeOp, RespectImageOrientationEnum shou
ldRespectImageOrientation) |
| 274 { | 273 { |
| 275 RefPtr<NativeImageSkia> image = nativeImageForCurrentFrame(); | 274 SkBitmap bitmap = bitmapForCurrentFrame(); |
| 276 if (!image) | 275 if (bitmap.isNull()) |
| 277 return; // It's too early and we don't have an image yet. | 276 return; // It's too early and we don't have an image yet. |
| 278 | 277 |
| 279 FloatRect normDstRect = adjustForNegativeSize(dstRect); | 278 FloatRect normDstRect = adjustForNegativeSize(dstRect); |
| 280 FloatRect normSrcRect = adjustForNegativeSize(srcRect); | 279 FloatRect normSrcRect = adjustForNegativeSize(srcRect); |
| 281 normSrcRect.intersect(FloatRect(0, 0, image->bitmap().width(), image->bitmap
().height())); | 280 normSrcRect.intersect(FloatRect(0, 0, bitmap.width(), bitmap.height())); |
| 282 | 281 |
| 283 if (normSrcRect.isEmpty() || normDstRect.isEmpty()) | 282 if (normSrcRect.isEmpty() || normDstRect.isEmpty()) |
| 284 return; // Nothing to draw. | 283 return; // Nothing to draw. |
| 285 | 284 |
| 286 ImageOrientation orientation = DefaultImageOrientation; | 285 ImageOrientation orientation = DefaultImageOrientation; |
| 287 if (shouldRespectImageOrientation == RespectImageOrientation) | 286 if (shouldRespectImageOrientation == RespectImageOrientation) |
| 288 orientation = frameOrientationAtIndex(m_currentFrame); | 287 orientation = frameOrientationAtIndex(m_currentFrame); |
| 289 | 288 |
| 290 GraphicsContextStateSaver saveContext(*ctxt, false); | 289 GraphicsContextStateSaver saveContext(*ctxt, false); |
| 291 if (orientation != DefaultImageOrientation) { | 290 if (orientation != DefaultImageOrientation) { |
| 292 saveContext.save(); | 291 saveContext.save(); |
| 293 | 292 |
| 294 // ImageOrientation expects the origin to be at (0, 0) | 293 // ImageOrientation expects the origin to be at (0, 0) |
| 295 ctxt->translate(normDstRect.x(), normDstRect.y()); | 294 ctxt->translate(normDstRect.x(), normDstRect.y()); |
| 296 normDstRect.setLocation(FloatPoint()); | 295 normDstRect.setLocation(FloatPoint()); |
| 297 | 296 |
| 298 ctxt->concatCTM(orientation.transformFromDefault(normDstRect.size())); | 297 ctxt->concatCTM(orientation.transformFromDefault(normDstRect.size())); |
| 299 | 298 |
| 300 if (orientation.usesWidthAsHeight()) { | 299 if (orientation.usesWidthAsHeight()) { |
| 301 // The destination rect will have it's width and height already reve
rsed for the orientation of | 300 // The destination rect will have it's width and height already reve
rsed for the orientation of |
| 302 // the image, as it was needed for page layout, so we need to revers
e it back here. | 301 // the image, as it was needed for page layout, so we need to revers
e it back here. |
| 303 normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRec
t.height(), normDstRect.width()); | 302 normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRec
t.height(), normDstRect.width()); |
| 304 } | 303 } |
| 305 } | 304 } |
| 306 | 305 |
| 307 image->draw(ctxt, normSrcRect, normDstRect, compositeOp); | 306 drawBitmap(ctxt, bitmap, normSrcRect, normDstRect, compositeOp); |
| 308 | 307 |
| 309 if (ImageObserver* observer = imageObserver()) | 308 if (ImageObserver* observer = imageObserver()) |
| 310 observer->didDraw(this); | 309 observer->didDraw(this); |
| 311 | 310 |
| 312 startAnimation(); | 311 startAnimation(); |
| 313 } | 312 } |
| 314 | 313 |
| 315 size_t BitmapImage::frameCount() | 314 size_t BitmapImage::frameCount() |
| 316 { | 315 { |
| 317 if (!m_haveFrameCount) { | 316 if (!m_haveFrameCount) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 332 m_sizeAvailable = m_source.isSizeAvailable(); | 331 m_sizeAvailable = m_source.isSizeAvailable(); |
| 333 | 332 |
| 334 return m_sizeAvailable; | 333 return m_sizeAvailable; |
| 335 } | 334 } |
| 336 | 335 |
| 337 bool BitmapImage::ensureFrameIsCached(size_t index) | 336 bool BitmapImage::ensureFrameIsCached(size_t index) |
| 338 { | 337 { |
| 339 if (index >= frameCount()) | 338 if (index >= frameCount()) |
| 340 return false; | 339 return false; |
| 341 | 340 |
| 342 if (index >= m_frames.size() || !m_frames[index].m_frame) | 341 if (index >= m_frames.size() || m_frames[index].m_frame.isNull()) |
| 343 cacheFrame(index); | 342 cacheFrame(index); |
| 344 | 343 |
| 345 return true; | 344 return true; |
| 346 } | 345 } |
| 347 | 346 |
| 348 PassRefPtr<NativeImageSkia> BitmapImage::frameAtIndex(size_t index) | 347 SkBitmap BitmapImage::frameAtIndex(size_t index) |
| 349 { | 348 { |
| 350 if (!ensureFrameIsCached(index)) | 349 if (!ensureFrameIsCached(index)) |
| 351 return nullptr; | 350 return SkBitmap(); |
| 352 | 351 |
| 353 return m_frames[index].m_frame; | 352 return m_frames[index].m_frame; |
| 354 } | 353 } |
| 355 | 354 |
| 356 bool BitmapImage::frameIsCompleteAtIndex(size_t index) | 355 bool BitmapImage::frameIsCompleteAtIndex(size_t index) |
| 357 { | 356 { |
| 358 if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[in
dex].m_isComplete) | 357 if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[in
dex].m_isComplete) |
| 359 return true; | 358 return true; |
| 360 | 359 |
| 361 return m_source.frameIsCompleteAtIndex(index); | 360 return m_source.frameIsCompleteAtIndex(index); |
| 362 } | 361 } |
| 363 | 362 |
| 364 float BitmapImage::frameDurationAtIndex(size_t index) | 363 float BitmapImage::frameDurationAtIndex(size_t index) |
| 365 { | 364 { |
| 366 if (index < m_frames.size() && m_frames[index].m_haveMetadata) | 365 if (index < m_frames.size() && m_frames[index].m_haveMetadata) |
| 367 return m_frames[index].m_duration; | 366 return m_frames[index].m_duration; |
| 368 | 367 |
| 369 return m_source.frameDurationAtIndex(index); | 368 return m_source.frameDurationAtIndex(index); |
| 370 } | 369 } |
| 371 | 370 |
| 372 PassRefPtr<NativeImageSkia> BitmapImage::nativeImageForCurrentFrame() | 371 SkBitmap BitmapImage::bitmapForCurrentFrame() |
| 373 { | 372 { |
| 374 return frameAtIndex(currentFrame()); | 373 return frameAtIndex(currentFrame()); |
| 375 } | 374 } |
| 376 | 375 |
| 377 PassRefPtr<Image> BitmapImage::imageForDefaultFrame() | 376 PassRefPtr<Image> BitmapImage::imageForDefaultFrame() |
| 378 { | 377 { |
| 379 if (frameCount() > 1 && frameAtIndex(0)) | 378 if (frameCount() > 1 && !frameAtIndex(0).isNull()) |
| 380 return BitmapImage::create(frameAtIndex(0)); | 379 return BitmapImage::create(frameAtIndex(0)); |
| 381 | 380 |
| 382 return Image::imageForDefaultFrame(); | 381 return Image::imageForDefaultFrame(); |
| 383 } | 382 } |
| 384 | 383 |
| 385 bool BitmapImage::frameHasAlphaAtIndex(size_t index) | 384 bool BitmapImage::frameHasAlphaAtIndex(size_t index) |
| 386 { | 385 { |
| 387 if (m_frames.size() <= index) | 386 if (m_frames.size() <= index) |
| 388 return true; | 387 return true; |
| 389 | 388 |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 } | 616 } |
| 618 | 617 |
| 619 void BitmapImage::checkForSolidColor() | 618 void BitmapImage::checkForSolidColor() |
| 620 { | 619 { |
| 621 m_isSolidColor = false; | 620 m_isSolidColor = false; |
| 622 m_checkedForSolidColor = true; | 621 m_checkedForSolidColor = true; |
| 623 | 622 |
| 624 if (frameCount() > 1) | 623 if (frameCount() > 1) |
| 625 return; | 624 return; |
| 626 | 625 |
| 627 RefPtr<NativeImageSkia> frame = frameAtIndex(0); | 626 SkBitmap bitmap = frameAtIndex(0); |
| 628 | 627 |
| 629 if (frame && size().width() == 1 && size().height() == 1) { | 628 if (!bitmap.isNull() && size().width() == 1 && size().height() == 1) { |
| 630 SkAutoLockPixels lock(frame->bitmap()); | 629 SkAutoLockPixels lock(bitmap); |
| 631 if (!frame->bitmap().getPixels()) | 630 if (!bitmap.getPixels()) |
| 632 return; | 631 return; |
| 633 | 632 |
| 634 m_isSolidColor = true; | 633 m_isSolidColor = true; |
| 635 m_solidColor = Color(frame->bitmap().getColor(0, 0)); | 634 m_solidColor = Color(bitmap.getColor(0, 0)); |
| 636 } | 635 } |
| 637 } | 636 } |
| 638 | 637 |
| 639 bool BitmapImage::mayFillWithSolidColor() | 638 bool BitmapImage::mayFillWithSolidColor() |
| 640 { | 639 { |
| 641 if (!m_checkedForSolidColor && frameCount() > 0) { | 640 if (!m_checkedForSolidColor && frameCount() > 0) { |
| 642 checkForSolidColor(); | 641 checkForSolidColor(); |
| 643 ASSERT(m_checkedForSolidColor); | 642 ASSERT(m_checkedForSolidColor); |
| 644 } | 643 } |
| 645 | 644 |
| 646 return m_isSolidColor && !m_currentFrame; | 645 return m_isSolidColor && !m_currentFrame; |
| 647 } | 646 } |
| 648 | 647 |
| 649 Color BitmapImage::solidColor() const | 648 Color BitmapImage::solidColor() const |
| 650 { | 649 { |
| 651 return m_solidColor; | 650 return m_solidColor; |
| 652 } | 651 } |
| 653 | 652 |
| 654 } // namespace blink | 653 } // namespace blink |
| OLD | NEW |