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