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 "HTMLImageElement.h"
     24 #include "JSGlobalObject.h"
     25 #include "JSHTMLImageElement.h"
     26 #include "JSLock.h"
     27 #include "ObjectPrototype.h"
     28 #include "StillImageQt.h"
     29 #include <QBuffer>
     30 #include <QByteArray>
     31 #include <QImage>
     32 #include <QPixmap>
     33 #include <QVariant>
     34 #include <runtime_method.h>
     35 #include <runtime_object.h>
     36 #include <runtime_root.h>
     37 #include "runtime/FunctionPrototype.h"
     38 
     39 using namespace WebCore;
     40 namespace JSC {
     41 
     42 namespace Bindings {
     43 
     44 class QtPixmapClass : public Class {
     45 public:
     46     QtPixmapClass();
     47     virtual MethodList methodsNamed(const Identifier&, Instance*) const;
     48     virtual Field* fieldNamed(const Identifier&, Instance*) const;
     49 };
     50 
     51 
     52 class QtPixmapWidthField : public Field {
     53 public:
     54     static const char* name() { return "width"; }
     55     virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const
     56     {
     57         return jsNumber(static_cast<const QtPixmapInstance*>(instance)->width());
     58     }
     59     virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
     60 };
     61 
     62 class QtPixmapHeightField : public Field {
     63 public:
     64     static const char* name() { return "height"; }
     65     virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const
     66     {
     67         return jsNumber(static_cast<const QtPixmapInstance*>(instance)->height());
     68     }
     69     virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
     70 };
     71 
     72 class QtPixmapRuntimeMethod : public Method {
     73 public:
     74     virtual int numParameters() const
     75     {
     76         return 0;
     77     }
     78     virtual JSValue invoke(ExecState* exec, QtPixmapInstance*) = 0;
     79 
     80 };
     81 
     82 // this function receives an HTML image element as a parameter, makes it display the pixmap/image from Qt
     83 class QtPixmapAssignToElementMethod : public QtPixmapRuntimeMethod {
     84 public:
     85     static const char* name() { return "assignToHTMLImageElement"; }
     86     JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
     87     {
     88         if (!exec->argumentCount())
     89             return jsUndefined();
     90 
     91         JSObject* objectArg = exec->argument(0).toObject(exec);
     92         if (!objectArg)
     93             return jsUndefined();
     94 
     95         if (!objectArg->inherits(&JSHTMLImageElement::s_info))
     96             return jsUndefined();
     97 
     98         // we now know that we have a valid <img> element as the argument, we can attach the pixmap to it.
     99         PassRefPtr<StillImage> stillImage = WebCore::StillImage::create(instance->toPixmap());
    100         HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(static_cast<JSHTMLImageElement*>(objectArg)->impl());
    101         imageElement->setCachedImage(new CachedImage(stillImage.get()));
    102         JSDOMGlobalObject* global = static_cast<JSDOMGlobalObject*>(instance->rootObject()->globalObject());
    103         toJS(exec, global, imageElement->document());
    104         return jsUndefined();
    105     }
    106 
    107     virtual int numParameters() const
    108     {
    109         return 1;
    110     }
    111 };
    112 
    113 // this function encodes the image to a dataUrl, to be used in background etc. Note: very slow.
    114 class QtPixmapToDataUrlMethod : public QtPixmapRuntimeMethod {
    115 public:
    116     static const char* name() { return "toDataUrl"; }
    117     JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
    118     {
    119         QByteArray byteArray;
    120         QBuffer buffer(&byteArray);
    121         instance->toImage().save(&buffer, "PNG");
    122         const QString encodedString = QLatin1String("data:image/png;base64,") + QLatin1String(byteArray.toBase64());
    123         const UString ustring((UChar*)encodedString.utf16(), encodedString.length());
    124         return jsString(exec, ustring);
    125     }
    126 };
    127 
    128 class QtPixmapToStringMethod : public QtPixmapRuntimeMethod {
    129     public:
    130     static const char* name() { return "toString"; }
    131     JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
    132     {
    133         return instance->valueOf(exec);
    134     }
    135 };
    136 
    137 struct QtPixmapMetaData {
    138     QtPixmapToDataUrlMethod toDataUrlMethod;
    139     QtPixmapAssignToElementMethod assignToElementMethod;
    140     QtPixmapToStringMethod toStringMethod;
    141     QtPixmapHeightField heightField;
    142     QtPixmapWidthField widthField;
    143     QtPixmapClass cls;
    144 } qt_pixmap_metaData;
    145 
    146 // Derived RuntimeObject
    147 class QtPixmapRuntimeObject : public RuntimeObject {
    148 public:
    149     QtPixmapRuntimeObject(ExecState*, JSGlobalObject*, PassRefPtr<Instance>);
    150 
    151     static const ClassInfo s_info;
    152 
    153     static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
    154     {
    155         return Structure::create(globalData, prototype, TypeInfo(ObjectType,  StructureFlags), AnonymousSlotCount, &s_info);
    156     }
    157 
    158 protected:
    159     static const unsigned StructureFlags = RuntimeObject::StructureFlags | OverridesMarkChildren;
    160 };
    161 
    162 QtPixmapRuntimeObject::QtPixmapRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr<Instance> instance)
    163     : RuntimeObject(exec, globalObject, WebCore::deprecatedGetDOMStructure<QtPixmapRuntimeObject>(exec), instance)
    164 {
    165 }
    166 
    167 const ClassInfo QtPixmapRuntimeObject::s_info = { "QtPixmapRuntimeObject", &RuntimeObject::s_info, 0, 0 };
    168 
    169 QtPixmapClass::QtPixmapClass()
    170 {
    171 }
    172 
    173 
    174 Class* QtPixmapInstance::getClass() const
    175 {
    176     return &qt_pixmap_metaData.cls;
    177 }
    178 
    179 JSValue QtPixmapInstance::getMethod(ExecState* exec, const Identifier& propertyName)
    180 {
    181     MethodList methodList = getClass()->methodsNamed(propertyName, this);
    182     return new (exec) RuntimeMethod(exec, exec->lexicalGlobalObject(), WebCore::deprecatedGetDOMStructure<RuntimeMethod>(exec), propertyName, methodList);
    183 }
    184 
    185 JSValue QtPixmapInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod)
    186 {
    187     const MethodList& methods = *runtimeMethod->methods();
    188 
    189     if (methods.size() == 1) {
    190         QtPixmapRuntimeMethod* method = static_cast<QtPixmapRuntimeMethod*>(methods[0]);
    191         return method->invoke(exec, this);
    192     }
    193     return jsUndefined();
    194 }
    195 
    196 MethodList QtPixmapClass::methodsNamed(const Identifier& identifier, Instance*) const
    197 {
    198     MethodList methods;
    199     if (identifier == QtPixmapToDataUrlMethod::name())
    200         methods.append(&qt_pixmap_metaData.toDataUrlMethod);
    201     else if (identifier == QtPixmapAssignToElementMethod::name())
    202         methods.append(&qt_pixmap_metaData.assignToElementMethod);
    203     else if (identifier == QtPixmapToStringMethod::name())
    204         methods.append(&qt_pixmap_metaData.toStringMethod);
    205     return methods;
    206 }
    207 
    208 Field* QtPixmapClass::fieldNamed(const Identifier& identifier, Instance*) const
    209 {
    210     if (identifier == QtPixmapWidthField::name())
    211         return &qt_pixmap_metaData.widthField;
    212     if (identifier == QtPixmapHeightField::name())
    213         return &qt_pixmap_metaData.heightField;
    214     return 0;
    215 }
    216 
    217 void QtPixmapInstance::getPropertyNames(ExecState*exec, PropertyNameArray& arr)
    218 {
    219     arr.add(Identifier(exec, UString(QtPixmapToDataUrlMethod::name())));
    220     arr.add(Identifier(exec, UString(QtPixmapAssignToElementMethod::name())));
    221     arr.add(Identifier(exec, UString(QtPixmapToStringMethod::name())));
    222     arr.add(Identifier(exec, UString(QtPixmapWidthField::name())));
    223     arr.add(Identifier(exec, UString(QtPixmapHeightField::name())));
    224 }
    225 
    226 JSValue QtPixmapInstance::defaultValue(ExecState* exec, PreferredPrimitiveType ptype) const
    227 {
    228     if (ptype == PreferNumber) {
    229         return jsBoolean(
    230                 (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()) && !(data.value<QImage>()).isNull())
    231                 || (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()) && !data.value<QPixmap>().isNull()));
    232     }
    233 
    234     if (ptype == PreferString)
    235         return valueOf(exec);
    236 
    237     return jsUndefined();
    238 }
    239 
    240 JSValue QtPixmapInstance::valueOf(ExecState* exec) const
    241 {
    242     const QString stringValue = QString::fromLatin1("[Qt Native Pixmap %1,%2]").arg(width()).arg(height());
    243     UString ustring((UChar*)stringValue.utf16(), stringValue.length());
    244     return jsString(exec, ustring);
    245 }
    246 
    247 QtPixmapInstance::QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& d)
    248         :Instance(rootObj), data(d)
    249 {
    250 }
    251 
    252 int QtPixmapInstance::width() const
    253 {
    254     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
    255         return data.value<QPixmap>().width();
    256     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
    257         return data.value<QImage>().width();
    258     return 0;
    259 }
    260 
    261 int QtPixmapInstance::height() const
    262 {
    263     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
    264         return data.value<QPixmap>().height();
    265     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
    266         return data.value<QImage>().height();
    267     return 0;
    268 }
    269 
    270 QPixmap QtPixmapInstance::toPixmap()
    271 {
    272     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
    273         return data.value<QPixmap>();
    274 
    275     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) {
    276         const QPixmap pixmap = QPixmap::fromImage(data.value<QImage>());
    277         data = QVariant::fromValue<QPixmap>(pixmap);
    278         return pixmap;
    279     }
    280 
    281     return QPixmap();
    282 }
    283 
    284 QImage QtPixmapInstance::toImage()
    285 {
    286     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
    287         return data.value<QImage>();
    288 
    289     if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) {
    290         const QImage image = data.value<QPixmap>().toImage();
    291         data = QVariant::fromValue<QImage>(image);
    292         return image;
    293     }
    294 
    295     return QImage();
    296 }
    297 
    298 QVariant QtPixmapInstance::variantFromObject(JSObject* object, QMetaType::Type hint)
    299 {
    300     if (!object)
    301         goto returnEmptyVariant;
    302 
    303     if (object->inherits(&JSHTMLImageElement::s_info)) {
    304         JSHTMLImageElement* elementJSWrapper = static_cast<JSHTMLImageElement*>(object);
    305         HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(elementJSWrapper->impl());
    306 
    307         if (!imageElement)
    308             goto returnEmptyVariant;
    309 
    310         CachedImage* cachedImage = imageElement->cachedImage();
    311         if (!cachedImage)
    312             goto returnEmptyVariant;
    313 
    314         Image* image = cachedImage->image();
    315         if (!image)
    316             goto returnEmptyVariant;
    317 
    318         QPixmap* pixmap = image->nativeImageForCurrentFrame();
    319         if (!pixmap)
    320             goto returnEmptyVariant;
    321 
    322         return (hint == static_cast<QMetaType::Type>(qMetaTypeId<QPixmap>()))
    323                   ? QVariant::fromValue<QPixmap>(*pixmap)
    324                   : QVariant::fromValue<QImage>(pixmap->toImage());
    325     }
    326 
    327     if (object->inherits(&QtPixmapRuntimeObject::s_info)) {
    328         QtPixmapRuntimeObject* runtimeObject = static_cast<QtPixmapRuntimeObject*>(object);
    329         QtPixmapInstance* instance = static_cast<QtPixmapInstance*>(runtimeObject->getInternalInstance());
    330         if (!instance)
    331             goto returnEmptyVariant;
    332 
    333         if (hint == qMetaTypeId<QPixmap>())
    334             return QVariant::fromValue<QPixmap>(instance->toPixmap());
    335 
    336         if (hint == qMetaTypeId<QImage>())
    337             return QVariant::fromValue<QImage>(instance->toImage());
    338     }
    339 
    340 returnEmptyVariant:
    341     if (hint == qMetaTypeId<QPixmap>())
    342         return QVariant::fromValue<QPixmap>(QPixmap());
    343     if (hint == qMetaTypeId<QImage>())
    344         return QVariant::fromValue<QImage>(QImage());
    345     return QVariant();
    346 }
    347 
    348 RuntimeObject* QtPixmapInstance::newRuntimeObject(ExecState* exec)
    349 {
    350     return new(exec) QtPixmapRuntimeObject(exec, exec->lexicalGlobalObject(), this);
    351 }
    352 
    353 JSObject* QtPixmapInstance::createPixmapRuntimeObject(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& data)
    354 {
    355     JSLock lock(SilenceAssertionsOnly);
    356     RefPtr<QtPixmapInstance> instance = adoptRef(new QtPixmapInstance(root, data));
    357     return instance->createRuntimeObject(exec);
    358 }
    359 
    360 bool QtPixmapInstance::canHandle(QMetaType::Type hint)
    361 {
    362     return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>();
    363 }
    364 
    365 }
    366 
    367 }
    368