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
loadResourcePixmap(const char * name)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
clear(bool clearMetadata)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
loadPlatformResource(const char * name)99 PassRefPtr<Image> Image::loadPlatformResource(const char* name)
100 {
101 return StillImage::create(loadResourcePixmap(name));
102 }
103
drawPattern(GraphicsContext * ctxt,const FloatRect & tileRect,const AffineTransform & patternTransform,const FloatPoint & phase,ColorSpace,CompositeOperator op,const FloatRect & destRect)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
BitmapImage(QPixmap * pixmap,ImageObserver * observer)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
initPlatformData()195 void BitmapImage::initPlatformData()
196 {
197 }
198
invalidatePlatformData()199 void BitmapImage::invalidatePlatformData()
200 {
201 }
202
203 // Drawing Routines
draw(GraphicsContext * ctxt,const FloatRect & dst,const FloatRect & src,ColorSpace styleColorSpace,CompositeOperator op)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
checkForSolidColor()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)
create(HBITMAP hBitmap)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
272