Home | History | Annotate | Download | only in qt
      1 /*
      2  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
      3  *
      4  *  This library is free software; you can redistribute it and/or
      5  *  modify it under the terms of the GNU Lesser General Public
      6  *  License as published by the Free Software Foundation; either
      7  *  version 2 of the License, or (at your option) any later version.
      8  *
      9  *  This library is distributed in the hope that it will be useful,
     10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *  Lesser General Public License for more details.
     13  *
     14  *  You should have received a copy of the GNU Lesser General Public
     15  *  License along with this library; if not, write to the Free Software
     16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     17  *
     18  */
     19 #include "config.h"
     20 #include "qt_pixmapruntime.h"
     21 
     22 #include "CachedImage.h"
     23 #include "DOMWindow.h"
     24 #include "HTMLImageElement.h"
     25 #include "HTMLNames.h"
     26 #include "JSDOMBinding.h"
     27 #include "JSDOMWindow.h"
     28 #include "JSGlobalObject.h"
     29 #include "JSHTMLImageElement.h"
     30 #include "JSLock.h"
     31 #include "ObjectPrototype.h"
     32 #include "StillImageQt.h"
     33 #include <QBuffer>
     34 #include <QByteArray>
     35 #include <QImage>
     36 #include <QPixmap>
     37 #include <QVariant>
     38 #include <runtime_object.h>
     39 #include <runtime_root.h>
     40 
     41 using namespace WebCore;
     42 namespace JSC {
     43 
     44 namespace Bindings {
     45 
     46 class QtPixmapClass : public Class {
     47 public:
     48     QtPixmapClass();
     49     virtual MethodList methodsNamed(const Identifier&, Instance*) const;
     50     virtual Field* fieldNamed(const Identifier&, Instance*) const;
     51 };
     52 
     53 
     54 class QtPixmapWidthField : public Field {
     55 public:
     56     static const char* name() { return "width"; }
     57     virtual JSValue valueFromInstance(ExecState* exec, const Instance* pixmap) const
     58     {
     59         return jsNumber(exec, static_cast<const QtPixmapInstance*>(pixmap)->width());
     60     }
     61     virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
     62 };
     63 class QtPixmapHeightField : public Field {
     64 public:
     65     static const char* name() { return "height"; }
     66     virtual JSValue valueFromInstance(ExecState* exec, const Instance* inst) const
     67     {
     68         return jsNumber(exec, static_cast<const QtPixmapInstance*>(inst)->height());
     69     }
     70     virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
     71 };
     72 
     73 class QtPixmapRuntimeMethod : public Method {
     74 public:
     75     virtual int numParameters() const
     76     {
     77         return 0;
     78     }
     79     virtual JSValue invoke(ExecState* exec, QVariant&, PassRefPtr<RootObject> root, QtPixmapInstance* inst) = 0;
     80 
     81 };
     82 
     83 class QtPixmapCreateElementMethod : public QtPixmapRuntimeMethod {
     84 public:
     85     static const char* name() { return "toHTMLImageElement"; }
     86     JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr<RootObject> root, QtPixmapInstance*)
     87     {
     88         QPixmap pxm;
     89         if (v.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) {
     90             pxm = QPixmap::fromImage(v.value<QImage>());
     91             v = QVariant::fromValue<QPixmap>(pxm);
     92         } else
     93             pxm = v.value<QPixmap>();
     94 
     95         Document* document = 0;
     96         JSDOMGlobalObject* global = static_cast<JSDOMGlobalObject*>(root->globalObject());
     97         if (global) {
     98             DOMWindow* dWindow = toDOMWindow(global);
     99             if (dWindow)
    100                 document = dWindow->document();
    101         }
    102 
    103         if (document) {
    104             PassRefPtr<StillImage> img = WebCore::StillImage::create(pxm);
    105             RefPtr<HTMLImageElement> image = new HTMLImageElement(HTMLNames::imgTag, document);
    106             image->setCachedImage(new CachedImage(img.get()));
    107             toJS(exec, global, document);
    108             return asObject(toJS(exec, global, image.release()));
    109         }
    110         return jsUndefined();
    111     }
    112 
    113 };
    114 
    115 class QtPixmapToDataUrlMethod : public QtPixmapRuntimeMethod {
    116 public:
    117     static const char* name() { return "toDataUrl"; }
    118     JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr<RootObject> root, QtPixmapInstance*)
    119     {
    120         QImage image;
    121         // for getting the data url, we always prefer the image.
    122         if (v.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) {
    123             image = v.value<QPixmap>().toImage();
    124             v = QVariant::fromValue<QImage>(image);
    125         } else
    126             image = v.value<QImage>();
    127         QByteArray ba;
    128         QBuffer b(&ba);
    129         image.save(&b, "PNG");
    130         const QString b64 = QString("data:image/png;base64,") + ba.toBase64();
    131         const UString ustring((UChar*)b64.utf16(), b64.length());
    132         return jsString(exec, ustring);
    133     }
    134 
    135 };
    136 
    137 class QtPixmapToStringMethod : public QtPixmapRuntimeMethod {
    138     public:
    139     static const char* name() { return "toString"; }
    140     JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr<RootObject> root, QtPixmapInstance* inst)
    141     {
    142         return inst->valueOf(exec);
    143     }
    144 
    145 };
    146 
    147 struct QtPixmapMetaData {
    148     QtPixmapToDataUrlMethod toDataUrlMethod;
    149     QtPixmapCreateElementMethod createElementMethod;
    150     QtPixmapToStringMethod toStringMethod;
    151     QtPixmapHeightField heightField;
    152     QtPixmapWidthField widthField;
    153     QtPixmapClass cls;
    154 } qt_pixmap_metaData;
    155 
    156 // Derived RuntimeObject
    157 class QtPixmapRuntimeObjectImp : public RuntimeObjectImp {
    158 public:
    159     QtPixmapRuntimeObjectImp(ExecState*, PassRefPtr<Instance>);
    160 
    161     static const ClassInfo s_info;
    162 
    163     static PassRefPtr<Structure> createStructure(JSValue prototype)
    164     {
    165         return Structure::create(prototype, TypeInfo(ObjectType,  StructureFlags), AnonymousSlotCount);
    166     }
    167 
    168 protected:
    169     static const unsigned StructureFlags = RuntimeObjectImp::StructureFlags | OverridesMarkChildren;
    170 
    171 private:
    172     virtual const ClassInfo* classInfo() const { return &s_info; }
    173 };
    174 
    175 QtPixmapRuntimeObjectImp::QtPixmapRuntimeObjectImp(ExecState* exec, PassRefPtr<Instance> instance)
    176     : RuntimeObjectImp(exec, WebCore::deprecatedGetDOMStructure<QtPixmapRuntimeObjectImp>(exec), instance)
    177 {
    178 }
    179 
    180 const ClassInfo QtPixmapRuntimeObjectImp::s_info = { "QtPixmapRuntimeObject", &RuntimeObjectImp::s_info, 0, 0 };
    181 
    182 
    183 QtPixmapClass::QtPixmapClass()
    184 {
    185 }
    186 
    187 
    188 Class* QtPixmapInstance::getClass() const
    189 {
    190     return &qt_pixmap_metaData.cls;
    191 }
    192 
    193 JSValue QtPixmapInstance::invokeMethod(ExecState* exec, const MethodList& methods, const ArgList& args)
    194 {
    195     if (methods.size() == 1) {
    196         QtPixmapRuntimeMethod* mtd = static_cast<QtPixmapRuntimeMethod*>(methods[0]);
    197         return mtd->invoke(exec, data, rootObject(), this);
    198     }
    199     return jsUndefined();
    200 }
    201 
    202 MethodList QtPixmapClass::methodsNamed(const Identifier& identifier, Instance*) const
    203 {
    204     MethodList methods;
    205     if (identifier == QtPixmapToDataUrlMethod::name())
    206         methods.append(&qt_pixmap_metaData.toDataUrlMethod);
    207     else if (identifier == QtPixmapCreateElementMethod::name())
    208         methods.append(&qt_pixmap_metaData.createElementMethod);
    209     else if (identifier == QtPixmapToStringMethod::name())
    210         methods.append(&qt_pixmap_metaData.toStringMethod);
    211     return methods;
    212 }
    213 
    214 Field* QtPixmapClass::fieldNamed(const Identifier& identifier, Instance*) const
    215 {
    216     if (identifier == QtPixmapWidthField::name())
    217         return &qt_pixmap_metaData.widthField;
    218     if (identifier == QtPixmapHeightField::name())
    219         return &qt_pixmap_metaData.heightField;
    220     return 0;
    221 }
    222 
    223 void QtPixmapInstance::getPropertyNames(ExecState*exec, PropertyNameArray& arr)
    224 {
    225     arr.add(Identifier(exec, UString(QtPixmapToDataUrlMethod::name())));
    226     arr.add(Identifier(exec, UString(QtPixmapCreateElementMethod::name())));
    227     arr.add(Identifier(exec, UString(QtPixmapToStringMethod::name())));
    228     arr.add(Identifier(exec, UString(QtPixmapWidthField::name())));
    229     arr.add(Identifier(exec, UString(QtPixmapHeightField::name())));
    230 }
    231 
    232 JSValue QtPixmapInstance::defaultValue(ExecState* exec, PreferredPrimitiveType ptype) const
    233 {
    234     if (ptype == PreferNumber) {
    235         return jsBoolean(
    236                 (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()) && !(data.value<QImage>()).isNull())
    237                 || (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()) && !data.value<QPixmap>().isNull()));
    238     }
    239     if (ptype == PreferString)
    240         return valueOf(exec);
    241     return jsUndefined();
    242 }
    243 
    244 JSValue QtPixmapInstance::valueOf(ExecState* exec) const
    245 {
    246     const QString toStr = QString("[Qt Native Pixmap %1,%2]").arg(width()).arg(height());
    247     UString ustring((UChar*)toStr.utf16(), toStr.length());
    248     return jsString(exec, ustring);
    249 }
    250 
    251 QtPixmapInstance::QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& d)
    252         :Instance(rootObj), data(d)
    253 {
    254 }
    255 
    256 int QtPixmapInstance::width() const
    257 {
    258     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
    259         return data.value<QPixmap>().width();
    260     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
    261         return data.value<QImage>().width();
    262     return 0;
    263 }
    264 
    265 int QtPixmapInstance::height() const
    266 {
    267     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
    268         return data.value<QPixmap>().height();
    269     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
    270         return data.value<QImage>().height();
    271     return 0;
    272 }
    273 
    274 QPixmap QtPixmapInstance::toPixmap()
    275 {
    276     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
    277         return data.value<QPixmap>();
    278     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) {
    279         const QPixmap pxm = QPixmap::fromImage(data.value<QImage>());
    280         data = QVariant::fromValue<QPixmap>(pxm);
    281         return pxm;
    282     }
    283     return QPixmap();
    284 
    285 }
    286 
    287 QImage QtPixmapInstance::toImage()
    288 {
    289     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
    290         return data.value<QImage>();
    291     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) {
    292         const QImage img = data.value<QPixmap>().toImage();
    293         data = QVariant::fromValue<QImage>(img);
    294         return img;
    295     }
    296     return QImage();
    297 }
    298 
    299 QVariant QtPixmapInstance::variantFromObject(JSObject* object, QMetaType::Type hint)
    300 {
    301     if (!object) {
    302         if (hint == qMetaTypeId<QPixmap>())
    303             return QVariant::fromValue<QPixmap>(QPixmap());
    304         if (hint == qMetaTypeId<QImage>())
    305             return QVariant::fromValue<QImage>(QImage());
    306     } else if (object->inherits(&JSHTMLImageElement::s_info)) {
    307         JSHTMLImageElement* el = static_cast<JSHTMLImageElement*>(object);
    308         HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(el->impl());
    309         if (imageElement) {
    310             CachedImage* cImg = imageElement->cachedImage();
    311             if (cImg) {
    312                 Image* img = cImg->image();
    313                 if (img) {
    314                     QPixmap* pxm = img->nativeImageForCurrentFrame();
    315                     if (pxm) {
    316                         return (hint == static_cast<QMetaType::Type>(qMetaTypeId<QPixmap>()))
    317                               ? QVariant::fromValue<QPixmap>(*pxm)
    318                               : QVariant::fromValue<QImage>(pxm->toImage());
    319                     }
    320                 }
    321             }
    322         }
    323     } else if (object->inherits(&QtPixmapRuntimeObjectImp::s_info)) {
    324         QtPixmapRuntimeObjectImp* imp = static_cast<QtPixmapRuntimeObjectImp*>(object);
    325         QtPixmapInstance* inst = static_cast<QtPixmapInstance*>(imp->getInternalInstance());
    326         if (inst) {
    327             if (hint == qMetaTypeId<QPixmap >())
    328                 return QVariant::fromValue<QPixmap>(inst->toPixmap());
    329             if (hint == qMetaTypeId<QImage>())
    330                 return QVariant::fromValue<QImage>(inst->toImage());
    331         }
    332     }
    333     return 0;
    334 }
    335 JSObject* QtPixmapInstance::createRuntimeObject(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& data)
    336 {
    337     JSLock lock(SilenceAssertionsOnly);
    338     return new(exec) QtPixmapRuntimeObjectImp(exec, new QtPixmapInstance(root, data));
    339 }
    340 
    341 bool QtPixmapInstance::canHandle(QMetaType::Type hint)
    342 {
    343     return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>();
    344 }
    345 
    346 }
    347 
    348 }
    349