1 /*
2 * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3 *
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.
8 *
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.
13 *
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
17 *
18 */
19 #include "config.h"
20 #include "qt_pixmapruntime.h"
21
22 #include "CachedImage.h"
23 #include "HTMLImageElement.h"
24 #include "JSGlobalObject.h"
25 #include "JSHTMLImageElement.h"
26 #include "JSLock.h"
27 #include "ObjectPrototype.h"
28 #include "StillImageQt.h"
29 #include <QBuffer>
30 #include <QByteArray>
31 #include <QImage>
32 #include <QPixmap>
33 #include <QVariant>
34 #include <runtime_method.h>
35 #include <runtime_object.h>
36 #include <runtime_root.h>
37 #include "runtime/FunctionPrototype.h"
38
39 using namespace WebCore;
40 namespace JSC {
41
42 namespace Bindings {
43
44 class QtPixmapClass : public Class {
45 public:
46 QtPixmapClass();
47 virtual MethodList methodsNamed(const Identifier&, Instance*) const;
48 virtual Field* fieldNamed(const Identifier&, Instance*) const;
49 };
50
51
52 class QtPixmapWidthField : public Field {
53 public:
name()54 static const char* name() { return "width"; }
valueFromInstance(ExecState *,const Instance * instance) const55 virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const
56 {
57 return jsNumber(static_cast<const QtPixmapInstance*>(instance)->width());
58 }
setValueToInstance(ExecState *,const Instance *,JSValue) const59 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
60 };
61
62 class QtPixmapHeightField : public Field {
63 public:
name()64 static const char* name() { return "height"; }
valueFromInstance(ExecState *,const Instance * instance) const65 virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const
66 {
67 return jsNumber(static_cast<const QtPixmapInstance*>(instance)->height());
68 }
setValueToInstance(ExecState *,const Instance *,JSValue) const69 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
70 };
71
72 class QtPixmapRuntimeMethod : public Method {
73 public:
numParameters() const74 virtual int numParameters() const
75 {
76 return 0;
77 }
78 virtual JSValue invoke(ExecState* exec, QtPixmapInstance*) = 0;
79
80 };
81
82 // this function receives an HTML image element as a parameter, makes it display the pixmap/image from Qt
83 class QtPixmapAssignToElementMethod : public QtPixmapRuntimeMethod {
84 public:
name()85 static const char* name() { return "assignToHTMLImageElement"; }
invoke(ExecState * exec,QtPixmapInstance * instance)86 JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
87 {
88 if (!exec->argumentCount())
89 return jsUndefined();
90
91 JSObject* objectArg = exec->argument(0).toObject(exec);
92 if (!objectArg)
93 return jsUndefined();
94
95 if (!objectArg->inherits(&JSHTMLImageElement::s_info))
96 return jsUndefined();
97
98 // we now know that we have a valid <img> element as the argument, we can attach the pixmap to it.
99 PassRefPtr<StillImage> stillImage = WebCore::StillImage::create(instance->toPixmap());
100 HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(static_cast<JSHTMLImageElement*>(objectArg)->impl());
101 imageElement->setCachedImage(new CachedImage(stillImage.get()));
102 JSDOMGlobalObject* global = static_cast<JSDOMGlobalObject*>(instance->rootObject()->globalObject());
103 toJS(exec, global, imageElement->document());
104 return jsUndefined();
105 }
106
numParameters() const107 virtual int numParameters() const
108 {
109 return 1;
110 }
111 };
112
113 // this function encodes the image to a dataUrl, to be used in background etc. Note: very slow.
114 class QtPixmapToDataUrlMethod : public QtPixmapRuntimeMethod {
115 public:
name()116 static const char* name() { return "toDataUrl"; }
invoke(ExecState * exec,QtPixmapInstance * instance)117 JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
118 {
119 QByteArray byteArray;
120 QBuffer buffer(&byteArray);
121 instance->toImage().save(&buffer, "PNG");
122 const QString encodedString = QLatin1String("data:image/png;base64,") + QLatin1String(byteArray.toBase64());
123 const UString ustring((UChar*)encodedString.utf16(), encodedString.length());
124 return jsString(exec, ustring);
125 }
126 };
127
128 class QtPixmapToStringMethod : public QtPixmapRuntimeMethod {
129 public:
name()130 static const char* name() { return "toString"; }
invoke(ExecState * exec,QtPixmapInstance * instance)131 JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
132 {
133 return instance->valueOf(exec);
134 }
135 };
136
137 struct QtPixmapMetaData {
138 QtPixmapToDataUrlMethod toDataUrlMethod;
139 QtPixmapAssignToElementMethod assignToElementMethod;
140 QtPixmapToStringMethod toStringMethod;
141 QtPixmapHeightField heightField;
142 QtPixmapWidthField widthField;
143 QtPixmapClass cls;
144 } qt_pixmap_metaData;
145
146 // Derived RuntimeObject
147 class QtPixmapRuntimeObject : public RuntimeObject {
148 public:
149 QtPixmapRuntimeObject(ExecState*, JSGlobalObject*, PassRefPtr<Instance>);
150
151 static const ClassInfo s_info;
152
createStructure(JSGlobalData & globalData,JSValue prototype)153 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
154 {
155 return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
156 }
157
158 protected:
159 static const unsigned StructureFlags = RuntimeObject::StructureFlags | OverridesMarkChildren;
160 };
161
QtPixmapRuntimeObject(ExecState * exec,JSGlobalObject * globalObject,PassRefPtr<Instance> instance)162 QtPixmapRuntimeObject::QtPixmapRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr<Instance> instance)
163 : RuntimeObject(exec, globalObject, WebCore::deprecatedGetDOMStructure<QtPixmapRuntimeObject>(exec), instance)
164 {
165 }
166
167 const ClassInfo QtPixmapRuntimeObject::s_info = { "QtPixmapRuntimeObject", &RuntimeObject::s_info, 0, 0 };
168
QtPixmapClass()169 QtPixmapClass::QtPixmapClass()
170 {
171 }
172
173
getClass() const174 Class* QtPixmapInstance::getClass() const
175 {
176 return &qt_pixmap_metaData.cls;
177 }
178
getMethod(ExecState * exec,const Identifier & propertyName)179 JSValue QtPixmapInstance::getMethod(ExecState* exec, const Identifier& propertyName)
180 {
181 MethodList methodList = getClass()->methodsNamed(propertyName, this);
182 return new (exec) RuntimeMethod(exec, exec->lexicalGlobalObject(), WebCore::deprecatedGetDOMStructure<RuntimeMethod>(exec), propertyName, methodList);
183 }
184
invokeMethod(ExecState * exec,RuntimeMethod * runtimeMethod)185 JSValue QtPixmapInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod)
186 {
187 const MethodList& methods = *runtimeMethod->methods();
188
189 if (methods.size() == 1) {
190 QtPixmapRuntimeMethod* method = static_cast<QtPixmapRuntimeMethod*>(methods[0]);
191 return method->invoke(exec, this);
192 }
193 return jsUndefined();
194 }
195
methodsNamed(const Identifier & identifier,Instance *) const196 MethodList QtPixmapClass::methodsNamed(const Identifier& identifier, Instance*) const
197 {
198 MethodList methods;
199 if (identifier == QtPixmapToDataUrlMethod::name())
200 methods.append(&qt_pixmap_metaData.toDataUrlMethod);
201 else if (identifier == QtPixmapAssignToElementMethod::name())
202 methods.append(&qt_pixmap_metaData.assignToElementMethod);
203 else if (identifier == QtPixmapToStringMethod::name())
204 methods.append(&qt_pixmap_metaData.toStringMethod);
205 return methods;
206 }
207
fieldNamed(const Identifier & identifier,Instance *) const208 Field* QtPixmapClass::fieldNamed(const Identifier& identifier, Instance*) const
209 {
210 if (identifier == QtPixmapWidthField::name())
211 return &qt_pixmap_metaData.widthField;
212 if (identifier == QtPixmapHeightField::name())
213 return &qt_pixmap_metaData.heightField;
214 return 0;
215 }
216
getPropertyNames(ExecState * exec,PropertyNameArray & arr)217 void QtPixmapInstance::getPropertyNames(ExecState*exec, PropertyNameArray& arr)
218 {
219 arr.add(Identifier(exec, UString(QtPixmapToDataUrlMethod::name())));
220 arr.add(Identifier(exec, UString(QtPixmapAssignToElementMethod::name())));
221 arr.add(Identifier(exec, UString(QtPixmapToStringMethod::name())));
222 arr.add(Identifier(exec, UString(QtPixmapWidthField::name())));
223 arr.add(Identifier(exec, UString(QtPixmapHeightField::name())));
224 }
225
defaultValue(ExecState * exec,PreferredPrimitiveType ptype) const226 JSValue QtPixmapInstance::defaultValue(ExecState* exec, PreferredPrimitiveType ptype) const
227 {
228 if (ptype == PreferNumber) {
229 return jsBoolean(
230 (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()) && !(data.value<QImage>()).isNull())
231 || (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()) && !data.value<QPixmap>().isNull()));
232 }
233
234 if (ptype == PreferString)
235 return valueOf(exec);
236
237 return jsUndefined();
238 }
239
valueOf(ExecState * exec) const240 JSValue QtPixmapInstance::valueOf(ExecState* exec) const
241 {
242 const QString stringValue = QString::fromLatin1("[Qt Native Pixmap %1,%2]").arg(width()).arg(height());
243 UString ustring((UChar*)stringValue.utf16(), stringValue.length());
244 return jsString(exec, ustring);
245 }
246
QtPixmapInstance(PassRefPtr<RootObject> rootObj,const QVariant & d)247 QtPixmapInstance::QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& d)
248 :Instance(rootObj), data(d)
249 {
250 }
251
width() const252 int QtPixmapInstance::width() const
253 {
254 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
255 return data.value<QPixmap>().width();
256 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
257 return data.value<QImage>().width();
258 return 0;
259 }
260
height() const261 int QtPixmapInstance::height() const
262 {
263 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
264 return data.value<QPixmap>().height();
265 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
266 return data.value<QImage>().height();
267 return 0;
268 }
269
toPixmap()270 QPixmap QtPixmapInstance::toPixmap()
271 {
272 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
273 return data.value<QPixmap>();
274
275 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) {
276 const QPixmap pixmap = QPixmap::fromImage(data.value<QImage>());
277 data = QVariant::fromValue<QPixmap>(pixmap);
278 return pixmap;
279 }
280
281 return QPixmap();
282 }
283
toImage()284 QImage QtPixmapInstance::toImage()
285 {
286 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
287 return data.value<QImage>();
288
289 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) {
290 const QImage image = data.value<QPixmap>().toImage();
291 data = QVariant::fromValue<QImage>(image);
292 return image;
293 }
294
295 return QImage();
296 }
297
variantFromObject(JSObject * object,QMetaType::Type hint)298 QVariant QtPixmapInstance::variantFromObject(JSObject* object, QMetaType::Type hint)
299 {
300 if (!object)
301 goto returnEmptyVariant;
302
303 if (object->inherits(&JSHTMLImageElement::s_info)) {
304 JSHTMLImageElement* elementJSWrapper = static_cast<JSHTMLImageElement*>(object);
305 HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(elementJSWrapper->impl());
306
307 if (!imageElement)
308 goto returnEmptyVariant;
309
310 CachedImage* cachedImage = imageElement->cachedImage();
311 if (!cachedImage)
312 goto returnEmptyVariant;
313
314 Image* image = cachedImage->image();
315 if (!image)
316 goto returnEmptyVariant;
317
318 QPixmap* pixmap = image->nativeImageForCurrentFrame();
319 if (!pixmap)
320 goto returnEmptyVariant;
321
322 return (hint == static_cast<QMetaType::Type>(qMetaTypeId<QPixmap>()))
323 ? QVariant::fromValue<QPixmap>(*pixmap)
324 : QVariant::fromValue<QImage>(pixmap->toImage());
325 }
326
327 if (object->inherits(&QtPixmapRuntimeObject::s_info)) {
328 QtPixmapRuntimeObject* runtimeObject = static_cast<QtPixmapRuntimeObject*>(object);
329 QtPixmapInstance* instance = static_cast<QtPixmapInstance*>(runtimeObject->getInternalInstance());
330 if (!instance)
331 goto returnEmptyVariant;
332
333 if (hint == qMetaTypeId<QPixmap>())
334 return QVariant::fromValue<QPixmap>(instance->toPixmap());
335
336 if (hint == qMetaTypeId<QImage>())
337 return QVariant::fromValue<QImage>(instance->toImage());
338 }
339
340 returnEmptyVariant:
341 if (hint == qMetaTypeId<QPixmap>())
342 return QVariant::fromValue<QPixmap>(QPixmap());
343 if (hint == qMetaTypeId<QImage>())
344 return QVariant::fromValue<QImage>(QImage());
345 return QVariant();
346 }
347
newRuntimeObject(ExecState * exec)348 RuntimeObject* QtPixmapInstance::newRuntimeObject(ExecState* exec)
349 {
350 return new(exec) QtPixmapRuntimeObject(exec, exec->lexicalGlobalObject(), this);
351 }
352
createPixmapRuntimeObject(ExecState * exec,PassRefPtr<RootObject> root,const QVariant & data)353 JSObject* QtPixmapInstance::createPixmapRuntimeObject(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& data)
354 {
355 JSLock lock(SilenceAssertionsOnly);
356 RefPtr<QtPixmapInstance> instance = adoptRef(new QtPixmapInstance(root, data));
357 return instance->createRuntimeObject(exec);
358 }
359
canHandle(QMetaType::Type hint)360 bool QtPixmapInstance::canHandle(QMetaType::Type hint)
361 {
362 return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>();
363 }
364
365 }
366
367 }
368