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 #include "SharedBuffer.h"
45
46 #include <QPixmap>
47 #include <QPainter>
48 #include <QImage>
49 #include <QImageReader>
50 #include <QTransform>
51
52 #include <QDebug>
53
54 #include <math.h>
55
56 // This function loads resources into WebKit
loadResourcePixmap(const char * name)57 static QPixmap loadResourcePixmap(const char *name)
58 {
59 QPixmap pixmap;
60 if (qstrcmp(name, "missingImage") == 0)
61 pixmap = QWebSettings::webGraphic(QWebSettings::MissingImageGraphic);
62 else if (qstrcmp(name, "nullPlugin") == 0)
63 pixmap = QWebSettings::webGraphic(QWebSettings::MissingPluginGraphic);
64 else if (qstrcmp(name, "urlIcon") == 0)
65 pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic);
66 else if (qstrcmp(name, "textAreaResizeCorner") == 0)
67 pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic);
68 else if (qstrcmp(name, "deleteButton") == 0)
69 pixmap = QWebSettings::webGraphic(QWebSettings::DeleteButtonGraphic);
70 else if (!qstrcmp(name, "inputSpeech"))
71 pixmap = QWebSettings::webGraphic(QWebSettings::InputSpeechButtonGraphic);
72 else if (!qstrcmp(name, "searchCancelButton"))
73 pixmap = QWebSettings::webGraphic(QWebSettings::SearchCancelButtonGraphic);
74 else if (!qstrcmp(name, "searchCancelButtonPressed"))
75 pixmap = QWebSettings::webGraphic(QWebSettings::SearchCancelButtonPressedGraphic);
76
77 return pixmap;
78 }
79
80 namespace WebCore {
81
clear(bool clearMetadata)82 bool FrameData::clear(bool clearMetadata)
83 {
84 if (clearMetadata)
85 m_haveMetadata = false;
86
87 if (m_frame) {
88 delete m_frame;
89 m_frame = 0;
90 return true;
91 }
92 return false;
93 }
94
95
96 // ================================================
97 // Image Class
98 // ================================================
99
loadPlatformResource(const char * name)100 PassRefPtr<Image> Image::loadPlatformResource(const char* name)
101 {
102 return StillImage::create(loadResourcePixmap(name));
103 }
104
drawPattern(GraphicsContext * ctxt,const FloatRect & tileRect,const AffineTransform & patternTransform,const FloatPoint & phase,ColorSpace,CompositeOperator op,const FloatRect & destRect)105 void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
106 const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect)
107 {
108 QPixmap* framePixmap = nativeImageForCurrentFrame();
109 if (!framePixmap) // If it's too early we won't have an image yet.
110 return;
111
112 // Qt interprets 0 width/height as full width/height so just short circuit.
113 QRectF dr = QRectF(destRect).normalized();
114 QRect tr = QRectF(tileRect).toRect().normalized();
115 if (!dr.width() || !dr.height() || !tr.width() || !tr.height())
116 return;
117
118 QPixmap pixmap = *framePixmap;
119 if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height())
120 pixmap = pixmap.copy(tr);
121
122 CompositeOperator previousOperator = ctxt->compositeOperation();
123
124 ctxt->setCompositeOperation(!pixmap.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op);
125
126 QPainter* p = ctxt->platformContext();
127 QTransform transform(patternTransform);
128
129 // If this would draw more than one scaled tile, we scale the pixmap first and then use the result to draw.
130 if (transform.type() == QTransform::TxScale) {
131 QRectF tileRectInTargetCoords = (transform * QTransform().translate(phase.x(), phase.y())).mapRect(tr);
132
133 bool tileWillBePaintedOnlyOnce = tileRectInTargetCoords.contains(dr);
134 if (!tileWillBePaintedOnlyOnce) {
135 QSizeF scaledSize(float(pixmap.width()) * transform.m11(), float(pixmap.height()) * transform.m22());
136 QPixmap scaledPixmap(scaledSize.toSize());
137 if (pixmap.hasAlpha())
138 scaledPixmap.fill(Qt::transparent);
139 {
140 QPainter painter(&scaledPixmap);
141 painter.setCompositionMode(QPainter::CompositionMode_Source);
142 painter.setRenderHints(p->renderHints());
143 painter.drawPixmap(QRect(0, 0, scaledPixmap.width(), scaledPixmap.height()), pixmap);
144 }
145 pixmap = scaledPixmap;
146 transform = QTransform::fromTranslate(transform.dx(), transform.dy());
147 }
148 }
149
150 /* Translate the coordinates as phase is not in world matrix coordinate space but the tile rect origin is. */
151 transform *= QTransform().translate(phase.x(), phase.y());
152 transform.translate(tr.x(), tr.y());
153
154 QBrush b(pixmap);
155 b.setTransform(transform);
156 p->fillRect(dr, b);
157
158 ctxt->setCompositeOperation(previousOperator);
159
160 if (imageObserver())
161 imageObserver()->didDraw(this);
162 }
163
BitmapImage(QPixmap * pixmap,ImageObserver * observer)164 BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer)
165 : Image(observer)
166 , m_currentFrame(0)
167 , m_frames(0)
168 , m_frameTimer(0)
169 , m_repetitionCount(cAnimationNone)
170 , m_repetitionCountStatus(Unknown)
171 , m_repetitionsComplete(0)
172 , m_isSolidColor(false)
173 , m_checkedForSolidColor(false)
174 , m_animationFinished(true)
175 , m_allDataReceived(true)
176 , m_haveSize(true)
177 , m_sizeAvailable(true)
178 , m_decodedSize(0)
179 , m_haveFrameCount(true)
180 , m_frameCount(1)
181 {
182 initPlatformData();
183
184 int width = pixmap->width();
185 int height = pixmap->height();
186 m_decodedSize = width * height * 4;
187 m_size = IntSize(width, height);
188
189 m_frames.grow(1);
190 m_frames[0].m_frame = pixmap;
191 m_frames[0].m_hasAlpha = pixmap->hasAlpha();
192 m_frames[0].m_haveMetadata = true;
193 checkForSolidColor();
194 }
195
initPlatformData()196 void BitmapImage::initPlatformData()
197 {
198 }
199
invalidatePlatformData()200 void BitmapImage::invalidatePlatformData()
201 {
202 }
203
204 // Drawing Routines
draw(GraphicsContext * ctxt,const FloatRect & dst,const FloatRect & src,ColorSpace styleColorSpace,CompositeOperator op)205 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
206 const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
207 {
208 QRectF normalizedDst = dst.normalized();
209 QRectF normalizedSrc = src.normalized();
210
211 startAnimation();
212
213 if (normalizedSrc.isEmpty() || normalizedDst.isEmpty())
214 return;
215
216 QPixmap* image = nativeImageForCurrentFrame();
217 if (!image)
218 return;
219
220 if (mayFillWithSolidColor()) {
221 fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op);
222 return;
223 }
224
225 CompositeOperator previousOperator = ctxt->compositeOperation();
226 ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op);
227
228 ContextShadow* shadow = ctxt->contextShadow();
229 if (shadow->m_type != ContextShadow::NoShadow) {
230 QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst);
231 if (shadowPainter) {
232 shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
233 shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc);
234 shadow->endShadowLayer(ctxt);
235 }
236 }
237
238 QByteArray a = QByteArray::fromRawData(data()->data(), data()->size());
239 ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc, &a);
240
241 ctxt->setCompositeOperation(previousOperator);
242
243 if (imageObserver())
244 imageObserver()->didDraw(this);
245 }
246
checkForSolidColor()247 void BitmapImage::checkForSolidColor()
248 {
249 m_isSolidColor = false;
250 m_checkedForSolidColor = true;
251
252 if (frameCount() > 1)
253 return;
254
255 QPixmap* framePixmap = frameAtIndex(0);
256 if (!framePixmap || framePixmap->width() != 1 || framePixmap->height() != 1)
257 return;
258
259 m_isSolidColor = true;
260 m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0));
261 }
262
263 #if OS(WINDOWS)
create(HBITMAP hBitmap)264 PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
265 {
266 return BitmapImage::create(new QPixmap(QPixmap::fromWinHBITMAP(hBitmap)));
267 }
268 #endif
269
270 }
271
272
273 // vim: ts=4 sw=4 et
274