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 "DOMWindow.h" 24 #include "HTMLImageElement.h" 25 #include "HTMLNames.h" 26 #include "JSDOMBinding.h" 27 #include "JSDOMWindow.h" 28 #include "JSGlobalObject.h" 29 #include "JSHTMLImageElement.h" 30 #include "JSLock.h" 31 #include "ObjectPrototype.h" 32 #include "StillImageQt.h" 33 #include <QBuffer> 34 #include <QByteArray> 35 #include <QImage> 36 #include <QPixmap> 37 #include <QVariant> 38 #include <runtime_object.h> 39 #include <runtime_root.h> 40 41 using namespace WebCore; 42 namespace JSC { 43 44 namespace Bindings { 45 46 class QtPixmapClass : public Class { 47 public: 48 QtPixmapClass(); 49 virtual MethodList methodsNamed(const Identifier&, Instance*) const; 50 virtual Field* fieldNamed(const Identifier&, Instance*) const; 51 }; 52 53 54 class QtPixmapWidthField : public Field { 55 public: 56 static const char* name() { return "width"; } 57 virtual JSValue valueFromInstance(ExecState* exec, const Instance* pixmap) const 58 { 59 return jsNumber(exec, static_cast<const QtPixmapInstance*>(pixmap)->width()); 60 } 61 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {} 62 }; 63 class QtPixmapHeightField : public Field { 64 public: 65 static const char* name() { return "height"; } 66 virtual JSValue valueFromInstance(ExecState* exec, const Instance* inst) const 67 { 68 return jsNumber(exec, static_cast<const QtPixmapInstance*>(inst)->height()); 69 } 70 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {} 71 }; 72 73 class QtPixmapRuntimeMethod : public Method { 74 public: 75 virtual int numParameters() const 76 { 77 return 0; 78 } 79 virtual JSValue invoke(ExecState* exec, QVariant&, PassRefPtr<RootObject> root, QtPixmapInstance* inst) = 0; 80 81 }; 82 83 class QtPixmapCreateElementMethod : public QtPixmapRuntimeMethod { 84 public: 85 static const char* name() { return "toHTMLImageElement"; } 86 JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr<RootObject> root, QtPixmapInstance*) 87 { 88 QPixmap pxm; 89 if (v.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) { 90 pxm = QPixmap::fromImage(v.value<QImage>()); 91 v = QVariant::fromValue<QPixmap>(pxm); 92 } else 93 pxm = v.value<QPixmap>(); 94 95 Document* document = 0; 96 JSDOMGlobalObject* global = static_cast<JSDOMGlobalObject*>(root->globalObject()); 97 if (global) { 98 DOMWindow* dWindow = toDOMWindow(global); 99 if (dWindow) 100 document = dWindow->document(); 101 } 102 103 if (document) { 104 PassRefPtr<StillImage> img = WebCore::StillImage::create(pxm); 105 RefPtr<HTMLImageElement> image = new HTMLImageElement(HTMLNames::imgTag, document); 106 image->setCachedImage(new CachedImage(img.get())); 107 toJS(exec, global, document); 108 return asObject(toJS(exec, global, image.release())); 109 } 110 return jsUndefined(); 111 } 112 113 }; 114 115 class QtPixmapToDataUrlMethod : public QtPixmapRuntimeMethod { 116 public: 117 static const char* name() { return "toDataUrl"; } 118 JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr<RootObject> root, QtPixmapInstance*) 119 { 120 QImage image; 121 // for getting the data url, we always prefer the image. 122 if (v.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) { 123 image = v.value<QPixmap>().toImage(); 124 v = QVariant::fromValue<QImage>(image); 125 } else 126 image = v.value<QImage>(); 127 QByteArray ba; 128 QBuffer b(&ba); 129 image.save(&b, "PNG"); 130 const QString b64 = QString("data:image/png;base64,") + ba.toBase64(); 131 const UString ustring((UChar*)b64.utf16(), b64.length()); 132 return jsString(exec, ustring); 133 } 134 135 }; 136 137 class QtPixmapToStringMethod : public QtPixmapRuntimeMethod { 138 public: 139 static const char* name() { return "toString"; } 140 JSValue invoke(ExecState* exec, QVariant& v, PassRefPtr<RootObject> root, QtPixmapInstance* inst) 141 { 142 return inst->valueOf(exec); 143 } 144 145 }; 146 147 struct QtPixmapMetaData { 148 QtPixmapToDataUrlMethod toDataUrlMethod; 149 QtPixmapCreateElementMethod createElementMethod; 150 QtPixmapToStringMethod toStringMethod; 151 QtPixmapHeightField heightField; 152 QtPixmapWidthField widthField; 153 QtPixmapClass cls; 154 } qt_pixmap_metaData; 155 156 // Derived RuntimeObject 157 class QtPixmapRuntimeObjectImp : public RuntimeObjectImp { 158 public: 159 QtPixmapRuntimeObjectImp(ExecState*, PassRefPtr<Instance>); 160 161 static const ClassInfo s_info; 162 163 static PassRefPtr<Structure> createStructure(JSValue prototype) 164 { 165 return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); 166 } 167 168 protected: 169 static const unsigned StructureFlags = RuntimeObjectImp::StructureFlags | OverridesMarkChildren; 170 171 private: 172 virtual const ClassInfo* classInfo() const { return &s_info; } 173 }; 174 175 QtPixmapRuntimeObjectImp::QtPixmapRuntimeObjectImp(ExecState* exec, PassRefPtr<Instance> instance) 176 : RuntimeObjectImp(exec, WebCore::deprecatedGetDOMStructure<QtPixmapRuntimeObjectImp>(exec), instance) 177 { 178 } 179 180 const ClassInfo QtPixmapRuntimeObjectImp::s_info = { "QtPixmapRuntimeObject", &RuntimeObjectImp::s_info, 0, 0 }; 181 182 183 QtPixmapClass::QtPixmapClass() 184 { 185 } 186 187 188 Class* QtPixmapInstance::getClass() const 189 { 190 return &qt_pixmap_metaData.cls; 191 } 192 193 JSValue QtPixmapInstance::invokeMethod(ExecState* exec, const MethodList& methods, const ArgList& args) 194 { 195 if (methods.size() == 1) { 196 QtPixmapRuntimeMethod* mtd = static_cast<QtPixmapRuntimeMethod*>(methods[0]); 197 return mtd->invoke(exec, data, rootObject(), this); 198 } 199 return jsUndefined(); 200 } 201 202 MethodList QtPixmapClass::methodsNamed(const Identifier& identifier, Instance*) const 203 { 204 MethodList methods; 205 if (identifier == QtPixmapToDataUrlMethod::name()) 206 methods.append(&qt_pixmap_metaData.toDataUrlMethod); 207 else if (identifier == QtPixmapCreateElementMethod::name()) 208 methods.append(&qt_pixmap_metaData.createElementMethod); 209 else if (identifier == QtPixmapToStringMethod::name()) 210 methods.append(&qt_pixmap_metaData.toStringMethod); 211 return methods; 212 } 213 214 Field* QtPixmapClass::fieldNamed(const Identifier& identifier, Instance*) const 215 { 216 if (identifier == QtPixmapWidthField::name()) 217 return &qt_pixmap_metaData.widthField; 218 if (identifier == QtPixmapHeightField::name()) 219 return &qt_pixmap_metaData.heightField; 220 return 0; 221 } 222 223 void QtPixmapInstance::getPropertyNames(ExecState*exec, PropertyNameArray& arr) 224 { 225 arr.add(Identifier(exec, UString(QtPixmapToDataUrlMethod::name()))); 226 arr.add(Identifier(exec, UString(QtPixmapCreateElementMethod::name()))); 227 arr.add(Identifier(exec, UString(QtPixmapToStringMethod::name()))); 228 arr.add(Identifier(exec, UString(QtPixmapWidthField::name()))); 229 arr.add(Identifier(exec, UString(QtPixmapHeightField::name()))); 230 } 231 232 JSValue QtPixmapInstance::defaultValue(ExecState* exec, PreferredPrimitiveType ptype) const 233 { 234 if (ptype == PreferNumber) { 235 return jsBoolean( 236 (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()) && !(data.value<QImage>()).isNull()) 237 || (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()) && !data.value<QPixmap>().isNull())); 238 } 239 if (ptype == PreferString) 240 return valueOf(exec); 241 return jsUndefined(); 242 } 243 244 JSValue QtPixmapInstance::valueOf(ExecState* exec) const 245 { 246 const QString toStr = QString("[Qt Native Pixmap %1,%2]").arg(width()).arg(height()); 247 UString ustring((UChar*)toStr.utf16(), toStr.length()); 248 return jsString(exec, ustring); 249 } 250 251 QtPixmapInstance::QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& d) 252 :Instance(rootObj), data(d) 253 { 254 } 255 256 int QtPixmapInstance::width() const 257 { 258 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) 259 return data.value<QPixmap>().width(); 260 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) 261 return data.value<QImage>().width(); 262 return 0; 263 } 264 265 int QtPixmapInstance::height() const 266 { 267 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) 268 return data.value<QPixmap>().height(); 269 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) 270 return data.value<QImage>().height(); 271 return 0; 272 } 273 274 QPixmap QtPixmapInstance::toPixmap() 275 { 276 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) 277 return data.value<QPixmap>(); 278 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) { 279 const QPixmap pxm = QPixmap::fromImage(data.value<QImage>()); 280 data = QVariant::fromValue<QPixmap>(pxm); 281 return pxm; 282 } 283 return QPixmap(); 284 285 } 286 287 QImage QtPixmapInstance::toImage() 288 { 289 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) 290 return data.value<QImage>(); 291 if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) { 292 const QImage img = data.value<QPixmap>().toImage(); 293 data = QVariant::fromValue<QImage>(img); 294 return img; 295 } 296 return QImage(); 297 } 298 299 QVariant QtPixmapInstance::variantFromObject(JSObject* object, QMetaType::Type hint) 300 { 301 if (!object) { 302 if (hint == qMetaTypeId<QPixmap>()) 303 return QVariant::fromValue<QPixmap>(QPixmap()); 304 if (hint == qMetaTypeId<QImage>()) 305 return QVariant::fromValue<QImage>(QImage()); 306 } else if (object->inherits(&JSHTMLImageElement::s_info)) { 307 JSHTMLImageElement* el = static_cast<JSHTMLImageElement*>(object); 308 HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(el->impl()); 309 if (imageElement) { 310 CachedImage* cImg = imageElement->cachedImage(); 311 if (cImg) { 312 Image* img = cImg->image(); 313 if (img) { 314 QPixmap* pxm = img->nativeImageForCurrentFrame(); 315 if (pxm) { 316 return (hint == static_cast<QMetaType::Type>(qMetaTypeId<QPixmap>())) 317 ? QVariant::fromValue<QPixmap>(*pxm) 318 : QVariant::fromValue<QImage>(pxm->toImage()); 319 } 320 } 321 } 322 } 323 } else if (object->inherits(&QtPixmapRuntimeObjectImp::s_info)) { 324 QtPixmapRuntimeObjectImp* imp = static_cast<QtPixmapRuntimeObjectImp*>(object); 325 QtPixmapInstance* inst = static_cast<QtPixmapInstance*>(imp->getInternalInstance()); 326 if (inst) { 327 if (hint == qMetaTypeId<QPixmap >()) 328 return QVariant::fromValue<QPixmap>(inst->toPixmap()); 329 if (hint == qMetaTypeId<QImage>()) 330 return QVariant::fromValue<QImage>(inst->toImage()); 331 } 332 } 333 return 0; 334 } 335 JSObject* QtPixmapInstance::createRuntimeObject(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& data) 336 { 337 JSLock lock(SilenceAssertionsOnly); 338 return new(exec) QtPixmapRuntimeObjectImp(exec, new QtPixmapInstance(root, data)); 339 } 340 341 bool QtPixmapInstance::canHandle(QMetaType::Type hint) 342 { 343 return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>(); 344 } 345 346 } 347 348 } 349