0c8ce9ed7b5e8e9ab937eff98c5dcfce519fe01c
[WebKit-https.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 "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
56 static 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
79 namespace WebCore {
80
81 bool 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
99 PassRefPtr<Image> Image::loadPlatformResource(const char* name)
100 {
101     return StillImage::create(loadResourcePixmap(name));
102 }
103
104 void 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
163 BitmapImage::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
195 void BitmapImage::initPlatformData()
196 {
197 }
198
199 void BitmapImage::invalidatePlatformData()
200 {
201 }
202
203 // Drawing Routines
204 void 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
245 void 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)
262 PassRefPtr<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