1/* 2 * Copyright (C) 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20#include "Image.h" 21 22#include "AffineTransform.h" 23#include "BitmapImage.h" 24#include "FloatConversion.h" 25#include "FloatRect.h" 26#include "GraphicsContext.h" 27#include "ImageBuffer.h" 28#include "ImageDecoder.h" 29#include "ImageObserver.h" 30#include "IntSize.h" 31#include "NotImplemented.h" 32#include "SharedBuffer.h" 33 34#include <BlackBerryPlatformGraphicsContext.h> 35#include <BlackBerryPlatformResourceStore.h> 36#include <wtf/MathExtras.h> 37 38using BlackBerry::Platform::ResourceData; 39using BlackBerry::Platform::ResourceStore; 40 41namespace WebCore { 42 43PassRefPtr<Image> Image::loadPlatformResource(const char *name) 44{ 45 ResourceData data = ResourceStore::instance()->requestResource(BlackBerry::Platform::String::fromUtf8(name)); 46 if (!data.data()) 47 return BitmapImage::nullImage(); 48 49 RefPtr<SharedBuffer> buffer = SharedBuffer::create(data.data(), data.len()); 50 if (!buffer) 51 return BitmapImage::nullImage(); 52 53 RefPtr<BitmapImage> img = BitmapImage::create(); 54 img->setData(buffer.release(), true /* allDataReceived */); 55 return img.release(); 56} 57 58PassNativeImagePtr ImageFrame::asNewNativeImage() const 59{ 60 return new BlackBerry::Platform::Graphics::TiledImage(m_size, m_bytes); 61} 62 63bool FrameData::clear(bool clearMetadata) 64{ 65 if (clearMetadata) 66 m_haveMetadata = false; 67 68 if (m_frame) { 69 delete m_frame; 70 m_frame = 0; 71 return true; 72 } 73 return false; 74} 75 76BitmapImage::BitmapImage(PassNativeImagePtr nativeImage, ImageObserver* observer) 77 : Image(observer) 78 , m_currentFrame(0) 79 , m_frames(0) 80 , m_frameTimer(0) 81 , m_repetitionCount(cAnimationNone) 82 , m_repetitionCountStatus(Unknown) 83 , m_repetitionsComplete(0) 84 , m_decodedSize(0) 85 , m_frameCount(1) 86 , m_isSolidColor(false) 87 , m_checkedForSolidColor(false) 88 , m_animationFinished(true) 89 , m_allDataReceived(true) 90 , m_haveSize(true) 91 , m_sizeAvailable(true) 92 , m_haveFrameCount(true) 93{ 94 int width = nativeImage->size().width(); 95 int height = nativeImage->size().height(); 96 m_decodedSize = width * height * 4; 97 m_size = IntSize(width, height); 98 99 m_frames.grow(1); 100 m_frames[0].m_frame = nativeImage; 101 m_frames[0].m_hasAlpha = nativeImage->hasAlpha(); 102 m_frames[0].m_haveMetadata = true; 103 checkForSolidColor(); 104} 105 106void BitmapImage::checkForSolidColor() 107{ 108 m_isSolidColor = size().width() == 1 && size().height() == 1 && frameCount() == 1; 109 m_checkedForSolidColor = true; 110 if (m_isSolidColor) { 111 unsigned buffer; 112 NativeImagePtr image = nativeImageForCurrentFrame(); 113 image->readPixels(&buffer, 1); 114 m_solidColor = Color(buffer); 115 } 116} 117 118void BitmapImage::invalidatePlatformData() 119{ 120} 121 122void BitmapImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator op, BlendMode blendMode) 123{ 124 draw(context, dstRect, srcRect, styleColorSpace, op, blendMode, DoNotRespectImageOrientation); 125} 126 127void BitmapImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator op, BlendMode, RespectImageOrientationEnum shouldRespectImageOrientation) 128{ 129 startAnimation(); 130 131 NativeImagePtr image = nativeImageForCurrentFrame(); 132 if (!image) 133 return; 134 135 FloatRect normDstRect = dstRect.normalized(); 136 FloatRect normSrcRect = srcRect.normalized(); 137 138 if (normSrcRect.isEmpty() || normDstRect.isEmpty()) 139 return; // Nothing to draw. 140 141#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) 142 normSrcRect = adjustSourceRectForDownSampling(normSrcRect, image->size()); 143#endif 144 145 // use similar orientation code as ImageSkia 146 ImageOrientation orientation = DefaultImageOrientation; 147 if (shouldRespectImageOrientation == RespectImageOrientation) 148 orientation = frameOrientationAtIndex(m_currentFrame); 149 150 GraphicsContextStateSaver saveContext(*context, false); 151 if (orientation != DefaultImageOrientation) { 152 saveContext.save(); 153 154 // ImageOrientation expects the origin to be at (0, 0) 155 context->translate(normDstRect.x(), normDstRect.y()); 156 normDstRect.setLocation(FloatPoint()); 157 158 context->concatCTM(orientation.transformFromDefault(normDstRect.size())); 159 if (orientation.usesWidthAsHeight()) { 160 // The destination rect will have its width and height already reversed for the orientation of 161 // the image, as it was needed for page layout, so we need to reverse it back here. 162 normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRect.height(), normDstRect.width()); 163 } 164 } 165 166 CompositeOperator oldOperator = context->compositeOperation(); 167 context->setCompositeOperation(op); 168 context->platformContext()->addImage(normDstRect, normSrcRect, image); 169 context->setCompositeOperation(oldOperator); 170 171 if (ImageObserver* observer = imageObserver()) 172 observer->didDraw(this); 173} 174 175void Image::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransformation, const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& dstRect, BlendMode) 176{ 177 NativeImagePtr image = nativeImageForCurrentFrame(); 178 if (!image) 179 return; 180 181 // patternTransformation contains the tile scale factor relative to 182 // document coordinates. phase is given in document coordinates and 183 // corresponds to a texture drawn with src starting at (0, 0). 184 // Thus, dstRect starts at phase + patternTransformation.mapPoint(srcRect.location()). 185 AffineTransform srcTransform; 186 srcTransform.translate(phase.x(), phase.y()); 187 srcTransform.multiply(patternTransformation); 188#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) 189 FloatRect srcRectLocal(srcRect); 190 const IntSize unscaledSize = size(); 191 const IntSize scaledSize = image->size(); 192 if (unscaledSize != scaledSize) { 193 srcRectLocal = adjustSourceRectForDownSampling(srcRect, scaledSize); 194 // If the image has been down sampled, the transformation should take the scale into account. 195 float xscale = static_cast<float>(unscaledSize.width()) / scaledSize.width(); 196 float yscale = static_cast<float>(unscaledSize.height()) / scaledSize.height(); 197 srcTransform.scaleNonUniform(xscale, yscale); 198 } 199#else 200 FloatRect srcRectLocal(srcRect); 201#endif 202 srcTransform.translate(srcRectLocal.x(), srcRectLocal.y()); 203 double srcTransformArray[6] = { 204 srcTransform.a(), srcTransform.b(), 205 srcTransform.c(), srcTransform.d(), 206 srcTransform.e(), srcTransform.f() 207 }; 208 209 CompositeOperator oldOperator = context->compositeOperation(); 210 context->setCompositeOperation(op); 211 context->platformContext()->addPattern(dstRect, srcRectLocal, srcTransformArray, image); 212 context->setCompositeOperation(oldOperator); 213} 214 215} // namespace WebCore 216