2 * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
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.
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.
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
20 #include "qt_pixmapruntime.h"
22 #include "CachedImage.h"
23 #include "HTMLImageElement.h"
24 #include "ImageData.h"
26 #include "JSDOMBinding.h"
27 #include "JSGlobalObject.h"
28 #include "JSHTMLImageElement.h"
29 #include "JSImageData.h"
31 #include "ObjectPrototype.h"
32 #include "StillImageQt.h"
40 #include <runtime_method.h>
41 #include <runtime_object.h>
42 #include <runtime_root.h>
43 #include "runtime/FunctionPrototype.h"
45 using namespace WebCore;
50 class QtPixmapClass : public Class {
53 virtual MethodList methodsNamed(const Identifier&, Instance*) const;
54 virtual Field* fieldNamed(const Identifier&, Instance*) const;
58 class QtPixmapWidthField : public Field {
60 static const char* name() { return "width"; }
61 virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const
63 return jsNumber(static_cast<const QtPixmapInstance*>(instance)->width());
65 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
68 class QtPixmapHeightField : public Field {
70 static const char* name() { return "height"; }
71 virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const
73 return jsNumber(static_cast<const QtPixmapInstance*>(instance)->height());
75 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
78 class QtPixmapRuntimeMethod : public Method {
80 virtual int numParameters() const
84 virtual JSValue invoke(ExecState* exec, QtPixmapInstance*) = 0;
88 class QtPixmapToImageDataMethod : public QtPixmapRuntimeMethod {
90 static const char* name() { return "toImageData"; }
91 JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
93 int width = instance->width();
94 int height = instance->height();
95 RefPtr<ByteArray> byteArray = ByteArray::create(width * height * 4);
96 copyPixels(instance->toImage(), width, height, byteArray->data());
97 RefPtr<ImageData> imageData = ImageData::create(IntSize(width, height), byteArray);
98 return toJS(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), imageData.get());
101 void copyPixels(const QImage& sourceImage, int width, int height, unsigned char* destPixels)
103 QImage image(sourceImage);
104 switch (image.format()) {
105 case QImage::Format_RGB888:
106 for (int y = 0; y < height; y++) {
107 const uchar* scanLine = image.scanLine(y);
108 for (int x = 0; x < width; x++) {
109 *(destPixels++) = *(scanLine++);
110 *(destPixels++) = *(scanLine++);
111 *(destPixels++) = *(scanLine++);
112 *(destPixels++) = 0xFF;
117 image = image.convertToFormat(QImage::Format_ARGB32);
119 case QImage::Format_RGB32:
120 case QImage::Format_ARGB32:
121 for (int y = 0; y < height; y++) {
122 const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(image.scanLine(y));
123 for (int x = 0; x < width; x++) {
124 QRgb pixel = scanLine[x];
125 qToBigEndian<quint32>((pixel << 8) | qAlpha(pixel), destPixels);
134 // this function receives an HTML image element as a parameter, makes it display the pixmap/image from Qt
135 class QtPixmapAssignToElementMethod : public QtPixmapRuntimeMethod {
137 static const char* name() { return "assignToHTMLImageElement"; }
138 JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
140 if (!exec->argumentCount())
141 return jsUndefined();
143 JSObject* objectArg = exec->argument(0).toObject(exec);
145 return jsUndefined();
147 if (!objectArg->inherits(&JSHTMLImageElement::s_info))
148 return jsUndefined();
150 // we now know that we have a valid <img> element as the argument, we can attach the pixmap to it.
151 PassRefPtr<StillImage> stillImage = WebCore::StillImage::create(instance->toPixmap());
152 HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(static_cast<JSHTMLImageElement*>(objectArg)->impl());
153 imageElement->setCachedImage(new CachedImage(stillImage.get()));
154 JSDOMGlobalObject* global = static_cast<JSDOMGlobalObject*>(instance->rootObject()->globalObject());
155 toJS(exec, global, imageElement->document());
156 return jsUndefined();
159 virtual int numParameters() const
165 // this function encodes the image to a dataUrl, to be used in background etc. Note: very slow.
166 class QtPixmapToDataUrlMethod : public QtPixmapRuntimeMethod {
168 static const char* name() { return "toDataUrl"; }
169 JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
171 QByteArray byteArray;
172 QBuffer buffer(&byteArray);
173 instance->toImage().save(&buffer, "PNG");
174 const QString encodedString = QLatin1String("data:image/png;base64,") + QLatin1String(byteArray.toBase64());
175 const UString ustring((UChar*)encodedString.utf16(), encodedString.length());
176 return jsString(exec, ustring);
180 class QtPixmapToStringMethod : public QtPixmapRuntimeMethod {
182 static const char* name() { return "toString"; }
183 JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
185 return instance->valueOf(exec);
189 struct QtPixmapMetaData {
190 QtPixmapToDataUrlMethod toDataUrlMethod;
191 QtPixmapToImageDataMethod toImageDataMethod;
192 QtPixmapAssignToElementMethod assignToElementMethod;
193 QtPixmapToStringMethod toStringMethod;
194 QtPixmapHeightField heightField;
195 QtPixmapWidthField widthField;
197 } qt_pixmap_metaData;
199 // Derived RuntimeObject
200 class QtPixmapRuntimeObject : public RuntimeObject {
202 typedef RuntimeObject Base;
204 static QtPixmapRuntimeObject* create(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr<Instance> instance)
206 Structure* domStructure = WebCore::deprecatedGetDOMStructure<QtPixmapRuntimeObject>(exec);
207 QtPixmapRuntimeObject* object = new (allocateCell<QtPixmapRuntimeObject>(*exec->heap())) QtPixmapRuntimeObject(exec, globalObject, domStructure, instance);
208 object->finishCreation(globalObject);
212 static const ClassInfo s_info;
214 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
216 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
220 static const unsigned StructureFlags = RuntimeObject::StructureFlags | OverridesVisitChildren;
223 QtPixmapRuntimeObject(ExecState*, JSGlobalObject*, Structure*, PassRefPtr<Instance>);
226 QtPixmapRuntimeObject::QtPixmapRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, PassRefPtr<Instance> instance)
227 : RuntimeObject(exec, globalObject, structure, instance)
231 const ClassInfo QtPixmapRuntimeObject::s_info = { "QtPixmapRuntimeObject", &RuntimeObject::s_info, 0, 0 };
233 QtPixmapClass::QtPixmapClass()
238 Class* QtPixmapInstance::getClass() const
240 return &qt_pixmap_metaData.cls;
243 JSValue QtPixmapInstance::getMethod(ExecState* exec, const Identifier& propertyName)
245 MethodList methodList = getClass()->methodsNamed(propertyName, this);
246 return RuntimeMethod::create(exec, exec->lexicalGlobalObject(), WebCore::deprecatedGetDOMStructure<RuntimeMethod>(exec), propertyName, methodList);
249 JSValue QtPixmapInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod)
251 const MethodList& methods = *runtimeMethod->methods();
253 if (methods.size() == 1) {
254 QtPixmapRuntimeMethod* method = static_cast<QtPixmapRuntimeMethod*>(methods[0]);
255 return method->invoke(exec, this);
257 return jsUndefined();
260 MethodList QtPixmapClass::methodsNamed(const Identifier& identifier, Instance*) const
263 if (identifier == QtPixmapToDataUrlMethod::name())
264 methods.append(&qt_pixmap_metaData.toDataUrlMethod);
265 else if (identifier == QtPixmapToImageDataMethod::name())
266 methods.append(&qt_pixmap_metaData.toImageDataMethod);
267 else if (identifier == QtPixmapAssignToElementMethod::name())
268 methods.append(&qt_pixmap_metaData.assignToElementMethod);
269 else if (identifier == QtPixmapToStringMethod::name())
270 methods.append(&qt_pixmap_metaData.toStringMethod);
274 Field* QtPixmapClass::fieldNamed(const Identifier& identifier, Instance*) const
276 if (identifier == QtPixmapWidthField::name())
277 return &qt_pixmap_metaData.widthField;
278 if (identifier == QtPixmapHeightField::name())
279 return &qt_pixmap_metaData.heightField;
283 void QtPixmapInstance::getPropertyNames(ExecState*exec, PropertyNameArray& arr)
285 arr.add(Identifier(exec, UString(QtPixmapToDataUrlMethod::name())));
286 arr.add(Identifier(exec, UString(QtPixmapToImageDataMethod::name())));
287 arr.add(Identifier(exec, UString(QtPixmapAssignToElementMethod::name())));
288 arr.add(Identifier(exec, UString(QtPixmapToStringMethod::name())));
289 arr.add(Identifier(exec, UString(QtPixmapWidthField::name())));
290 arr.add(Identifier(exec, UString(QtPixmapHeightField::name())));
293 JSValue QtPixmapInstance::defaultValue(ExecState* exec, PreferredPrimitiveType ptype) const
295 if (ptype == PreferNumber) {
297 (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()) && !(data.value<QImage>()).isNull())
298 || (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()) && !data.value<QPixmap>().isNull()));
301 if (ptype == PreferString)
302 return valueOf(exec);
304 return jsUndefined();
307 JSValue QtPixmapInstance::valueOf(ExecState* exec) const
309 const QString stringValue = QString::fromLatin1("[Qt Native Pixmap %1,%2]").arg(width()).arg(height());
310 UString ustring((UChar*)stringValue.utf16(), stringValue.length());
311 return jsString(exec, ustring);
314 QtPixmapInstance::QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& d)
315 :Instance(rootObj), data(d)
319 int QtPixmapInstance::width() const
321 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
322 return data.value<QPixmap>().width();
323 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
324 return data.value<QImage>().width();
328 int QtPixmapInstance::height() const
330 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
331 return data.value<QPixmap>().height();
332 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
333 return data.value<QImage>().height();
337 QPixmap QtPixmapInstance::toPixmap()
339 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
340 return data.value<QPixmap>();
342 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) {
343 const QPixmap pixmap = QPixmap::fromImage(data.value<QImage>());
344 data = QVariant::fromValue<QPixmap>(pixmap);
351 QImage QtPixmapInstance::toImage()
353 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
354 return data.value<QImage>();
356 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) {
357 const QImage image = data.value<QPixmap>().toImage();
358 data = QVariant::fromValue<QImage>(image);
365 QVariant QtPixmapInstance::variantFromObject(JSObject* object, QMetaType::Type hint)
368 goto returnEmptyVariant;
370 if (object->inherits(&JSHTMLImageElement::s_info)) {
371 JSHTMLImageElement* elementJSWrapper = static_cast<JSHTMLImageElement*>(object);
372 HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(elementJSWrapper->impl());
375 goto returnEmptyVariant;
377 CachedImage* cachedImage = imageElement->cachedImage();
379 goto returnEmptyVariant;
381 Image* image = cachedImage->image();
383 goto returnEmptyVariant;
385 QPixmap* pixmap = image->nativeImageForCurrentFrame();
387 goto returnEmptyVariant;
389 return (hint == static_cast<QMetaType::Type>(qMetaTypeId<QPixmap>()))
390 ? QVariant::fromValue<QPixmap>(*pixmap)
391 : QVariant::fromValue<QImage>(pixmap->toImage());
394 if (object->inherits(&QtPixmapRuntimeObject::s_info)) {
395 QtPixmapRuntimeObject* runtimeObject = static_cast<QtPixmapRuntimeObject*>(object);
396 QtPixmapInstance* instance = static_cast<QtPixmapInstance*>(runtimeObject->getInternalInstance());
398 goto returnEmptyVariant;
400 if (hint == qMetaTypeId<QPixmap>())
401 return QVariant::fromValue<QPixmap>(instance->toPixmap());
403 if (hint == qMetaTypeId<QImage>())
404 return QVariant::fromValue<QImage>(instance->toImage());
408 if (hint == qMetaTypeId<QPixmap>())
409 return QVariant::fromValue<QPixmap>(QPixmap());
410 if (hint == qMetaTypeId<QImage>())
411 return QVariant::fromValue<QImage>(QImage());
415 RuntimeObject* QtPixmapInstance::newRuntimeObject(ExecState* exec)
417 return QtPixmapRuntimeObject::create(exec, exec->lexicalGlobalObject(), this);
420 JSObject* QtPixmapInstance::createPixmapRuntimeObject(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& data)
422 JSLock lock(SilenceAssertionsOnly);
423 RefPtr<QtPixmapInstance> instance = adoptRef(new QtPixmapInstance(root, data));
424 return instance->createRuntimeObject(exec);
427 bool QtPixmapInstance::canHandle(QMetaType::Type hint)
429 return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>();