1 /* 2 * Copyright (C) 2006 Dirk Mueller <mueller (at) kde.org> 3 * Copyright (C) 2006 Zack Rusin <zack (at) kde.org> 4 * Copyright (C) 2006 Simon Hausmann <hausmann (at) 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 272