Home | History | Annotate | Download | only in qt
      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