/* * 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 "HTMLImageElement.h" #include "JSGlobalObject.h" #include "JSHTMLImageElement.h" #include "JSLock.h" #include "ObjectPrototype.h" #include "StillImageQt.h" #include #include #include #include #include #include #include #include #include "runtime/FunctionPrototype.h" 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*, const Instance* instance) const { return jsNumber(static_cast(instance)->width()); } virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {} }; class QtPixmapHeightField : public Field { public: static const char* name() { return "height"; } virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const { return jsNumber(static_cast(instance)->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, QtPixmapInstance*) = 0; }; // this function receives an HTML image element as a parameter, makes it display the pixmap/image from Qt class QtPixmapAssignToElementMethod : public QtPixmapRuntimeMethod { public: static const char* name() { return "assignToHTMLImageElement"; } JSValue invoke(ExecState* exec, QtPixmapInstance* instance) { if (!exec->argumentCount()) return jsUndefined(); JSObject* objectArg = exec->argument(0).toObject(exec); if (!objectArg) return jsUndefined(); if (!objectArg->inherits(&JSHTMLImageElement::s_info)) return jsUndefined(); // we now know that we have a valid element as the argument, we can attach the pixmap to it. PassRefPtr stillImage = WebCore::StillImage::create(instance->toPixmap()); HTMLImageElement* imageElement = static_cast(static_cast(objectArg)->impl()); imageElement->setCachedImage(new CachedImage(stillImage.get())); JSDOMGlobalObject* global = static_cast(instance->rootObject()->globalObject()); toJS(exec, global, imageElement->document()); return jsUndefined(); } virtual int numParameters() const { return 1; } }; // this function encodes the image to a dataUrl, to be used in background etc. Note: very slow. class QtPixmapToDataUrlMethod : public QtPixmapRuntimeMethod { public: static const char* name() { return "toDataUrl"; } JSValue invoke(ExecState* exec, QtPixmapInstance* instance) { QByteArray byteArray; QBuffer buffer(&byteArray); instance->toImage().save(&buffer, "PNG"); const QString encodedString = QLatin1String("data:image/png;base64,") + QLatin1String(byteArray.toBase64()); const UString ustring((UChar*)encodedString.utf16(), encodedString.length()); return jsString(exec, ustring); } }; class QtPixmapToStringMethod : public QtPixmapRuntimeMethod { public: static const char* name() { return "toString"; } JSValue invoke(ExecState* exec, QtPixmapInstance* instance) { return instance->valueOf(exec); } }; struct QtPixmapMetaData { QtPixmapToDataUrlMethod toDataUrlMethod; QtPixmapAssignToElementMethod assignToElementMethod; QtPixmapToStringMethod toStringMethod; QtPixmapHeightField heightField; QtPixmapWidthField widthField; QtPixmapClass cls; } qt_pixmap_metaData; // Derived RuntimeObject class QtPixmapRuntimeObject : public RuntimeObject { public: QtPixmapRuntimeObject(ExecState*, JSGlobalObject*, PassRefPtr); static const ClassInfo s_info; static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = RuntimeObject::StructureFlags | OverridesMarkChildren; }; QtPixmapRuntimeObject::QtPixmapRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr instance) : RuntimeObject(exec, globalObject, WebCore::deprecatedGetDOMStructure(exec), instance) { } const ClassInfo QtPixmapRuntimeObject::s_info = { "QtPixmapRuntimeObject", &RuntimeObject::s_info, 0, 0 }; QtPixmapClass::QtPixmapClass() { } Class* QtPixmapInstance::getClass() const { return &qt_pixmap_metaData.cls; } JSValue QtPixmapInstance::getMethod(ExecState* exec, const Identifier& propertyName) { MethodList methodList = getClass()->methodsNamed(propertyName, this); return new (exec) RuntimeMethod(exec, exec->lexicalGlobalObject(), WebCore::deprecatedGetDOMStructure(exec), propertyName, methodList); } JSValue QtPixmapInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod) { const MethodList& methods = *runtimeMethod->methods(); if (methods.size() == 1) { QtPixmapRuntimeMethod* method = static_cast(methods[0]); return method->invoke(exec, 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 == QtPixmapAssignToElementMethod::name()) methods.append(&qt_pixmap_metaData.assignToElementMethod); 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(QtPixmapAssignToElementMethod::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 stringValue = QString::fromLatin1("[Qt Native Pixmap %1,%2]").arg(width()).arg(height()); UString ustring((UChar*)stringValue.utf16(), stringValue.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 pixmap = QPixmap::fromImage(data.value()); data = QVariant::fromValue(pixmap); return pixmap; } return QPixmap(); } QImage QtPixmapInstance::toImage() { if (data.type() == static_cast(qMetaTypeId())) return data.value(); if (data.type() == static_cast(qMetaTypeId())) { const QImage image = data.value().toImage(); data = QVariant::fromValue(image); return image; } return QImage(); } QVariant QtPixmapInstance::variantFromObject(JSObject* object, QMetaType::Type hint) { if (!object) goto returnEmptyVariant; if (object->inherits(&JSHTMLImageElement::s_info)) { JSHTMLImageElement* elementJSWrapper = static_cast(object); HTMLImageElement* imageElement = static_cast(elementJSWrapper->impl()); if (!imageElement) goto returnEmptyVariant; CachedImage* cachedImage = imageElement->cachedImage(); if (!cachedImage) goto returnEmptyVariant; Image* image = cachedImage->image(); if (!image) goto returnEmptyVariant; QPixmap* pixmap = image->nativeImageForCurrentFrame(); if (!pixmap) goto returnEmptyVariant; return (hint == static_cast(qMetaTypeId())) ? QVariant::fromValue(*pixmap) : QVariant::fromValue(pixmap->toImage()); } if (object->inherits(&QtPixmapRuntimeObject::s_info)) { QtPixmapRuntimeObject* runtimeObject = static_cast(object); QtPixmapInstance* instance = static_cast(runtimeObject->getInternalInstance()); if (!instance) goto returnEmptyVariant; if (hint == qMetaTypeId()) return QVariant::fromValue(instance->toPixmap()); if (hint == qMetaTypeId()) return QVariant::fromValue(instance->toImage()); } returnEmptyVariant: if (hint == qMetaTypeId()) return QVariant::fromValue(QPixmap()); if (hint == qMetaTypeId()) return QVariant::fromValue(QImage()); return QVariant(); } RuntimeObject* QtPixmapInstance::newRuntimeObject(ExecState* exec) { return new(exec) QtPixmapRuntimeObject(exec, exec->lexicalGlobalObject(), this); } JSObject* QtPixmapInstance::createPixmapRuntimeObject(ExecState* exec, PassRefPtr root, const QVariant& data) { JSLock lock(SilenceAssertionsOnly); RefPtr instance = adoptRef(new QtPixmapInstance(root, data)); return instance->createRuntimeObject(exec); } bool QtPixmapInstance::canHandle(QMetaType::Type hint) { return hint == qMetaTypeId() || hint == qMetaTypeId(); } } }