• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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