1/* 2 * Copyright (C) 2004, 2005, 2006 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Alp Toker <alp@atoker.com> 4 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29#include "BitmapImage.h" 30 31#include "CairoUtilities.h" 32#include "ImageObserver.h" 33#include "PlatformContextCairo.h" 34#include "Timer.h" 35#include <cairo.h> 36 37namespace WebCore { 38 39BitmapImage::BitmapImage(PassRefPtr<cairo_surface_t> nativeImage, ImageObserver* observer) 40 : Image(observer) 41 , m_size(cairoSurfaceSize(nativeImage.get())) 42 , m_currentFrame(0) 43 , m_repetitionCount(cAnimationNone) 44 , m_repetitionCountStatus(Unknown) 45 , m_repetitionsComplete(0) 46 , m_decodedSize(m_size.width() * m_size.height() * 4) 47 , m_frameCount(1) 48 , m_isSolidColor(false) 49 , m_checkedForSolidColor(false) 50 , m_animationFinished(true) 51 , m_allDataReceived(true) 52 , m_haveSize(true) 53 , m_sizeAvailable(true) 54 , m_haveFrameCount(true) 55{ 56 m_frames.grow(1); 57 m_frames[0].m_hasAlpha = cairo_surface_get_content(nativeImage.get()) != CAIRO_CONTENT_COLOR; 58 m_frames[0].m_frame = nativeImage; 59 m_frames[0].m_haveMetadata = true; 60 61 checkForSolidColor(); 62} 63 64void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op, 65 BlendMode blendMode, ImageOrientationDescription description) 66{ 67 if (!dst.width() || !dst.height() || !src.width() || !src.height()) 68 return; 69 70 startAnimation(); 71 72 RefPtr<cairo_surface_t> surface = frameAtIndex(m_currentFrame); 73 if (!surface) // If it's too early we won't have an image yet. 74 return; 75 76 if (mayFillWithSolidColor()) { 77 fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); 78 return; 79 } 80 81 context->save(); 82 83 // Set the compositing operation. 84 if (op == CompositeSourceOver && blendMode == BlendModeNormal && !frameHasAlphaAtIndex(m_currentFrame)) 85 context->setCompositeOperation(CompositeCopy); 86 else 87 context->setCompositeOperation(op, blendMode); 88 89#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) 90 IntSize scaledSize = cairoSurfaceSize(surface.get()); 91 FloatRect adjustedSrcRect = adjustSourceRectForDownSampling(src, scaledSize); 92#else 93 FloatRect adjustedSrcRect(src); 94#endif 95 96 ImageOrientation frameOrientation(description.imageOrientation()); 97 if (description.respectImageOrientation() == RespectImageOrientation) 98 frameOrientation = frameOrientationAtIndex(m_currentFrame); 99 100 FloatRect dstRect = dst; 101 102 if (frameOrientation != DefaultImageOrientation) { 103 // ImageOrientation expects the origin to be at (0, 0). 104 context->translate(dstRect.x(), dstRect.y()); 105 dstRect.setLocation(FloatPoint()); 106 context->concatCTM(frameOrientation.transformFromDefault(dstRect.size())); 107 if (frameOrientation.usesWidthAsHeight()) { 108 // The destination rectangle will have it's width and height already reversed for the orientation of 109 // the image, as it was needed for page layout, so we need to reverse it back here. 110 dstRect = FloatRect(dstRect.x(), dstRect.y(), dstRect.height(), dstRect.width()); 111 } 112 } 113 114 context->platformContext()->drawSurfaceToContext(surface.get(), dstRect, adjustedSrcRect, context); 115 116 context->restore(); 117 118 if (imageObserver()) 119 imageObserver()->didDraw(this); 120} 121 122void BitmapImage::checkForSolidColor() 123{ 124 m_isSolidColor = false; 125 m_checkedForSolidColor = true; 126 127 if (frameCount() > 1) 128 return; 129 130 RefPtr<cairo_surface_t> surface = frameAtIndex(m_currentFrame); 131 if (!surface) // If it's too early we won't have an image yet. 132 return; 133 134 if (cairo_surface_get_type(surface.get()) != CAIRO_SURFACE_TYPE_IMAGE) 135 return; 136 137 IntSize size = cairoSurfaceSize(surface.get()); 138 139 if (size.width() != 1 || size.height() != 1) 140 return; 141 142 unsigned* pixelColor = reinterpret_cast_ptr<unsigned*>(cairo_image_surface_get_data(surface.get())); 143 m_solidColor = colorFromPremultipliedARGB(*pixelColor); 144 145 m_isSolidColor = true; 146} 147 148bool FrameData::clear(bool clearMetadata) 149{ 150 if (clearMetadata) 151 m_haveMetadata = false; 152 153 if (m_frame) { 154 m_frame.clear(); 155 return true; 156 } 157 return false; 158} 159 160} // namespace WebCore 161 162