blob: 3e6197f0af605ddd8900751838714f752996e3e3 [file] [log] [blame]
/*
* 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 <QBuffer>
#include <QByteArray>
#include <QImage>
#include <QPixmap>
#include <QVariant>
#include <runtime_object.h>
#include <runtime_root.h>
#include <runtime_method.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* exec, const Instance* instance) const
{
return jsNumber(exec, static_cast<const QtPixmapInstance*>(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* exec, const Instance* instance) const
{
return jsNumber(exec, static_cast<const QtPixmapInstance*>(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*, const ArgList&) = 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, const ArgList& args)
{
if (!args.size())
return jsUndefined();
JSObject* objectArg = args.at(0).toObject(exec);
if (!objectArg)
return jsUndefined();
if (!objectArg->inherits(&JSHTMLImageElement::s_info))
return jsUndefined();
// we now know that we have a valid <img> element as the argument, we can attach the pixmap to it.
PassRefPtr<StillImage> stillImage = WebCore::StillImage::create(instance->toPixmap());
HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(static_cast<JSHTMLImageElement*>(objectArg)->impl());
imageElement->setCachedImage(new CachedImage(stillImage.get()));
JSDOMGlobalObject* global = static_cast<JSDOMGlobalObject*>(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, const ArgList&)
{
QByteArray byteArray;
QBuffer buffer(&byteArray);
instance->toImage().save(&buffer, "PNG");
const QString encodedString = QString("data:image/png;base64,") + 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, const ArgList&)
{
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*, PassRefPtr<Instance>);
static const ClassInfo s_info;
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
static const unsigned StructureFlags = RuntimeObject::StructureFlags | OverridesMarkChildren;
private:
virtual const ClassInfo* classInfo() const { return &s_info; }
};
QtPixmapRuntimeObject::QtPixmapRuntimeObject(ExecState* exec, PassRefPtr<Instance> instance)
: RuntimeObject(exec, WebCore::deprecatedGetDOMStructure<QtPixmapRuntimeObject>(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, propertyName, methodList);
}
JSValue QtPixmapInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod, const ArgList& args)
{
const MethodList& methods = *runtimeMethod->methods();
if (methods.size() == 1) {
QtPixmapRuntimeMethod* method = static_cast<QtPixmapRuntimeMethod*>(methods[0]);
return method->invoke(exec, this, args);
}
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<QVariant::Type>(qMetaTypeId<QImage>()) && !(data.value<QImage>()).isNull())
|| (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()) && !data.value<QPixmap>().isNull()));
}
if (ptype == PreferString)
return valueOf(exec);
return jsUndefined();
}
JSValue QtPixmapInstance::valueOf(ExecState* exec) const
{
const QString stringValue = QString("[Qt Native Pixmap %1,%2]").arg(width()).arg(height());
UString ustring((UChar*)stringValue.utf16(), stringValue.length());
return jsString(exec, ustring);
}
QtPixmapInstance::QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& d)
:Instance(rootObj), data(d)
{
}
int QtPixmapInstance::width() const
{
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
return data.value<QPixmap>().width();
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
return data.value<QImage>().width();
return 0;
}
int QtPixmapInstance::height() const
{
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
return data.value<QPixmap>().height();
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
return data.value<QImage>().height();
return 0;
}
QPixmap QtPixmapInstance::toPixmap()
{
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
return data.value<QPixmap>();
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) {
const QPixmap pixmap = QPixmap::fromImage(data.value<QImage>());
data = QVariant::fromValue<QPixmap>(pixmap);
return pixmap;
}
return QPixmap();
}
QImage QtPixmapInstance::toImage()
{
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
return data.value<QImage>();
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) {
const QImage image = data.value<QPixmap>().toImage();
data = QVariant::fromValue<QImage>(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<JSHTMLImageElement*>(object);
HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(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<QMetaType::Type>(qMetaTypeId<QPixmap>()))
? QVariant::fromValue<QPixmap>(*pixmap)
: QVariant::fromValue<QImage>(pixmap->toImage());
}
if (object->inherits(&QtPixmapRuntimeObject::s_info)) {
QtPixmapRuntimeObject* runtimeObject = static_cast<QtPixmapRuntimeObject*>(object);
QtPixmapInstance* instance = static_cast<QtPixmapInstance*>(runtimeObject->getInternalInstance());
if (!instance)
goto returnEmptyVariant;
if (hint == qMetaTypeId<QPixmap>())
return QVariant::fromValue<QPixmap>(instance->toPixmap());
if (hint == qMetaTypeId<QImage>())
return QVariant::fromValue<QImage>(instance->toImage());
}
returnEmptyVariant:
if (hint == qMetaTypeId<QPixmap>())
return QVariant::fromValue<QPixmap>(QPixmap());
if (hint == qMetaTypeId<QImage>())
return QVariant::fromValue<QImage>(QImage());
return QVariant();
}
RuntimeObject* QtPixmapInstance::newRuntimeObject(ExecState* exec)
{
return new(exec) QtPixmapRuntimeObject(exec, this);
}
JSObject* QtPixmapInstance::createPixmapRuntimeObject(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& data)
{
JSLock lock(SilenceAssertionsOnly);
QtPixmapInstance* instance = new QtPixmapInstance(root, data);
return instance->createRuntimeObject(exec);
}
bool QtPixmapInstance::canHandle(QMetaType::Type hint)
{
return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>();
}
}
}