1/* 2 * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> 3 * Copyright (C) 2006 Zack Rusin <zack@kde.org> 4 * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> 5 * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ 6 * Copyright (C) 2010 Sencha, Inc. 7 * 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "config.h" 33#include "Image.h" 34 35#include "AffineTransform.h" 36#include "BitmapImage.h" 37#include "ContextShadow.h" 38#include "FloatRect.h" 39#include "GraphicsContext.h" 40#include "ImageObserver.h" 41#include "PlatformString.h" 42#include "StillImageQt.h" 43#include "qwebsettings.h" 44 45#include <QPixmap> 46#include <QPainter> 47#include <QImage> 48#include <QImageReader> 49#include <QTransform> 50 51#include <QDebug> 52 53#include <math.h> 54 55// This function loads resources into WebKit 56static QPixmap loadResourcePixmap(const char *name) 57{ 58 QPixmap pixmap; 59 if (qstrcmp(name, "missingImage") == 0) 60 pixmap = QWebSettings::webGraphic(QWebSettings::MissingImageGraphic); 61 else if (qstrcmp(name, "nullPlugin") == 0) 62 pixmap = QWebSettings::webGraphic(QWebSettings::MissingPluginGraphic); 63 else if (qstrcmp(name, "urlIcon") == 0) 64 pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic); 65 else if (qstrcmp(name, "textAreaResizeCorner") == 0) 66 pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic); 67 else if (qstrcmp(name, "deleteButton") == 0) 68 pixmap = QWebSettings::webGraphic(QWebSettings::DeleteButtonGraphic); 69 else if (!qstrcmp(name, "inputSpeech")) 70 pixmap = QWebSettings::webGraphic(QWebSettings::InputSpeechButtonGraphic); 71 else if (!qstrcmp(name, "searchCancelButton")) 72 pixmap = QWebSettings::webGraphic(QWebSettings::SearchCancelButtonGraphic); 73 else if (!qstrcmp(name, "searchCancelButtonPressed")) 74 pixmap = QWebSettings::webGraphic(QWebSettings::SearchCancelButtonPressedGraphic); 75 76 return pixmap; 77} 78 79namespace WebCore { 80 81bool FrameData::clear(bool clearMetadata) 82{ 83 if (clearMetadata) 84 m_haveMetadata = false; 85 86 if (m_frame) { 87 delete m_frame; 88 m_frame = 0; 89 return true; 90 } 91 return false; 92} 93 94 95// ================================================ 96// Image Class 97// ================================================ 98 99PassRefPtr<Image> Image::loadPlatformResource(const char* name) 100{ 101 return StillImage::create(loadResourcePixmap(name)); 102} 103 104void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, 105 const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect) 106{ 107 QPixmap* framePixmap = nativeImageForCurrentFrame(); 108 if (!framePixmap) // If it's too early we won't have an image yet. 109 return; 110 111 // Qt interprets 0 width/height as full width/height so just short circuit. 112 QRectF dr = QRectF(destRect).normalized(); 113 QRect tr = QRectF(tileRect).toRect().normalized(); 114 if (!dr.width() || !dr.height() || !tr.width() || !tr.height()) 115 return; 116 117 QPixmap pixmap = *framePixmap; 118 if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) 119 pixmap = pixmap.copy(tr); 120 121 CompositeOperator previousOperator = ctxt->compositeOperation(); 122 123 ctxt->setCompositeOperation(!pixmap.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); 124 125 QPainter* p = ctxt->platformContext(); 126 QTransform transform(patternTransform); 127 128 // If this would draw more than one scaled tile, we scale the pixmap first and then use the result to draw. 129 if (transform.type() == QTransform::TxScale) { 130 QRectF tileRectInTargetCoords = (transform * QTransform().translate(phase.x(), phase.y())).mapRect(tr); 131 132 bool tileWillBePaintedOnlyOnce = tileRectInTargetCoords.contains(dr); 133 if (!tileWillBePaintedOnlyOnce) { 134 QSizeF scaledSize(float(pixmap.width()) * transform.m11(), float(pixmap.height()) * transform.m22()); 135 QPixmap scaledPixmap(scaledSize.toSize()); 136 if (pixmap.hasAlpha()) 137 scaledPixmap.fill(Qt::transparent); 138 { 139 QPainter painter(&scaledPixmap); 140 painter.setCompositionMode(QPainter::CompositionMode_Source); 141 painter.setRenderHints(p->renderHints()); 142 painter.drawPixmap(QRect(0, 0, scaledPixmap.width(), scaledPixmap.height()), pixmap); 143 } 144 pixmap = scaledPixmap; 145 transform = QTransform::fromTranslate(transform.dx(), transform.dy()); 146 } 147 } 148 149 /* Translate the coordinates as phase is not in world matrix coordinate space but the tile rect origin is. */ 150 transform *= QTransform().translate(phase.x(), phase.y()); 151 transform.translate(tr.x(), tr.y()); 152 153 QBrush b(pixmap); 154 b.setTransform(transform); 155 p->fillRect(dr, b); 156 157 ctxt->setCompositeOperation(previousOperator); 158 159 if (imageObserver()) 160 imageObserver()->didDraw(this); 161} 162 163BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer) 164 : Image(observer) 165 , m_currentFrame(0) 166 , m_frames(0) 167 , m_frameTimer(0) 168 , m_repetitionCount(cAnimationNone) 169 , m_repetitionCountStatus(Unknown) 170 , m_repetitionsComplete(0) 171 , m_isSolidColor(false) 172 , m_checkedForSolidColor(false) 173 , m_animationFinished(true) 174 , m_allDataReceived(true) 175 , m_haveSize(true) 176 , m_sizeAvailable(true) 177 , m_decodedSize(0) 178 , m_haveFrameCount(true) 179 , m_frameCount(1) 180{ 181 initPlatformData(); 182 183 int width = pixmap->width(); 184 int height = pixmap->height(); 185 m_decodedSize = width * height * 4; 186 m_size = IntSize(width, height); 187 188 m_frames.grow(1); 189 m_frames[0].m_frame = pixmap; 190 m_frames[0].m_hasAlpha = pixmap->hasAlpha(); 191 m_frames[0].m_haveMetadata = true; 192 checkForSolidColor(); 193} 194 195void BitmapImage::initPlatformData() 196{ 197} 198 199void BitmapImage::invalidatePlatformData() 200{ 201} 202 203// Drawing Routines 204void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, 205 const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) 206{ 207 QRectF normalizedDst = dst.normalized(); 208 QRectF normalizedSrc = src.normalized(); 209 210 startAnimation(); 211 212 if (normalizedSrc.isEmpty() || normalizedDst.isEmpty()) 213 return; 214 215 QPixmap* image = nativeImageForCurrentFrame(); 216 if (!image) 217 return; 218 219 if (mayFillWithSolidColor()) { 220 fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op); 221 return; 222 } 223 224 CompositeOperator previousOperator = ctxt->compositeOperation(); 225 ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); 226 227 ContextShadow* shadow = ctxt->contextShadow(); 228 if (shadow->m_type != ContextShadow::NoShadow) { 229 QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst); 230 if (shadowPainter) { 231 shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); 232 shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc); 233 shadow->endShadowLayer(ctxt); 234 } 235 } 236 237 ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); 238 239 ctxt->setCompositeOperation(previousOperator); 240 241 if (imageObserver()) 242 imageObserver()->didDraw(this); 243} 244 245void BitmapImage::checkForSolidColor() 246{ 247 m_isSolidColor = false; 248 m_checkedForSolidColor = true; 249 250 if (frameCount() > 1) 251 return; 252 253 QPixmap* framePixmap = frameAtIndex(0); 254 if (!framePixmap || framePixmap->width() != 1 || framePixmap->height() != 1) 255 return; 256 257 m_isSolidColor = true; 258 m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0)); 259} 260 261#if OS(WINDOWS) 262PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) 263{ 264 return BitmapImage::create(new QPixmap(QPixmap::fromWinHBITMAP(hBitmap))); 265} 266#endif 267 268} 269 270 271// vim: ts=4 sw=4 et 272