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