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 "FloatRect.h" 38#include "GraphicsContext.h" 39#include "ImageObserver.h" 40#include "ShadowBlur.h" 41#include "StillImageQt.h" 42#include <wtf/text/WTFString.h> 43 44#include <QCoreApplication> 45#include <QDebug> 46#include <QImage> 47#include <QImageReader> 48#include <QPainter> 49#include <QPixmap> 50#include <QTransform> 51 52#include <math.h> 53 54#if OS(WINDOWS) 55QT_BEGIN_NAMESPACE 56Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP, int hbitmapFormat = 0); 57QT_END_NAMESPACE 58#endif 59 60typedef QHash<QByteArray, QPixmap> WebGraphicHash; 61Q_GLOBAL_STATIC(WebGraphicHash, _graphics) 62 63static void earlyClearGraphics() 64{ 65 _graphics()->clear(); 66} 67 68static WebGraphicHash* graphics() 69{ 70 WebGraphicHash* hash = _graphics(); 71 72 if (hash->isEmpty()) { 73 74 // prevent ~QPixmap running after ~QApplication (leaks native pixmaps) 75 qAddPostRoutine(earlyClearGraphics); 76 77 // QWebSettings::MissingImageGraphic 78 hash->insert("missingImage", QPixmap(QLatin1String(":webkit/resources/missingImage.png"))); 79 // QWebSettings::MissingPluginGraphic 80 hash->insert("nullPlugin", QPixmap(QLatin1String(":webkit/resources/nullPlugin.png"))); 81 // QWebSettings::DefaultFrameIconGraphic 82 hash->insert("urlIcon", QPixmap(QLatin1String(":webkit/resources/urlIcon.png"))); 83 // QWebSettings::TextAreaSizeGripCornerGraphic 84 hash->insert("textAreaResizeCorner", QPixmap(QLatin1String(":webkit/resources/textAreaResizeCorner.png"))); 85 // QWebSettings::DeleteButtonGraphic 86 hash->insert("deleteButton", QPixmap(QLatin1String(":webkit/resources/deleteButton.png"))); 87 // QWebSettings::InputSpeechButtonGraphic 88 hash->insert("inputSpeech", QPixmap(QLatin1String(":webkit/resources/inputSpeech.png"))); 89 } 90 91 return hash; 92} 93 94// This function loads resources into WebKit 95static QPixmap loadResourcePixmap(const char *name) 96{ 97 return graphics()->value(name); 98} 99 100namespace WebCore { 101 102bool FrameData::clear(bool clearMetadata) 103{ 104 if (clearMetadata) 105 m_haveMetadata = false; 106 107 if (m_frame) { 108 delete m_frame; 109 m_frame = 0; 110 return true; 111 } 112 return false; 113} 114 115 116// ================================================ 117// Image Class 118// ================================================ 119 120PassRefPtr<Image> Image::loadPlatformResource(const char* name) 121{ 122 return StillImage::create(loadResourcePixmap(name)); 123} 124 125void Image::setPlatformResource(const char* name, const QPixmap& pixmap) 126{ 127 WebGraphicHash* h = graphics(); 128 if (pixmap.isNull()) 129 h->remove(name); 130 else 131 h->insert(name, pixmap); 132} 133 134void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, 135 const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode) 136{ 137 QPixmap* framePixmap = nativeImageForCurrentFrame(); 138 if (!framePixmap) // If it's too early we won't have an image yet. 139 return; 140 141#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) 142 FloatRect tileRectAdjusted = adjustSourceRectForDownSampling(tileRect, framePixmap->size()); 143#else 144 FloatRect tileRectAdjusted = tileRect; 145#endif 146 147 // Qt interprets 0 width/height as full width/height so just short circuit. 148 QRectF dr = QRectF(destRect).normalized(); 149 QRect tr = QRectF(tileRectAdjusted).toRect().normalized(); 150 if (!dr.width() || !dr.height() || !tr.width() || !tr.height()) 151 return; 152 153 QPixmap pixmap = *framePixmap; 154 if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) 155 pixmap = pixmap.copy(tr); 156 157 CompositeOperator previousOperator = ctxt->compositeOperation(); 158 159 ctxt->setCompositeOperation(!pixmap.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); 160 161 QPainter* p = ctxt->platformContext(); 162 QTransform transform(patternTransform); 163 164 // If this would draw more than one scaled tile, we scale the pixmap first and then use the result to draw. 165 if (transform.type() == QTransform::TxScale) { 166 QRectF tileRectInTargetCoords = (transform * QTransform().translate(phase.x(), phase.y())).mapRect(tr); 167 168 bool tileWillBePaintedOnlyOnce = tileRectInTargetCoords.contains(dr); 169 if (!tileWillBePaintedOnlyOnce) { 170 QSizeF scaledSize(float(pixmap.width()) * transform.m11(), float(pixmap.height()) * transform.m22()); 171 QPixmap scaledPixmap(scaledSize.toSize()); 172 if (pixmap.hasAlpha()) 173 scaledPixmap.fill(Qt::transparent); 174 { 175 QPainter painter(&scaledPixmap); 176 painter.setCompositionMode(QPainter::CompositionMode_Source); 177 painter.setRenderHints(p->renderHints()); 178 painter.drawPixmap(QRect(0, 0, scaledPixmap.width(), scaledPixmap.height()), pixmap); 179 } 180 pixmap = scaledPixmap; 181 transform = QTransform::fromTranslate(transform.dx(), transform.dy()); 182 } 183 } 184 185 /* Translate the coordinates as phase is not in world matrix coordinate space but the tile rect origin is. */ 186 transform *= QTransform().translate(phase.x(), phase.y()); 187 transform.translate(tr.x(), tr.y()); 188 189 QBrush b(pixmap); 190 b.setTransform(transform); 191 p->fillRect(dr, b); 192 193 ctxt->setCompositeOperation(previousOperator); 194 195 if (imageObserver()) 196 imageObserver()->didDraw(this); 197} 198 199BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer) 200 : Image(observer) 201 , m_currentFrame(0) 202 , m_frames(0) 203 , m_frameTimer(0) 204 , m_repetitionCount(cAnimationNone) 205 , m_repetitionCountStatus(Unknown) 206 , m_repetitionsComplete(0) 207 , m_decodedSize(0) 208 , m_frameCount(1) 209 , m_isSolidColor(false) 210 , m_checkedForSolidColor(false) 211 , m_animationFinished(true) 212 , m_allDataReceived(true) 213 , m_haveSize(true) 214 , m_sizeAvailable(true) 215 , m_haveFrameCount(true) 216{ 217 int width = pixmap->width(); 218 int height = pixmap->height(); 219 m_decodedSize = width * height * 4; 220 m_size = IntSize(width, height); 221 222 m_frames.grow(1); 223 m_frames[0].m_frame = pixmap; 224 m_frames[0].m_hasAlpha = pixmap->hasAlpha(); 225 m_frames[0].m_haveMetadata = true; 226 checkForSolidColor(); 227} 228 229void BitmapImage::invalidatePlatformData() 230{ 231} 232 233// Drawing Routines 234void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, 235 const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op, BlendMode) 236{ 237 QRectF normalizedDst = dst.normalized(); 238 QRectF normalizedSrc = src.normalized(); 239 240 startAnimation(); 241 242 if (normalizedSrc.isEmpty() || normalizedDst.isEmpty()) 243 return; 244 245 QPixmap* image = nativeImageForCurrentFrame(); 246 if (!image) 247 return; 248 249 if (mayFillWithSolidColor()) { 250 fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op); 251 return; 252 } 253 254#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) 255 normalizedSrc = adjustSourceRectForDownSampling(normalizedSrc, image->size()); 256#endif 257 258 CompositeOperator previousOperator = ctxt->compositeOperation(); 259 ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); 260 261 if (ctxt->hasShadow()) { 262 ShadowBlur shadow(ctxt->state()); 263 GraphicsContext* shadowContext = shadow.beginShadowLayer(ctxt, normalizedDst); 264 if (shadowContext) { 265 QPainter* shadowPainter = shadowContext->platformContext(); 266 shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc); 267 shadow.endShadowLayer(ctxt); 268 } 269 } 270 271 ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); 272 273 ctxt->setCompositeOperation(previousOperator); 274 275 if (imageObserver()) 276 imageObserver()->didDraw(this); 277} 278 279void BitmapImage::checkForSolidColor() 280{ 281 m_isSolidColor = false; 282 m_checkedForSolidColor = true; 283 284 if (frameCount() > 1) 285 return; 286 287 QPixmap* framePixmap = frameAtIndex(0); 288 if (!framePixmap || framePixmap->width() != 1 || framePixmap->height() != 1) 289 return; 290 291 m_isSolidColor = true; 292 m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0)); 293} 294 295#if OS(WINDOWS) 296PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) 297{ 298 QPixmap* qPixmap = new QPixmap(qt_pixmapFromWinHBITMAP(hBitmap)); 299 300 return BitmapImage::create(qPixmap); 301} 302#endif 303 304} 305 306 307// vim: ts=4 sw=4 et 308