blob: fc01c407d28341e9f52d7f36b2ea51f567f04c9d [file] [log] [blame]
rwlbuis98021982006-08-23 21:04:08 +00001/*
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>
treat@webkit.orgf793b272009-03-02 15:37:02 +00005 * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
commit-queue@webkit.org580b2cb2010-11-23 08:00:30 +00006 * Copyright (C) 2010 Sencha, Inc.
rwlbuis98021982006-08-23 21:04:08 +00007 *
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
krit@webkit.org2b95a9a2010-02-08 20:30:42 +000035#include "AffineTransform.h"
eseidel61952852006-12-29 01:57:44 +000036#include "BitmapImage.h"
rwlbuis98021982006-08-23 21:04:08 +000037#include "FloatRect.h"
38#include "GraphicsContext.h"
commit-queue@webkit.org580b2cb2010-11-23 08:00:30 +000039#include "ImageObserver.h"
commit-queue@webkit.orgd1e03a72011-07-05 21:29:42 +000040#include "ShadowBlur.h"
hausmann@webkit.orgedf35132008-05-08 14:58:01 +000041#include "StillImageQt.h"
weinig@apple.com3f5ab022012-09-06 17:36:48 +000042#include <wtf/text/WTFString.h>
rwlbuis98021982006-08-23 21:04:08 +000043
hausmann@webkit.orgea04d9f2012-02-15 14:14:27 +000044#include <QCoreApplication>
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000045#include <QDebug>
rwlbuis98021982006-08-23 21:04:08 +000046#include <QImage>
47#include <QImageReader>
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000048#include <QPainter>
49#include <QPixmap>
larsf6076a42007-01-17 19:04:39 +000050#include <QTransform>
rwlbuis98021982006-08-23 21:04:08 +000051
rwlbuis98021982006-08-23 21:04:08 +000052#include <math.h>
53
hausmann@webkit.org2d2e5352012-08-07 12:06:52 +000054#if OS(WINDOWS)
ossy@webkit.org618d62e32012-06-12 13:30:54 +000055Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP, int hbitmapFormat = 0);
56#endif
57
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000058typedef QHash<QByteArray, QPixmap> WebGraphicHash;
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000059Q_GLOBAL_STATIC(WebGraphicHash, _graphics)
60
61static void earlyClearGraphics()
62{
63 _graphics()->clear();
64}
65
66static WebGraphicHash* graphics()
67{
68 WebGraphicHash* hash = _graphics();
69
70 if (hash->isEmpty()) {
71
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000072 // prevent ~QPixmap running after ~QApplication (leaks native pixmaps)
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000073 qAddPostRoutine(earlyClearGraphics);
74
75 // QWebSettings::MissingImageGraphic
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000076 hash->insert("missingImage", QPixmap(QLatin1String(":webkit/resources/missingImage.png")));
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000077 // QWebSettings::MissingPluginGraphic
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000078 hash->insert("nullPlugin", QPixmap(QLatin1String(":webkit/resources/nullPlugin.png")));
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000079 // QWebSettings::DefaultFrameIconGraphic
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000080 hash->insert("urlIcon", QPixmap(QLatin1String(":webkit/resources/urlIcon.png")));
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000081 // QWebSettings::TextAreaSizeGripCornerGraphic
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000082 hash->insert("textAreaResizeCorner", QPixmap(QLatin1String(":webkit/resources/textAreaResizeCorner.png")));
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000083 // QWebSettings::DeleteButtonGraphic
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000084 hash->insert("deleteButton", QPixmap(QLatin1String(":webkit/resources/deleteButton.png")));
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000085 // QWebSettings::InputSpeechButtonGraphic
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000086 hash->insert("inputSpeech", QPixmap(QLatin1String(":webkit/resources/inputSpeech.png")));
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000087 }
88
89 return hash;
90}
91
staikoscdc883d2007-06-22 03:29:41 +000092// This function loads resources into WebKit
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +000093static QPixmap loadResourcePixmap(const char *name)
hausmann15e7c0e2007-11-07 14:30:50 +000094{
hausmann@webkit.org71c57c72011-11-17 14:22:48 +000095 return graphics()->value(name);
hausmann15e7c0e2007-11-07 14:30:50 +000096}
rwlbuis98021982006-08-23 21:04:08 +000097
98namespace WebCore {
99
pkasting@chromium.orga2910e12009-01-09 18:46:51 +0000100bool FrameData::clear(bool clearMetadata)
rwlbuis98021982006-08-23 21:04:08 +0000101{
pkasting@chromium.orga2910e12009-01-09 18:46:51 +0000102 if (clearMetadata)
103 m_haveMetadata = false;
104
rwlbuis98021982006-08-23 21:04:08 +0000105 if (m_frame) {
hausmann@webkit.org88b3eb32009-10-06 14:14:10 +0000106 delete m_frame;
rwlbuis98021982006-08-23 21:04:08 +0000107 m_frame = 0;
pkasting@chromium.orga2910e12009-01-09 18:46:51 +0000108 return true;
rwlbuis98021982006-08-23 21:04:08 +0000109 }
pkasting@chromium.orga2910e12009-01-09 18:46:51 +0000110 return false;
rwlbuis98021982006-08-23 21:04:08 +0000111}
112
larsf6076a42007-01-17 19:04:39 +0000113
rwlbuis98021982006-08-23 21:04:08 +0000114// ================================================
115// Image Class
116// ================================================
117
eric@webkit.orgac3f6662008-08-14 01:15:50 +0000118PassRefPtr<Image> Image::loadPlatformResource(const char* name)
rwlbuis98021982006-08-23 21:04:08 +0000119{
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000120 return StillImage::create(loadResourcePixmap(name));
rwlbuis98021982006-08-23 21:04:08 +0000121}
122
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000123void Image::setPlatformResource(const char* name, const QPixmap& pixmap)
hausmann@webkit.org71c57c72011-11-17 14:22:48 +0000124{
125 WebGraphicHash* h = graphics();
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000126 if (pixmap.isNull())
hausmann@webkit.org71c57c72011-11-17 14:22:48 +0000127 h->remove(name);
128 else
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000129 h->insert(name, pixmap);
hausmann@webkit.org71c57c72011-11-17 14:22:48 +0000130}
131
krit@webkit.org2b95a9a2010-02-08 20:30:42 +0000132void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
eric@webkit.orgdabc7d22009-12-17 00:41:04 +0000133 const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect)
larsf6076a42007-01-17 19:04:39 +0000134{
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000135 QPixmap* framePixmap = nativeImageForCurrentFrame();
136 if (!framePixmap) // If it's too early we won't have an image yet.
hausmann@webkit.org42009bb2009-02-07 15:33:19 +0000137 return;
138
commit-queue@webkit.orgcbfbe552012-05-30 18:48:52 +0000139#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
140 FloatRect tileRectAdjusted = adjustSourceRectForDownSampling(tileRect, framePixmap->size());
141#else
142 FloatRect tileRectAdjusted = tileRect;
143#endif
144
benjamin.poulain@nokia.combe697bf2010-11-19 21:15:43 +0000145 // Qt interprets 0 width/height as full width/height so just short circuit.
commit-queue@webkit.org6d767de2010-11-09 08:04:24 +0000146 QRectF dr = QRectF(destRect).normalized();
commit-queue@webkit.orgcbfbe552012-05-30 18:48:52 +0000147 QRect tr = QRectF(tileRectAdjusted).toRect().normalized();
benjamin.poulain@nokia.combe697bf2010-11-19 21:15:43 +0000148 if (!dr.width() || !dr.height() || !tr.width() || !tr.height())
commit-queue@webkit.org6d767de2010-11-09 08:04:24 +0000149 return;
150
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000151 QPixmap pixmap = *framePixmap;
152 if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height())
153 pixmap = pixmap.copy(tr);
hausmann@webkit.org42009bb2009-02-07 15:33:19 +0000154
andreas.kling@nokia.coma43c7092010-12-14 17:49:06 +0000155 CompositeOperator previousOperator = ctxt->compositeOperation();
commit-queue@webkit.org6d767de2010-11-09 08:04:24 +0000156
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000157 ctxt->setCompositeOperation(!pixmap.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op);
commit-queue@webkit.org6d767de2010-11-09 08:04:24 +0000158
andreas.kling@nokia.combbef9f52011-01-22 01:45:14 +0000159 QPainter* p = ctxt->platformContext();
commit-queue@webkit.org6d767de2010-11-09 08:04:24 +0000160 QTransform transform(patternTransform);
noam.rosenthal@nokia.com6cbc9242011-01-17 08:50:11 +0000161
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000162 // If this would draw more than one scaled tile, we scale the pixmap first and then use the result to draw.
noam.rosenthal@nokia.com6cbc9242011-01-17 08:50:11 +0000163 if (transform.type() == QTransform::TxScale) {
164 QRectF tileRectInTargetCoords = (transform * QTransform().translate(phase.x(), phase.y())).mapRect(tr);
165
166 bool tileWillBePaintedOnlyOnce = tileRectInTargetCoords.contains(dr);
167 if (!tileWillBePaintedOnlyOnce) {
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000168 QSizeF scaledSize(float(pixmap.width()) * transform.m11(), float(pixmap.height()) * transform.m22());
169 QPixmap scaledPixmap(scaledSize.toSize());
170 if (pixmap.hasAlpha())
171 scaledPixmap.fill(Qt::transparent);
noam.rosenthal@nokia.com6cbc9242011-01-17 08:50:11 +0000172 {
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000173 QPainter painter(&scaledPixmap);
noam.rosenthal@nokia.com6cbc9242011-01-17 08:50:11 +0000174 painter.setCompositionMode(QPainter::CompositionMode_Source);
175 painter.setRenderHints(p->renderHints());
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000176 painter.drawPixmap(QRect(0, 0, scaledPixmap.width(), scaledPixmap.height()), pixmap);
noam.rosenthal@nokia.com6cbc9242011-01-17 08:50:11 +0000177 }
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000178 pixmap = scaledPixmap;
noam.rosenthal@nokia.com6cbc9242011-01-17 08:50:11 +0000179 transform = QTransform::fromTranslate(transform.dx(), transform.dy());
180 }
181 }
182
183 /* Translate the coordinates as phase is not in world matrix coordinate space but the tile rect origin is. */
commit-queue@webkit.org6d767de2010-11-09 08:04:24 +0000184 transform *= QTransform().translate(phase.x(), phase.y());
185 transform.translate(tr.x(), tr.y());
186
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000187 QBrush b(pixmap);
commit-queue@webkit.org6d767de2010-11-09 08:04:24 +0000188 b.setTransform(transform);
189 p->fillRect(dr, b);
190
andreas.kling@nokia.coma43c7092010-12-14 17:49:06 +0000191 ctxt->setCompositeOperation(previousOperator);
hausmann@webkit.org60de1ee2009-05-20 08:22:23 +0000192
193 if (imageObserver())
194 imageObserver()->didDraw(this);
larsf6076a42007-01-17 19:04:39 +0000195}
196
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000197BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer)
eric@webkit.org1e2dd432009-11-02 18:17:18 +0000198 : Image(observer)
199 , m_currentFrame(0)
200 , m_frames(0)
201 , m_frameTimer(0)
202 , m_repetitionCount(cAnimationNone)
203 , m_repetitionCountStatus(Unknown)
204 , m_repetitionsComplete(0)
commit-queue@webkit.org191451a2011-12-09 01:31:12 +0000205 , m_decodedSize(0)
206 , m_frameCount(1)
eric@webkit.org1e2dd432009-11-02 18:17:18 +0000207 , m_isSolidColor(false)
208 , m_checkedForSolidColor(false)
209 , m_animationFinished(true)
210 , m_allDataReceived(true)
211 , m_haveSize(true)
212 , m_sizeAvailable(true)
eric@webkit.org1e2dd432009-11-02 18:17:18 +0000213 , m_haveFrameCount(true)
eric@webkit.org1e2dd432009-11-02 18:17:18 +0000214{
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000215 int width = pixmap->width();
216 int height = pixmap->height();
eric@webkit.org1e2dd432009-11-02 18:17:18 +0000217 m_decodedSize = width * height * 4;
218 m_size = IntSize(width, height);
219
220 m_frames.grow(1);
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000221 m_frames[0].m_frame = pixmap;
222 m_frames[0].m_hasAlpha = pixmap->hasAlpha();
eric@webkit.org1e2dd432009-11-02 18:17:18 +0000223 m_frames[0].m_haveMetadata = true;
224 checkForSolidColor();
225}
226
larsf6076a42007-01-17 19:04:39 +0000227void BitmapImage::invalidatePlatformData()
228{
229}
kenneth@webkit.orgf86e4e12009-07-21 12:02:38 +0000230
rwlbuis98021982006-08-23 21:04:08 +0000231// Drawing Routines
eseidel61952852006-12-29 01:57:44 +0000232void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
bdakin@apple.com62711a62009-11-19 23:36:58 +0000233 const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
rwlbuis98021982006-08-23 21:04:08 +0000234{
commit-queue@webkit.org580b2cb2010-11-23 08:00:30 +0000235 QRectF normalizedDst = dst.normalized();
236 QRectF normalizedSrc = src.normalized();
commit-queue@webkit.org70777c82010-07-02 18:47:54 +0000237
pkasting@chromium.orge8a5a6b2008-10-15 20:38:13 +0000238 startAnimation();
239
benjamin.poulain@nokia.com194e50b2010-11-19 17:34:14 +0000240 if (normalizedSrc.isEmpty() || normalizedDst.isEmpty())
241 return;
242
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000243 QPixmap* image = nativeImageForCurrentFrame();
larsf6076a42007-01-17 19:04:39 +0000244 if (!image)
rwlbuis98021982006-08-23 21:04:08 +0000245 return;
kenneth@webkit.orgf86e4e12009-07-21 12:02:38 +0000246
larsf6076a42007-01-17 19:04:39 +0000247 if (mayFillWithSolidColor()) {
commit-queue@webkit.org70777c82010-07-02 18:47:54 +0000248 fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op);
rwlbuis98021982006-08-23 21:04:08 +0000249 return;
larsf6076a42007-01-17 19:04:39 +0000250 }
rwlbuis98021982006-08-23 21:04:08 +0000251
commit-queue@webkit.orgcbfbe552012-05-30 18:48:52 +0000252#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
253 normalizedSrc = adjustSourceRectForDownSampling(normalizedSrc, image->size());
254#endif
255
andreas.kling@nokia.combbef9f52011-01-22 01:45:14 +0000256 CompositeOperator previousOperator = ctxt->compositeOperation();
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000257 ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op);
treat@webkit.org66c012f2009-02-27 20:47:04 +0000258
commit-queue@webkit.orgd1e03a72011-07-05 21:29:42 +0000259 if (ctxt->hasShadow()) {
260 ShadowBlur* shadow = ctxt->shadowBlur();
261 GraphicsContext* shadowContext = shadow->beginShadowLayer(ctxt, normalizedDst);
262 if (shadowContext) {
263 QPainter* shadowPainter = shadowContext->platformContext();
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000264 shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc);
commit-queue@webkit.org6a1fb1a2011-01-04 00:21:05 +0000265 shadow->endShadowLayer(ctxt);
commit-queue@webkit.org580b2cb2010-11-23 08:00:30 +0000266 }
eric@webkit.orgfabc5502010-06-02 08:30:39 +0000267 }
268
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000269 ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc);
rwlbuis98021982006-08-23 21:04:08 +0000270
andreas.kling@nokia.combbef9f52011-01-22 01:45:14 +0000271 ctxt->setCompositeOperation(previousOperator);
hausmann@webkit.org60de1ee2009-05-20 08:22:23 +0000272
273 if (imageObserver())
274 imageObserver()->didDraw(this);
rwlbuis98021982006-08-23 21:04:08 +0000275}
276
eseidel61952852006-12-29 01:57:44 +0000277void BitmapImage::checkForSolidColor()
rwlbuis98021982006-08-23 21:04:08 +0000278{
rwlbuis98021982006-08-23 21:04:08 +0000279 m_isSolidColor = false;
treat@webkit.orgf793b272009-03-02 15:37:02 +0000280 m_checkedForSolidColor = true;
281
282 if (frameCount() > 1)
283 return;
284
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000285 QPixmap* framePixmap = frameAtIndex(0);
286 if (!framePixmap || framePixmap->width() != 1 || framePixmap->height() != 1)
treat@webkit.orgf793b272009-03-02 15:37:02 +0000287 return;
288
289 m_isSolidColor = true;
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000290 m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0));
rwlbuis98021982006-08-23 21:04:08 +0000291}
292
mjs@apple.comacbcc282010-01-05 08:58:28 +0000293#if OS(WINDOWS)
eric@webkit.org1e2dd432009-11-02 18:17:18 +0000294PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
295{
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000296 QPixmap* qPixmap = new QPixmap(qt_pixmapFromWinHBITMAP(hBitmap));
kbalazs@webkit.org4b6f8552012-06-10 12:09:37 +0000297
zoltan@webkit.orgb4e6b152012-10-08 13:44:14 +0000298 return BitmapImage::create(qPixmap);
eric@webkit.org1e2dd432009-11-02 18:17:18 +0000299}
300#endif
301
rwlbuis98021982006-08-23 21:04:08 +0000302}
303
eseidel61952852006-12-29 01:57:44 +0000304
rwlbuis98021982006-08-23 21:04:08 +0000305// vim: ts=4 sw=4 et