File indexing completed on 2024-04-28 15:23:07

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 2004 Apple Computer, Inc.
0004  *  Copyright (C) 2005 Zack Rusin <zack@kde.org>
0005  *  Copyright (C) 2007, 2008 Maksim Orlovich <maksim@kde.org>
0006  *
0007  *  This library is free software; you can redistribute it and/or
0008  *  modify it under the terms of the GNU Lesser General Public
0009  *  License as published by the Free Software Foundation; either
0010  *  version 2 of the License, or (at your option) any later version.
0011  *
0012  *  This library is distributed in the hope that it will be useful,
0013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  *  Lesser General Public License for more details.
0016  *
0017  *  You should have received a copy of the GNU Lesser General Public
0018  *  License along with this library; if not, write to the Free Software
0019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0020  */
0021 
0022 #include "kjs_context2d.h"
0023 
0024 
0025 #include <misc/loader.h>
0026 #include <dom/dom_exception.h>
0027 #include <xml/dom2_eventsimpl.h>
0028 #include <xml/dom_textimpl.h>
0029 #include <html/html_baseimpl.h>
0030 #include <html/html_blockimpl.h>
0031 #include <html/html_canvasimpl.h>
0032 #include <html/html_documentimpl.h>
0033 #include <html/html_formimpl.h>
0034 #include <html/html_headimpl.h>
0035 #include <html/html_imageimpl.h>
0036 #include <html/html_inlineimpl.h>
0037 #include <html/html_listimpl.h>
0038 #include <html/html_objectimpl.h>
0039 #include <html/html_tableimpl.h>
0040 
0041 #include <imload/imagemanager.h>
0042 
0043 #include <khtml_part.h>
0044 #include <khtmlview.h>
0045 
0046 #include "kjs_css.h"
0047 #include "kjs_window.h"
0048 #include "kjs_events.h"
0049 #include "kjs_proxy.h"
0050 #include <kjs/operations.h>
0051 
0052 #include <rendering/render_canvasimage.h>
0053 #include <rendering/render_object.h>
0054 #include <rendering/render_layer.h>
0055 
0056 #include "khtml_debug.h"
0057 
0058 #include <css/cssparser.h>
0059 #include <css/css_stylesheetimpl.h>
0060 #include <css/css_ruleimpl.h>
0061 
0062 using namespace DOM;
0063 
0064 #include "kjs_context2d.lut.h"
0065 
0066 namespace KJS
0067 {
0068 
0069 ////////////////////// Context2D Object ////////////////////////
0070 
0071 KJS_DEFINE_PROTOTYPE(Context2DProto)
0072 KJS_IMPLEMENT_PROTOFUNC(Context2DFunction)
0073 KJS_IMPLEMENT_PROTOTYPE("CanvasRenderingContext2DProto", Context2DProto, Context2DFunction, ObjectPrototype)
0074 
0075 /*
0076    @begin Context2DProtoTable 48
0077    #
0078    # state ops
0079    save                     Context2D::Save                        DontDelete|Function 0
0080    restore                  Context2D::Restore                     DontDelete|Function 0
0081    #
0082    # transformations
0083    scale                    Context2D::Scale                       DontDelete|Function 2
0084    rotate                   Context2D::Rotate                      DontDelete|Function 2
0085    translate                Context2D::Translate                   DontDelete|Function 1
0086    transform                Context2D::Transform                   DontDelete|Function 6
0087    setTransform             Context2D::SetTransform                DontDelete|Function 6
0088    #
0089    # colors and styles
0090    createLinearGradient     Context2D::CreateLinearGradient        DontDelete|Function 4
0091    createRadialGradient     Context2D::CreateRadialGradient        DontDelete|Function 6
0092    createPattern            Context2D::CreatePattern               DontDelete|Function 2
0093    #
0094    # rectangle ops
0095    clearRect                Context2D::ClearRect                   DontDelete|Function 4
0096    fillRect                 Context2D::FillRect                    DontDelete|Function 4
0097    strokeRect               Context2D::StrokeRect                  DontDelete|Function 4
0098    #
0099    # paths
0100    beginPath                Context2D::BeginPath                   DontDelete|Function 0
0101    closePath                Context2D::ClosePath                   DontDelete|Function 0
0102    moveTo                   Context2D::MoveTo                      DontDelete|Function 2
0103    lineTo                   Context2D::LineTo                      DontDelete|Function 2
0104    quadraticCurveTo         Context2D::QuadraticCurveTo            DontDelete|Function 4
0105    bezierCurveTo            Context2D::BezierCurveTo               DontDelete|Function 6
0106    arcTo                    Context2D::ArcTo                       DontDelete|Function 5
0107    rect                     Context2D::Rect                        DontDelete|Function 4
0108    arc                      Context2D::Arc                         DontDelete|Function 6
0109    fill                     Context2D::Fill                        DontDelete|Function 0
0110    isPointInPath            Context2D::IsPointInPath               DontDelete|Function 2
0111    stroke                   Context2D::Stroke                      DontDelete|Function 0
0112    clip                     Context2D::Clip                        DontDelete|Function 0
0113    #
0114    # images. Lots of overloading here!
0115    drawImage                Context2D::DrawImage                   DontDelete|Function 3
0116    #
0117    # pixel ops.
0118    getImageData             Context2D::GetImageData                DontDelete|Function 4
0119    putImageData             Context2D::PutImageData                DontDelete|Function 3
0120    createImageData          Context2D::CreateImageData             DontDelete|Function 2
0121    @end
0122 */
0123 
0124 IMPLEMENT_PSEUDO_CONSTRUCTOR(Context2DPseudoCtor, "CanvasRenderingContext2D", Context2DProto)
0125 
0126 Context2D::Context2D(ExecState *exec, DOM::CanvasContext2DImpl *ctx):
0127     WrapperBase(Context2DProto::self(exec), ctx)
0128 {}
0129 
0130 // Checks count and sets an exception if needed
0131 static bool enoughArguments(ExecState *exec, const List &args, int limit)
0132 {
0133     if (args.size() < limit) {
0134         setDOMException(exec, DOMException::NOT_SUPPORTED_ERR);
0135         return false;
0136     }
0137     return true;
0138 }
0139 
0140 // Verifies that a float value is not NaN or a plus/minus infinity (unless infOK)
0141 static bool valFloatOK(ExecState *exec, const JSValue *v, bool infOK)
0142 {
0143     float val = v->toFloat(exec);
0144     if (KJS::isNaN(val) || (!infOK && KJS::isInf(val))) {
0145         setDOMException(exec, DOMException::NOT_SUPPORTED_ERR);
0146         return false;
0147     }
0148     return true;
0149 }
0150 
0151 // Verifies that float arguments are not NaN or a plus/minus infinity (unless infOK)
0152 static bool argFloatsOK(ExecState *exec, const List &args, int minArg, int maxArg, bool infOK)
0153 {
0154     for (int c = minArg; c <= maxArg; ++c) {
0155         if (!valFloatOK(exec, args[c], infOK)) {
0156             return false;
0157         }
0158     }
0159     return true;
0160 }
0161 
0162 // Checks if the JSValue is Inf or NaN
0163 static bool argFloatIsInforNaN(ExecState *exec, const JSValue *v)
0164 {
0165     float val = v->toFloat(exec);
0166     if (KJS::isNaN(val) || KJS::isInf(val)) {
0167         return true;
0168     }
0169     return false;
0170 }
0171 
0172 // Checks if one the arguments if Inf or NaN
0173 static bool argumentsContainInforNaN(ExecState *exec, const List &args, int minArg, int maxArg)
0174 {
0175     for (int c = minArg; c <= maxArg; ++c) {
0176         if (argFloatIsInforNaN(exec, args[c])) {
0177             return true;
0178         }
0179     }
0180     return false;
0181 }
0182 
0183 // HTML5-style checking
0184 #define KJS_REQUIRE_ARGS(n) do { if (!enoughArguments(exec, args,n)) return jsUndefined(); } while(0);
0185 #define KJS_CHECK_FLOAT_ARGS(min,max) do { if (!argFloatsOK(exec, args, min, max, false )) return jsUndefined(); } while(0);
0186 #define KJS_CHECK_FLOAT_OR_INF_ARGS(min,max) do { if (!argFloatsOK(exec, args, min, max, true)) return jsUndefined(); } while(0);
0187 #define KJS_CHECK_FLOAT_VAL(v) if (!valFloatOK(exec, v, false)) return;
0188 
0189 // Unlike the above checks, ignore the invalid(Inf/NaN) values,
0190 // without throwing an exception
0191 #define KJS_CHECK_FLOAT_IGNORE_INVALID(v) do { if (argFloatIsInforNaN(exec, v)) return; } while(0)
0192 #define KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(min,max) do { if (argumentsContainInforNaN(exec, args, min, max)) return jsUndefined(); } while(0)
0193 
0194 JSValue *KJS::Context2DFunction::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
0195 {
0196     KJS_CHECK_THIS(Context2D, thisObj);
0197 
0198 #ifdef KJS_VERBOSE
0199     qCDebug(KHTML_LOG) << "KJS::Context2DFunction::callAsFunction " << functionName().qstring();
0200 #endif
0201 
0202     Context2D *jsContextObject = static_cast<KJS::Context2D *>(thisObj);
0203     CanvasContext2DImpl *ctx   = jsContextObject->impl();
0204     DOMExceptionTranslator exception(exec);
0205 
0206     switch (id) {
0207     // State ops
0208     /////////////
0209     case Context2D::Save: {
0210         ctx->save();
0211         break;
0212     }
0213 
0214     case Context2D::Restore: {
0215         ctx->restore();
0216         break;
0217     }
0218 
0219     // Transform ops. These have NaN inf handled specially in the impl
0220     case Context2D::Scale: {
0221         KJS_REQUIRE_ARGS(2);
0222         KJS_CHECK_FLOAT_OR_INF_ARGS(0, 1);
0223 
0224         ctx->scale(args[0]->toFloat(exec), args[1]->toFloat(exec));
0225         break;
0226     }
0227 
0228     case Context2D::Rotate: {
0229         KJS_REQUIRE_ARGS(1);
0230         // Rotate actually rejects NaN/infinity as well
0231         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 0);
0232 
0233         ctx->rotate(args[0]->toFloat(exec));
0234         break;
0235     }
0236 
0237     case Context2D::Translate: {
0238         KJS_REQUIRE_ARGS(2);
0239         KJS_CHECK_FLOAT_OR_INF_ARGS(0, 1);
0240 
0241         ctx->translate(args[0]->toFloat(exec), args[1]->toFloat(exec));
0242         break;
0243     }
0244 
0245     case Context2D::Transform: {
0246         KJS_REQUIRE_ARGS(6);
0247         KJS_CHECK_FLOAT_OR_INF_ARGS(0, 5);
0248 
0249         ctx->transform(args[0]->toFloat(exec), args[1]->toFloat(exec),
0250                        args[2]->toFloat(exec), args[3]->toFloat(exec),
0251                        args[4]->toFloat(exec), args[5]->toFloat(exec));
0252 
0253         break;
0254     }
0255 
0256     case Context2D::SetTransform: {
0257         KJS_REQUIRE_ARGS(6);
0258         KJS_CHECK_FLOAT_OR_INF_ARGS(0, 5);
0259 
0260         ctx->setTransform(args[0]->toFloat(exec), args[1]->toFloat(exec),
0261                           args[2]->toFloat(exec), args[3]->toFloat(exec),
0262                           args[4]->toFloat(exec), args[5]->toFloat(exec));
0263         break;
0264     }
0265 
0266     // Composition state is properties --- not in prototype
0267 
0268     // Color and style info..
0269     case Context2D::CreateLinearGradient: {
0270         KJS_REQUIRE_ARGS(4);
0271         KJS_CHECK_FLOAT_ARGS(0, 3);
0272 
0273         CanvasGradientImpl *grad = ctx->createLinearGradient(
0274                                        args[0]->toFloat(exec), args[1]->toFloat(exec),
0275                                        args[2]->toFloat(exec), args[3]->toFloat(exec));
0276         return getWrapper<CanvasGradient>(exec, grad);
0277     }
0278 
0279     case Context2D::CreateRadialGradient: {
0280         KJS_REQUIRE_ARGS(6);
0281         KJS_CHECK_FLOAT_ARGS(0, 5);
0282 
0283         CanvasGradientImpl *grad = ctx->createRadialGradient(
0284                                        args[0]->toFloat(exec), args[1]->toFloat(exec),
0285                                        args[2]->toFloat(exec), args[3]->toFloat(exec),
0286                                        args[4]->toFloat(exec), args[5]->toFloat(exec),
0287                                        exception);
0288 
0289         return getWrapper<CanvasGradient>(exec, grad);
0290     }
0291 
0292     case Context2D::CreatePattern: {
0293         KJS_REQUIRE_ARGS(2);
0294 
0295         ElementImpl *el = toElement(args[0]);
0296         if (!el) {
0297             setDOMException(exec, DOMException::TYPE_MISMATCH_ERR);
0298             return jsUndefined();
0299         }
0300 
0301         CanvasPatternImpl *pat = ctx->createPattern(el, valueToStringWithNullCheck(exec, args[1]),
0302                                  exception);
0303 
0304         return getWrapper<CanvasPattern>(exec, pat);
0305     }
0306 
0307     // Line properties are all... properties!
0308 
0309     // Rectangle ops
0310     case Context2D::ClearRect: {
0311         KJS_REQUIRE_ARGS(4);
0312         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 3);
0313 
0314         ctx->clearRect(args[0]->toFloat(exec), args[1]->toFloat(exec),
0315                        args[2]->toFloat(exec), args[3]->toFloat(exec),
0316                        exception);
0317 
0318         break;
0319     }
0320 
0321     case Context2D::FillRect: {
0322         KJS_REQUIRE_ARGS(4);
0323         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 3);
0324 
0325         ctx->fillRect(args[0]->toFloat(exec), args[1]->toFloat(exec),
0326                       args[2]->toFloat(exec), args[3]->toFloat(exec),
0327                       exception);
0328 
0329         break;
0330     }
0331 
0332     case Context2D::StrokeRect: {
0333         KJS_REQUIRE_ARGS(4);
0334         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 3);
0335 
0336         ctx->strokeRect(args[0]->toFloat(exec), args[1]->toFloat(exec),
0337                         args[2]->toFloat(exec), args[3]->toFloat(exec),
0338                         exception);
0339 
0340         break;
0341     }
0342 
0343     // Path ops
0344     case Context2D::BeginPath: {
0345         ctx->beginPath();
0346         break;
0347     }
0348 
0349     case Context2D::ClosePath: {
0350         ctx->closePath();
0351         break;
0352     }
0353 
0354     case Context2D::MoveTo: {
0355         KJS_REQUIRE_ARGS(2);
0356         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 1);
0357 
0358         ctx->moveTo(args[0]->toFloat(exec), args[1]->toFloat(exec));
0359         break;
0360     }
0361 
0362     case Context2D::LineTo: {
0363         KJS_REQUIRE_ARGS(2);
0364         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 1);
0365 
0366         ctx->lineTo(args[0]->toFloat(exec), args[1]->toFloat(exec));
0367         break;
0368     }
0369 
0370     case Context2D::QuadraticCurveTo: {
0371         KJS_REQUIRE_ARGS(4);
0372         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 3);
0373 
0374         ctx->quadraticCurveTo(args[0]->toFloat(exec), args[1]->toFloat(exec),
0375                               args[2]->toFloat(exec), args[3]->toFloat(exec));
0376         break;
0377     }
0378 
0379     case Context2D::BezierCurveTo: {
0380         KJS_REQUIRE_ARGS(6);
0381         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 5);
0382 
0383         ctx->bezierCurveTo(args[0]->toFloat(exec), args[1]->toFloat(exec),
0384                            args[2]->toFloat(exec), args[3]->toFloat(exec),
0385                            args[4]->toFloat(exec), args[5]->toFloat(exec));
0386         break;
0387     }
0388 
0389     case Context2D::ArcTo: {
0390         KJS_REQUIRE_ARGS(5);
0391         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 4);
0392 
0393         ctx->arcTo(args[0]->toFloat(exec), args[1]->toFloat(exec),
0394                    args[2]->toFloat(exec), args[3]->toFloat(exec),
0395                    args[4]->toFloat(exec), exception);
0396         break;
0397     }
0398 
0399     case Context2D::Rect: {
0400         KJS_REQUIRE_ARGS(4);
0401         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 3);
0402 
0403         ctx->rect(args[0]->toFloat(exec), args[1]->toFloat(exec),
0404                   args[2]->toFloat(exec), args[3]->toFloat(exec),
0405                   exception);
0406         break;
0407     }
0408 
0409     case Context2D::Arc: {
0410         KJS_REQUIRE_ARGS(6);
0411         KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(0, 5);
0412 
0413         ctx->arc(args[0]->toFloat(exec), args[1]->toFloat(exec),
0414                  args[2]->toFloat(exec), args[3]->toFloat(exec),
0415                  args[4]->toFloat(exec), args[5]->toBoolean(exec),
0416                  exception);
0417         break;
0418     }
0419 
0420     case Context2D::Fill: {
0421         ctx->fill();
0422         break;
0423     }
0424 
0425     case Context2D::Stroke: {
0426         ctx->stroke();
0427         break;
0428     }
0429 
0430     case Context2D::Clip: {
0431         ctx->clip();
0432         break;
0433     }
0434 
0435     case Context2D::IsPointInPath: {
0436         KJS_REQUIRE_ARGS(2);
0437         if (argumentsContainInforNaN(exec, args, 0, 1)) {
0438             return jsBoolean(false);
0439         }
0440         return jsBoolean(ctx->isPointInPath(args[0]->toFloat(exec),
0441                                             args[1]->toFloat(exec)));
0442     }
0443 
0444     case Context2D::DrawImage: {
0445         ElementImpl *el = toElement(args[0]);
0446         if (!el) {
0447             setDOMException(exec, DOMException::TYPE_MISMATCH_ERR);
0448             break;
0449         }
0450 
0451         if (args.size() < 3) {
0452             setDOMException(exec, DOMException::NOT_SUPPORTED_ERR);
0453             break;
0454         }
0455 
0456         if (args.size() < 5) { // 3 or 4 arguments
0457             KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(1, 2);
0458             ctx->drawImage(el,
0459                            args[1]->toFloat(exec),
0460                            args[2]->toFloat(exec),
0461                            exception);
0462         } else if (args.size() < 9) { // 5 through 9 arguments
0463             KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(1, 4);
0464             ctx->drawImage(el,
0465                            args[1]->toFloat(exec),
0466                            args[2]->toFloat(exec),
0467                            args[3]->toFloat(exec),
0468                            args[4]->toFloat(exec),
0469                            exception);
0470         } else  { // 9 or more arguments
0471             KJS_CHECK_FLOAT_ARGUMENTS_IGNORE_INVALID(1, 8);
0472             ctx->drawImage(el,
0473                            args[1]->toFloat(exec),
0474                            args[2]->toFloat(exec),
0475                            args[3]->toFloat(exec),
0476                            args[4]->toFloat(exec),
0477                            args[5]->toFloat(exec),
0478                            args[6]->toFloat(exec),
0479                            args[7]->toFloat(exec),
0480                            args[8]->toFloat(exec),
0481                            exception);
0482         }
0483         break;
0484     }
0485     case Context2D::GetImageData: {
0486         KJS_REQUIRE_ARGS(4);
0487         KJS_CHECK_FLOAT_ARGS(0, 3);
0488         CanvasImageDataImpl *id = ctx->getImageData(args[0]->toFloat(exec), args[1]->toFloat(exec),
0489                                   args[2]->toFloat(exec), args[3]->toFloat(exec),
0490                                   exception);
0491         return getWrapper<CanvasImageData>(exec, id);
0492         break;
0493     }
0494     case Context2D::PutImageData: {
0495         KJS_REQUIRE_ARGS(3);
0496         KJS_CHECK_FLOAT_ARGS(1, 2);
0497         SharedPtr<CanvasImageDataImpl> id = toCanvasImageData(exec, args[0]); // may need to delete..
0498         ctx->putImageData(id.get(), args[1]->toFloat(exec), args[2]->toFloat(exec), exception);
0499         break;
0500     }
0501     case Context2D::CreateImageData: {
0502         KJS_REQUIRE_ARGS(2);
0503         KJS_CHECK_FLOAT_ARGS(0, 1);
0504         CanvasImageDataImpl *id = ctx->createImageData(args[0]->toFloat(exec),
0505                                   args[1]->toFloat(exec),
0506                                   exception);
0507         return getWrapper<CanvasImageData>(exec, id);
0508     }
0509 
0510     }
0511 
0512     return jsUndefined();
0513 }
0514 
0515 const ClassInfo Context2D::info = { "CanvasRenderingContext2D", nullptr, &Context2DTable, nullptr };
0516 
0517 /*
0518    @begin Context2DTable 11
0519    canvas                   Context2D::Canvas                      DontDelete|ReadOnly
0520    #
0521    # compositing
0522    globalAlpha              Context2D::GlobalAlpha                 DontDelete
0523    globalCompositeOperation Context2D::GlobalCompositeOperation    DontDelete
0524    #
0525    # colors and styles
0526    strokeStyle              Context2D::StrokeStyle                 DontDelete
0527    fillStyle                Context2D::FillStyle                   DontDelete
0528    #
0529    # line drawing properties
0530    lineWidth                Context2D::LineWidth                   DontDelete
0531    lineCap                  Context2D::LineCap                     DontDelete
0532    lineJoin                 Context2D::LineJoin                    DontDelete
0533    miterLimit               Context2D::MiterLimit                  DontDelete
0534    # shadow properties
0535    shadowOffsetX            Context2D::ShadowOffsetX               DontDelete
0536    shadowOffsetY            Context2D::ShadowOffsetY               DontDelete
0537    shadowBlur               Context2D::ShadowBlur                  DontDelete
0538    shadowColor              Context2D::ShadowColor                 DontDelete
0539    @end
0540 */
0541 
0542 bool Context2D::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0543 {
0544     return getStaticValueSlot<Context2D, DOMObject>(exec, &Context2DTable, this, propertyName, slot);
0545 }
0546 
0547 static JSValue *encodeStyle(ExecState *exec, CanvasStyleBaseImpl *style)
0548 {
0549     switch (style->type()) {
0550     case CanvasStyleBaseImpl::Color:
0551         return jsString(UString(static_cast<CanvasColorImpl *>(style)->toString()));
0552     case CanvasStyleBaseImpl::Gradient:
0553         return getWrapper<CanvasGradient>(exec, static_cast<CanvasGradientImpl *>(style));
0554     case CanvasStyleBaseImpl::Pattern:
0555         return getWrapper<CanvasPattern>(exec, static_cast<CanvasPatternImpl *>(style));
0556     }
0557 
0558     return jsNull();
0559 }
0560 
0561 // ### TODO: test how non-string things are handled in other browsers.
0562 static CanvasStyleBaseImpl *decodeStyle(ExecState *exec, JSValue *v)
0563 {
0564     if (v->isObject() && static_cast<JSObject *>(v)->inherits(&CanvasGradient::info)) {
0565         return static_cast<CanvasGradient *>(v)->impl();
0566     } else if (v->isObject() && static_cast<JSObject *>(v)->inherits(&CanvasPattern::info)) {
0567         return static_cast<CanvasPattern *>(v)->impl();
0568     } else {
0569         return CanvasColorImpl::fromString(v->toString(exec).domString());
0570     }
0571 }
0572 
0573 JSValue *Context2D::getValueProperty(ExecState *exec, int token) const
0574 {
0575     const CanvasContext2DImpl *ctx = impl();
0576     switch (token) {
0577     case Canvas:
0578         return getDOMNode(exec, ctx->canvas());
0579 
0580     case GlobalAlpha:
0581         return jsNumber(ctx->globalAlpha());
0582 
0583     case GlobalCompositeOperation:
0584         return jsString(ctx->globalCompositeOperation());
0585 
0586     case StrokeStyle:
0587         return encodeStyle(exec, ctx->strokeStyle());
0588 
0589     case FillStyle:
0590         return encodeStyle(exec, ctx->fillStyle());
0591 
0592     case LineWidth:
0593         return jsNumber(ctx->lineWidth());
0594 
0595     case LineCap:
0596         return jsString(ctx->lineCap());
0597 
0598     case LineJoin:
0599         return jsString(ctx->lineJoin());
0600 
0601     case MiterLimit:
0602         return jsNumber(ctx->miterLimit());
0603 
0604     case ShadowOffsetX:
0605         return jsNumber(ctx->shadowOffsetX());
0606 
0607     case ShadowOffsetY:
0608         return jsNumber(ctx->shadowOffsetY());
0609 
0610     case ShadowBlur:
0611         return jsNumber(ctx->shadowBlur());
0612 
0613     case ShadowColor:
0614         return jsString(ctx->shadowColor());
0615 
0616     default:
0617         assert(0);
0618         return jsUndefined();
0619     }
0620 }
0621 
0622 void Context2D::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
0623 {
0624     lookupPut<Context2D, DOMObject>(exec, propertyName, value, attr, &Context2DTable, this);
0625 }
0626 
0627 void Context2D::putValueProperty(ExecState *exec, int token, JSValue *value, int /*attr*/)
0628 {
0629     CanvasContext2DImpl *ctx = impl();
0630     switch (token) {
0631     case GlobalAlpha:
0632         KJS_CHECK_FLOAT_IGNORE_INVALID(value);
0633         ctx->setGlobalAlpha(value->toFloat(exec));
0634         break;
0635     case GlobalCompositeOperation:
0636         ctx->setGlobalCompositeOperation(value->toString(exec).domString());
0637         break;
0638     case StrokeStyle:
0639         ctx->setStrokeStyle(decodeStyle(exec, value));
0640         break;
0641     case FillStyle:
0642         ctx->setFillStyle(decodeStyle(exec, value));
0643         break;
0644     case LineWidth:
0645         KJS_CHECK_FLOAT_IGNORE_INVALID(value);
0646         ctx->setLineWidth(value->toFloat(exec));
0647         break;
0648     case LineCap:
0649         ctx->setLineCap(value->toString(exec).domString());
0650         break;
0651     case LineJoin:
0652         ctx->setLineJoin(value->toString(exec).domString());
0653         break;
0654     case MiterLimit:
0655         KJS_CHECK_FLOAT_IGNORE_INVALID(value);
0656         ctx->setMiterLimit(value->toFloat(exec));
0657         break;
0658     case ShadowOffsetX:
0659         KJS_CHECK_FLOAT_IGNORE_INVALID(value);
0660         ctx->setShadowOffsetX(value->toFloat(exec));
0661         break;
0662     case ShadowOffsetY:
0663         KJS_CHECK_FLOAT_IGNORE_INVALID(value);
0664         ctx->setShadowOffsetY(value->toFloat(exec));
0665         break;
0666     case ShadowBlur:
0667         KJS_CHECK_FLOAT_IGNORE_INVALID(value);
0668         ctx->setShadowBlur(value->toFloat(exec));
0669         break;
0670     case ShadowColor:
0671         ctx->setShadowColor(value->toString(exec).domString());
0672         break;
0673     default: {
0674     } // huh?
0675     }
0676 }
0677 
0678 ////////////////////// CanvasGradient Object ////////////////////////
0679 const ClassInfo KJS::CanvasGradient::info = { "CanvasGradient", nullptr, nullptr, nullptr };
0680 
0681 KJS_DEFINE_PROTOTYPE(CanvasGradientProto)
0682 KJS_IMPLEMENT_PROTOFUNC(CanvasGradientFunction)
0683 KJS_IMPLEMENT_PROTOTYPE("CanvasGradientProto", CanvasGradientProto, CanvasGradientFunction, ObjectPrototype)
0684 
0685 /*
0686    @begin CanvasGradientProtoTable 1
0687    addColorStop             CanvasGradient::AddColorStop                DontDelete|Function 2
0688    @end
0689 */
0690 
0691 JSValue *CanvasGradientFunction::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
0692 {
0693     KJS_CHECK_THIS(CanvasGradient, thisObj);
0694 
0695     CanvasGradientImpl *impl = static_cast<KJS::CanvasGradient *>(thisObj)->impl();
0696 
0697     DOMExceptionTranslator exception(exec);
0698     switch (id) {
0699     case CanvasGradient::AddColorStop:
0700         KJS_REQUIRE_ARGS(2);
0701         impl->addColorStop(args[0]->toFloat(exec), args[1]->toString(exec).domString(), exception);
0702         break;
0703     default:
0704         assert(0);
0705     }
0706 
0707     return jsUndefined();
0708 }
0709 
0710 CanvasGradient::CanvasGradient(ExecState *exec, DOM::CanvasGradientImpl *impl) :
0711     WrapperBase(CanvasGradientProto::self(exec), impl)
0712 {}
0713 
0714 ////////////////////// CanvasPattern Object ////////////////////////
0715 
0716 const ClassInfo CanvasPattern::info = { "CanvasPattern", nullptr, nullptr, nullptr };
0717 
0718 // Provide an empty prototype in case people want to hack it
0719 KJS_DEFINE_PROTOTYPE(CanvasPatternProto)
0720 KJS_IMPLEMENT_PROTOFUNC(CanvasPatternFunction)
0721 KJS_IMPLEMENT_PROTOTYPE("CanvasPatternProto", CanvasPatternProto, CanvasPatternFunction, ObjectPrototype)
0722 
0723 /*
0724    @begin CanvasPatternProtoTable 0
0725    @end
0726 */
0727 
0728 JSValue *CanvasPatternFunction::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
0729 {
0730     Q_UNUSED(exec);
0731     Q_UNUSED(thisObj);
0732     Q_UNUSED(args);
0733     assert(0);
0734     return nullptr;
0735 }
0736 
0737 CanvasPattern::CanvasPattern(ExecState *exec, DOM::CanvasPatternImpl *impl) :
0738     WrapperBase(CanvasPatternProto::self(exec), impl)
0739 {}
0740 
0741 ////////////////////// CanvasImageData[Array] Object /////////////////
0742 
0743 const ClassInfo CanvasImageData::info = { "ImageData", nullptr, nullptr, nullptr };
0744 
0745 CanvasImageData::CanvasImageData(ExecState *exec, DOM::CanvasImageDataImpl *impl) :
0746     WrapperBase(exec->lexicalInterpreter()->builtinObjectPrototype(), impl)
0747 {
0748     data = new CanvasImageDataArray(exec, this);
0749     // Set out properties from the image info..
0750     putDirect("width",  jsNumber(impl->width()),  DontDelete | ReadOnly);
0751     putDirect("height", jsNumber(impl->height()), DontDelete | ReadOnly);
0752     putDirect("data",   data, DontDelete | ReadOnly);
0753 }
0754 
0755 void CanvasImageData::mark()
0756 {
0757     JSObject::mark();
0758     if (!data->marked()) {
0759         data->mark();
0760     }
0761 }
0762 
0763 JSObject *CanvasImageData::valueClone(Interpreter *targetCtx) const
0764 {
0765     return static_cast<JSObject *>(getWrapper<CanvasImageData>(targetCtx->globalExec(), impl()->clone()));
0766 }
0767 
0768 const ClassInfo CanvasImageDataArray::info = { "ImageDataArray", nullptr, nullptr, nullptr };
0769 
0770 CanvasImageDataArray::CanvasImageDataArray(ExecState *exec, CanvasImageData *p) :
0771     JSObject(exec->lexicalInterpreter()->builtinArrayPrototype()), parent(p)
0772 {
0773     size = p->impl()->width() * p->impl()->height() * 4;
0774     putDirect(exec->propertyNames().length, jsNumber(size), DontDelete | ReadOnly);
0775 }
0776 
0777 void CanvasImageDataArray::mark()
0778 {
0779     JSObject::mark();
0780     if (!parent->marked()) {
0781         parent->mark();
0782     }
0783 }
0784 
0785 JSValue *CanvasImageDataArray::indexGetter(ExecState *exec, unsigned index)
0786 {
0787     Q_UNUSED(exec);
0788     if (index >= size) { // paranoia..
0789         return jsNull();
0790     }
0791 
0792     unsigned pixel = index / 4;
0793     unsigned comp  = index % 4;
0794     QColor color = parent->impl()->pixel(pixel);
0795     //"... with each pixel's red, green, blue, and alpha components being given in that order"
0796     switch (comp) {
0797     case 0: return jsNumber(color.red());
0798     case 1: return jsNumber(color.green());
0799     case 2: return jsNumber(color.blue());
0800     default:     // aka case 3, for quietness purposes
0801         return jsNumber(color.alpha());
0802     }
0803 }
0804 
0805 bool CanvasImageDataArray::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0806 {
0807     // ### this doesn't behave exactly like array does --- should we care?
0808     bool ok;
0809     unsigned index = propertyName.toArrayIndex(&ok);
0810     if (ok && index < size) {
0811         slot.setCustomIndex(this, index, indexGetterAdapter<CanvasImageDataArray>);
0812         return true;
0813     }
0814 
0815     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
0816 }
0817 
0818 bool CanvasImageDataArray::getOwnPropertySlot(ExecState *exec, unsigned index, PropertySlot &slot)
0819 {
0820     if (index < size) {
0821         slot.setCustomIndex(this, index, indexGetterAdapter<CanvasImageDataArray>);
0822         return true;
0823     }
0824 
0825     return JSObject::getOwnPropertySlot(exec, index, slot);
0826 }
0827 
0828 void CanvasImageDataArray::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
0829 {
0830     bool ok;
0831     unsigned index = propertyName.toArrayIndex(&ok);
0832     if (ok) {
0833         put(exec, index, value, attr);
0834         return;
0835     }
0836 
0837     JSObject::put(exec, propertyName, value, attr);
0838 }
0839 
0840 unsigned char CanvasImageDataArray::decodeComponent(ExecState *exec, JSValue *jsVal)
0841 {
0842     double val = jsVal->toNumber(exec);
0843 
0844     if (jsVal->isUndefined()) {
0845         val = 0.0;
0846     } else if (val < 0.0) {
0847         val = 0.0;
0848     } else if (val > 255.0) {
0849         val = 255.0;
0850     }
0851 
0852     // ### fixme: round to even
0853     return (unsigned char)qRound(val);
0854 }
0855 
0856 void CanvasImageDataArray::put(ExecState *exec, unsigned index, JSValue *value, int attr)
0857 {
0858     if (index < size) {
0859         unsigned char componentValue = decodeComponent(exec, value);
0860         unsigned int  pixel = index / 4;
0861         unsigned int  comp  = index % 4;
0862         parent->impl()->setComponent(pixel, comp, componentValue);
0863         return;
0864     }
0865 
0866     // Must use the string version here since numberic one will fall back to
0867     // us again.
0868     JSObject::put(exec, Identifier::from(index), value, attr);
0869 }
0870 
0871 DOM::CanvasImageDataImpl *toCanvasImageData(ExecState *exec, JSValue *val)
0872 {
0873     JSObject *obj = val->getObject();
0874     if (!obj) {
0875         return nullptr;
0876     }
0877 
0878     if (obj->inherits(&CanvasImageData::info)) {
0879         return static_cast<CanvasImageData *>(val)->impl();
0880     }
0881 
0882     // Uff. May be a fake one.
0883     bool ok = true;
0884     uint32_t width  = obj->get(exec, "width")->toUInt32(exec, ok);
0885     if (!ok || !width || exec->hadException()) {
0886         return nullptr;
0887     }
0888     uint32_t height = obj->get(exec, "height")->toUInt32(exec, ok);
0889     if (!ok || !height || exec->hadException()) {
0890         return nullptr;
0891     }
0892 
0893     // Perform safety check on the size.
0894     if (!khtmlImLoad::ImageManager::isAcceptableSize(width, height)) {
0895         return nullptr;
0896     }
0897 
0898     JSObject *data = obj->get(exec, "data")->getObject();
0899     if (!data) {
0900         return nullptr;
0901     }
0902 
0903     uint32_t length = data->get(exec, "length")->toUInt32(exec, ok);
0904     if (!ok || !length || exec->hadException()) {
0905         return nullptr;
0906     }
0907 
0908     if (length != 4 * width * height) {
0909         return nullptr;
0910     }
0911 
0912     // Uff. Well, it sounds sane enough for us to decode..
0913     CanvasImageDataImpl *id = new CanvasImageDataImpl(width, height);
0914     for (unsigned pixel = 0; pixel < width * height; ++pixel) {
0915         unsigned char r = CanvasImageDataArray::decodeComponent(exec, data->get(exec, pixel * 4));
0916         unsigned char g = CanvasImageDataArray::decodeComponent(exec, data->get(exec, pixel * 4 + 1));
0917         unsigned char b = CanvasImageDataArray::decodeComponent(exec, data->get(exec, pixel * 4 + 2));
0918         unsigned char a = CanvasImageDataArray::decodeComponent(exec, data->get(exec, pixel * 4 + 3));
0919         id->setPixel(pixel, QColor(r, g, b, a));
0920     }
0921     return id;
0922 }
0923 
0924 // This is completely fake!
0925 IMPLEMENT_PSEUDO_CONSTRUCTOR(SVGAnglePseudoCtor, "SVGAngle", Context2DProto)
0926 
0927 } // namespace
0928