File indexing completed on 2023-09-24 04:06: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