blob: 2bc5c2caca447ec4e8756367357c4888885b3347 [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 "APICast.h"
#include "CachedImage.h"
#include "HTMLImageElement.h"
#include "ImageData.h"
#include "IntSize.h"
#include "JSDOMBinding.h"
#include "JSGlobalObject.h"
#include "JSHTMLImageElement.h"
#include "JSImageData.h"
#include "JSRetainPtr.h"
#include "JavaScript.h"
#include "StillImageQt.h"
#include <QBuffer>
#include <QByteArray>
#include <QColor>
#include <QImage>
#include <QPixmap>
#include <QVariant>
#include <QtEndian>
using namespace WebCore;
namespace JSC {
namespace Bindings {
static void copyPixelsInto(const QImage& sourceImage, int width, int height, unsigned char* destPixels)
{
QImage image(sourceImage);
switch (image.format()) {
case QImage::Format_RGB888:
for (int y = 0; y < height; y++) {
const uchar* scanLine = image.scanLine(y);
for (int x = 0; x < width; x++) {
*(destPixels++) = *(scanLine++);
*(destPixels++) = *(scanLine++);
*(destPixels++) = *(scanLine++);
*(destPixels++) = 0xFF;
}
}
break;
default:
image = image.convertToFormat(QImage::Format_ARGB32);
// Fall through
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
for (int y = 0; y < height; y++) {
const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(image.scanLine(y));
for (int x = 0; x < width; x++) {
QRgb pixel = scanLine[x];
qToBigEndian<quint32>((pixel << 8) | qAlpha(pixel), destPixels);
destPixels += 4;
}
}
break;
}
}
static QPixmap toPixmap(const QVariant& data)
{
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
return data.value<QPixmap>();
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
return QPixmap::fromImage(data.value<QImage>());
return QPixmap();
}
static QImage toImage(const QVariant& data)
{
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
return data.value<QImage>();
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
return data.value<QPixmap>().toImage();
return QImage();
}
static QSize imageSizeForVariant(const QVariant& data)
{
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
return data.value<QPixmap>().size();
if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
return data.value<QImage>().size();
return QSize(0, 0);
}
static JSValueRef getPixmapWidth(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef*)
{
QVariant& data = *static_cast<QVariant*>(JSObjectGetPrivate(object));
return JSValueMakeNumber(context, imageSizeForVariant(data).width());
}
static JSValueRef getPixmapHeight(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef*)
{
QVariant& data = *static_cast<QVariant*>(JSObjectGetPrivate(object));
return JSValueMakeNumber(context, imageSizeForVariant(data).height());
}
static JSValueRef assignToHTMLImageElement(JSContextRef context, JSObjectRef function, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
if (!argumentCount)
return JSValueMakeUndefined(context);
JSObjectRef objectArg = JSValueToObject(context, arguments[0], exception);
if (!objectArg)
return JSValueMakeUndefined(context);
JSObject* jsObject = ::toJS(objectArg);
if (!jsObject->inherits(&JSHTMLImageElement::s_info))
return JSValueMakeUndefined(context);
QVariant& data = *static_cast<QVariant*>(JSObjectGetPrivate(object));
// We now know that we have a valid <img> element as the argument, we can attach the pixmap to it.
RefPtr<StillImage> stillImage = WebCore::StillImage::create(toPixmap(data));
HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(static_cast<JSHTMLImageElement*>(jsObject)->impl());
imageElement->setCachedImage(new CachedImage(stillImage.get()));
return JSValueMakeUndefined(context);
}
static JSValueRef pixmapToImageData(JSContextRef context, JSObjectRef function, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
QVariant& data = *static_cast<QVariant*>(JSObjectGetPrivate(object));
QImage image = toImage(data);
int width = image.width();
int height = image.height();
RefPtr<ImageData> imageData = ImageData::create(IntSize(width, height));
copyPixelsInto(image, width, height, imageData->data()->data());
JSDOMGlobalObject* globalObject = static_cast<JSDOMGlobalObject*>(::toJS(JSContextGetGlobalObject(context)));
JSC::ExecState* exec = ::toJS(context);
return ::toRef(exec, toJS(exec, globalObject, imageData.get()));
}
static JSValueRef pixmapToDataUrl(JSContextRef context, JSObjectRef function, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
QVariant& data = *static_cast<QVariant*>(JSObjectGetPrivate(object));
QByteArray byteArray;
QBuffer buffer(&byteArray);
toImage(data).save(&buffer, "PNG");
QByteArray encoded = QByteArray("data:image/png;base64,") + byteArray.toBase64();
JSRetainPtr<JSStringRef> str(Adopt, JSStringCreateWithUTF8CString(encoded.constData()));
JSValueRef value = JSValueMakeString(context, str.get());
return value;
}
static JSValueRef pixmapToString(JSContextRef context, JSObjectRef function, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
QVariant& data = *static_cast<QVariant*>(JSObjectGetPrivate(object));
QSize size = imageSizeForVariant(data);
QString stringValue = QString::fromLatin1("[Qt Native Pixmap %1,%2]").arg(size.width()).arg(size.height());
JSRetainPtr<JSStringRef> str(Adopt, JSStringCreateWithUTF8CString(stringValue.toUtf8().constData()));
JSValueRef value = JSValueMakeString(context, str.get());
return value;
}
static void finalizePixmap(JSObjectRef object)
{
delete static_cast<QVariant*>(JSObjectGetPrivate(object));
}
JSObjectRef QtPixmapRuntime::toJS(JSContextRef context, const QVariant& value, JSValueRef* exception)
{
return JSObjectMake(context, getClassRef(), new QVariant(value));
}
static QVariant emptyVariantForHint(QMetaType::Type hint)
{
if (hint == qMetaTypeId<QPixmap>())
return QVariant::fromValue(QPixmap());
if (hint == qMetaTypeId<QImage>())
return QVariant::fromValue(QImage());
return QVariant();
}
QVariant QtPixmapRuntime::toQt(JSContextRef context, JSObjectRef obj, QMetaType::Type hint, JSValueRef* exception)
{
if (!obj)
return emptyVariantForHint(hint);
if (JSValueIsObjectOfClass(context, obj, QtPixmapRuntime::getClassRef())) {
QVariant* originalVariant = static_cast<QVariant*>(JSObjectGetPrivate(obj));
if (hint == qMetaTypeId<QPixmap>())
return QVariant::fromValue<QPixmap>(toPixmap(*originalVariant));
if (hint == qMetaTypeId<QImage>())
return QVariant::fromValue<QImage>(toImage(*originalVariant));
}
JSObject* jsObject = ::toJS(obj);
if (!jsObject->inherits(&JSHTMLImageElement::s_info))
return emptyVariantForHint(hint);
JSHTMLImageElement* elementJSWrapper = static_cast<JSHTMLImageElement*>(jsObject);
HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(elementJSWrapper->impl());
if (!imageElement)
return emptyVariantForHint(hint);
CachedImage* cachedImage = imageElement->cachedImage();
if (!cachedImage)
return emptyVariantForHint(hint);
Image* image = cachedImage->imageForRenderer(imageElement->renderer());
if (!image)
return emptyVariantForHint(hint);
QPixmap* pixmap = image->nativeImageForCurrentFrame();
if (!pixmap)
return emptyVariantForHint(hint);
return (hint == static_cast<QMetaType::Type>(qMetaTypeId<QPixmap>()))
? QVariant::fromValue<QPixmap>(*pixmap)
: QVariant::fromValue<QImage>(pixmap->toImage());
}
bool QtPixmapRuntime::canHandle(QMetaType::Type hint)
{
return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>();
}
JSClassRef QtPixmapRuntime::getClassRef()
{
static const JSStaticValue staticValues[] = {
{ "width", getPixmapWidth, 0, 0 },
{ "height", getPixmapHeight, 0, 0 }
};
static const JSStaticFunction staticFunctions[] = {
{ "assignTo", assignToHTMLImageElement, 0 },
{ "toDataUrl", pixmapToDataUrl, 0 },
{ "toImageData", pixmapToImageData, 0 },
{ "toString", pixmapToString, 0 }
};
static const JSClassDefinition classDefinition = {
0, 0, "QtPixmapRuntimeObject", 0, staticValues, staticFunctions,
0, finalizePixmap, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static JSClassRef classRef = JSClassCreate(&classDefinition);
return classRef;
}
}
}