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: 54 static const char* name() { return "width"; } 55 virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const 56 { 57 return jsNumber(static_cast<const QtPixmapInstance*>(instance)->width()); 58 } 59 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {} 60 }; 61 62 class QtPixmapHeightField : public Field { 63 public: 64 static const char* name() { return "height"; } 65 virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const 66 { 67 return jsNumber(static_cast<const QtPixmapInstance*>(instance)->height()); 68 } 69 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {} 70 }; 71 72 class QtPixmapRuntimeMethod : public Method { 73 public: 74 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: 85 static const char* name() { return "assignToHTMLImageElement"; } 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 107 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: 116 static const char* name() { return "toDataUrl"; } 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: 130 static const char* name() { return "toString"; } 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 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 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 169 QtPixmapClass::QtPixmapClass() 170 { 171 } 172 173 174 Class* QtPixmapInstance::getClass() const 175 { 176 return &qt_pixmap_metaData.cls; 177 } 178 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 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 196 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 208 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 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 226 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 240 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 247 QtPixmapInstance::QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& d) 248 :Instance(rootObj), data(d) 249 { 250 } 251 252 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 261 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 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 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 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 348 RuntimeObject* QtPixmapInstance::newRuntimeObject(ExecState* exec) 349 { 350 return new(exec) QtPixmapRuntimeObject(exec, exec->lexicalGlobalObject(), this); 351 } 352 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 360 bool QtPixmapInstance::canHandle(QMetaType::Type hint) 361 { 362 return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>(); 363 } 364 365 } 366 367 } 368