/* * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include "qt_pixmapruntime.h" #include "CachedImage.h" #include "DOMWindow.h" #include "HTMLImageElement.h" #include "HTMLNames.h" #include "JSDOMBinding.h" #include "JSDOMWindow.h" #include "JSGlobalObject.h" #include "JSHTMLImageElement.h" #include "JSLock.h" #include "ObjectPrototype.h" #include "StillImageQt.h" #include #include #include #include #include #include #include using namespace WebCore; namespace JSC { namespace Bindings { class QtPixmapClass : public Class { public: QtPixmapClass(); virtual MethodList methodsNamed(const Identifier&, Instance*) const; virtual Field* fieldNamed(const Identifier&, Instance*) const; }; class QtPixmapWidthField : public Field { public: static const char* name() { return "width"; } virtual JSValue valueFromInstance(ExecState* exec, const Instance* pixmap) const { return jsNumber(exec, static_cast(pixmap)->width()); } virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {} }; class QtPixmapHeightField : public Field { public: static const char* name() { return "height"; } virtual JSValue valueFromInstance(ExecState* exec, const Instance* inst) const { return jsNumber(exec, static_cast(inst)->height()); } virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {} }; class QtPixmapRuntimeMethod : public Method { public: virtual int numParameters() const { return 0; } virtual JSValue invoke(ExecState* exec, QVariant&, PassRefPtr root, QtPixmapInstance* inst) = 0; }; class QtPixmapCreateElementMethod : public QtPixmapRuntimeMethod { public: static const char* name() { return "toHTMLImageElement"; } JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr root, QtPixmapInstance*) { QPixmap pxm; if (v.type() == static_cast(qMetaTypeId())) { pxm = QPixmap::fromImage(v.value()); v = QVariant::fromValue(pxm); } else pxm = v.value(); Document* document = 0; JSDOMGlobalObject* global = static_cast(root->globalObject()); if (global) { DOMWindow* dWindow = toDOMWindow(global); if (dWindow) document = dWindow->document(); } if (document) { PassRefPtr img = WebCore::StillImage::create(pxm); RefPtr image = new HTMLImageElement(HTMLNames::imgTag, document); image->setCachedImage(new CachedImage(img.get())); toJS(exec, global, document); return asObject(toJS(exec, global, image.release())); } return jsUndefined(); } }; class QtPixmapToDataUrlMethod : public QtPixmapRuntimeMethod { public: static const char* name() { return "toDataUrl"; } JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr root, QtPixmapInstance*) { QImage image; // for getting the data url, we always prefer the image. if (v.type() == static_cast(qMetaTypeId())) { image = v.value().toImage(); v = QVariant::fromValue(image); } else image = v.value(); QByteArray ba; QBuffer b(&ba); image.save(&b, "PNG"); const QString b64 = QString("data:image/png;base64,") + ba.toBase64(); const UString ustring((UChar*)b64.utf16(), b64.length()); return jsString(exec, ustring); } }; class QtPixmapToStringMethod : public QtPixmapRuntimeMethod { public: static const char* name() { return "toString"; } JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr root, QtPixmapInstance* inst) { return inst->valueOf(exec); } }; struct QtPixmapMetaData { QtPixmapToDataUrlMethod toDataUrlMethod; QtPixmapCreateElementMethod createElementMethod; QtPixmapToStringMethod toStringMethod; QtPixmapHeightField heightField; QtPixmapWidthField widthField; QtPixmapClass cls; } qt_pixmap_metaData; // Derived RuntimeObject class QtPixmapRuntimeObjectImp : public RuntimeObjectImp { public: QtPixmapRuntimeObjectImp(ExecState*, PassRefPtr); static const ClassInfo s_info; static PassRefPtr createStructure(JSValue prototype) { return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); } protected: static const unsigned StructureFlags = RuntimeObjectImp::StructureFlags | OverridesMarkChildren; private: virtual const ClassInfo* classInfo() const { return &s_info; } }; QtPixmapRuntimeObjectImp::QtPixmapRuntimeObjectImp(ExecState* exec, PassRefPtr instance) : RuntimeObjectImp(exec, WebCore::deprecatedGetDOMStructure(exec), instance) { } const ClassInfo QtPixmapRuntimeObjectImp::s_info = { "QtPixmapRuntimeObject", &RuntimeObjectImp::s_info, 0, 0 }; QtPixmapClass::QtPixmapClass() { } Class* QtPixmapInstance::getClass() const { return &qt_pixmap_metaData.cls; } JSValue QtPixmapInstance::invokeMethod(ExecState* exec, const MethodList& methods, const ArgList& args) { if (methods.size() == 1) { QtPixmapRuntimeMethod* mtd = static_cast(methods[0]); return mtd->invoke(exec, data, rootObject(), this); } return jsUndefined(); } MethodList QtPixmapClass::methodsNamed(const Identifier& identifier, Instance*) const { MethodList methods; if (identifier == QtPixmapToDataUrlMethod::name()) methods.append(&qt_pixmap_metaData.toDataUrlMethod); else if (identifier == QtPixmapCreateElementMethod::name()) methods.append(&qt_pixmap_metaData.createElementMethod); else if (identifier == QtPixmapToStringMethod::name()) methods.append(&qt_pixmap_metaData.toStringMethod); return methods; } Field* QtPixmapClass::fieldNamed(const Identifier& identifier, Instance*) const { if (identifier == QtPixmapWidthField::name()) return &qt_pixmap_metaData.widthField; if (identifier == QtPixmapHeightField::name()) return &qt_pixmap_metaData.heightField; return 0; } void QtPixmapInstance::getPropertyNames(ExecState*exec, PropertyNameArray& arr) { arr.add(Identifier(exec, UString(QtPixmapToDataUrlMethod::name()))); arr.add(Identifier(exec, UString(QtPixmapCreateElementMethod::name()))); arr.add(Identifier(exec, UString(QtPixmapToStringMethod::name()))); arr.add(Identifier(exec, UString(QtPixmapWidthField::name()))); arr.add(Identifier(exec, UString(QtPixmapHeightField::name()))); } JSValue QtPixmapInstance::defaultValue(ExecState* exec, PreferredPrimitiveType ptype) const { if (ptype == PreferNumber) { return jsBoolean( (data.type() == static_cast(qMetaTypeId()) && !(data.value()).isNull()) || (data.type() == static_cast(qMetaTypeId()) && !data.value().isNull())); } if (ptype == PreferString) return valueOf(exec); return jsUndefined(); } JSValue QtPixmapInstance::valueOf(ExecState* exec) const { const QString toStr = QString("[Qt Native Pixmap %1,%2]").arg(width()).arg(height()); UString ustring((UChar*)toStr.utf16(), toStr.length()); return jsString(exec, ustring); } QtPixmapInstance::QtPixmapInstance(PassRefPtr rootObj, const QVariant& d) :Instance(rootObj), data(d) { } int QtPixmapInstance::width() const { if (data.type() == static_cast(qMetaTypeId())) return data.value().width(); if (data.type() == static_cast(qMetaTypeId())) return data.value().width(); return 0; } int QtPixmapInstance::height() const { if (data.type() == static_cast(qMetaTypeId())) return data.value().height(); if (data.type() == static_cast(qMetaTypeId())) return data.value().height(); return 0; } QPixmap QtPixmapInstance::toPixmap() { if (data.type() == static_cast(qMetaTypeId())) return data.value(); if (data.type() == static_cast(qMetaTypeId())) { const QPixmap pxm = QPixmap::fromImage(data.value()); data = QVariant::fromValue(pxm); return pxm; } return QPixmap(); } QImage QtPixmapInstance::toImage() { if (data.type() == static_cast(qMetaTypeId())) return data.value(); if (data.type() == static_cast(qMetaTypeId())) { const QImage img = data.value().toImage(); data = QVariant::fromValue(img); return img; } return QImage(); } QVariant QtPixmapInstance::variantFromObject(JSObject* object, QMetaType::Type hint) { if (!object) { if (hint == qMetaTypeId()) return QVariant::fromValue(QPixmap()); if (hint == qMetaTypeId()) return QVariant::fromValue(QImage()); } else if (object->inherits(&JSHTMLImageElement::s_info)) { JSHTMLImageElement* el = static_cast(object); HTMLImageElement* imageElement = static_cast(el->impl()); if (imageElement) { CachedImage* cImg = imageElement->cachedImage(); if (cImg) { Image* img = cImg->image(); if (img) { QPixmap* pxm = img->nativeImageForCurrentFrame(); if (pxm) { return (hint == static_cast(qMetaTypeId())) ? QVariant::fromValue(*pxm) : QVariant::fromValue(pxm->toImage()); } } } } } else if (object->inherits(&QtPixmapRuntimeObjectImp::s_info)) { QtPixmapRuntimeObjectImp* imp = static_cast(object); QtPixmapInstance* inst = static_cast(imp->getInternalInstance()); if (inst) { if (hint == qMetaTypeId()) return QVariant::fromValue(inst->toPixmap()); if (hint == qMetaTypeId()) return QVariant::fromValue(inst->toImage()); } } return 0; } JSObject* QtPixmapInstance::createRuntimeObject(ExecState* exec, PassRefPtr root, const QVariant& data) { JSLock lock(SilenceAssertionsOnly); return new(exec) QtPixmapRuntimeObjectImp(exec, new QtPixmapInstance(root, data)); } bool QtPixmapInstance::canHandle(QMetaType::Type hint) { return hint == qMetaTypeId() || hint == qMetaTypeId(); } } }