diff options
Diffstat (limited to 'V8Binding/bindings/v8_custom.cpp')
-rw-r--r-- | V8Binding/bindings/v8_custom.cpp | 1102 |
1 files changed, 1102 insertions, 0 deletions
diff --git a/V8Binding/bindings/v8_custom.cpp b/V8Binding/bindings/v8_custom.cpp new file mode 100644 index 0000000..855e192 --- /dev/null +++ b/V8Binding/bindings/v8_custom.cpp @@ -0,0 +1,1102 @@ +/* + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2004-2006 Apple Computer, Inc. + * Copyright (C) 2006 James G. Speth (speth@end.com) + * Copyright (C) 2006 Samuel Weinig (sam@webkit.org) + * Copyright 2007, 2008 Google Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <Assertions.h> +#include <wtf/ASCIICType.h> + +#include "v8_proxy.h" +#include "v8_binding.h" +#include "V8NPObject.h" +#include "v8_custom.h" + +#include "V8Attr.h" +#include "V8CanvasGradient.h" +#include "V8CanvasPattern.h" +#include "V8CustomEventListener.h" +#include "V8Document.h" +#include "V8DOMWindow.h" +#include "V8HTMLCanvasElement.h" +#include "V8HTMLDocument.h" +#include "V8HTMLImageElement.h" +#include "V8HTMLOptionElement.h" +#include "V8Node.h" + +#if ENABLE(XPATH) +#include "V8XPathNSResolver.h" +#include "V8XPathResult.h" +#endif + +#include "Base64.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasRenderingContext2D.h" +#include "CanvasStyle.h" +#include "Clipboard.h" +#include "ClipboardEvent.h" +#include "Console.h" +#include "DOMParser.h" +#include "DOMStringList.h" +#include "DOMTimer.h" +#include "DOMWindow.h" +#include "Document.h" +#include "DocumentFragment.h" +#include "Event.h" +#include "EventListener.h" +#include "EventTarget.h" +#include "ExceptionCode.h" +#include "FloatRect.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "HTMLBodyElement.h" +#include "HTMLCanvasElement.h" +#include "HTMLDocument.h" +#include "HTMLEmbedElement.h" +#include "HTMLFormElement.h" +#include "HTMLFrameElement.h" +#include "HTMLFrameElementBase.h" +#include "HTMLFrameSetElement.h" +#include "HTMLIFrameElement.h" +#include "HTMLImageElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" +#include "HTMLOptionsCollection.h" +#include "HTMLSelectElement.h" +#include "History.h" +#include "JSXPathNSResolver.h" +#include "JSDOMBinding.h" +#include "KURL.h" +#include "Location.h" +#include "MessageChannel.h" +#include "MessagePort.h" +#include "MouseEvent.h" +#include "NodeIterator.h" +#include "NodeList.h" +#include "RGBColor.h" +#include "RenderPartObject.h" +#include "RenderWidget.h" +#include "ScheduledAction.h" +#include "ScriptState.h" +#include "ScriptController.h" +#include "ScriptSourceCode.h" +#include "SecurityOrigin.h" +#include "StyleSheetList.h" +#include "TreeWalker.h" +#include "WebKitCSSMatrix.h" +#include "WebKitPoint.h" +#include "XMLSerializer.h" +#include "XPathEvaluator.h" +#include "XPathResult.h" +#include "XSLTProcessor.h" + +#if ENABLE(SVG) +#include "V8SVGPODTypeWrapper.h" +#include "SVGElementInstance.h" +#include "SVGException.h" +#include "SVGPathSeg.h" +#endif + +#include "Navigator.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(WebKitPointConstructor) { + INC_STATS("DOM.WebKitPoint.Constructor"); + return V8Proxy::ConstructDOMObject<V8ClassIndex::WEBKITPOINT, + WebKitPoint>(args); +} + +// DOMImplementation is a singleton in WebCore. If we use our normal +// mapping from DOM objects to V8 wrappers, the same wrapper will be +// shared for all frames in the same process. This is a major +// security problem. Therefore, we generate a DOMImplementation +// wrapper per document and store it in an internal field of the +// document. Since the DOMImplementation object is a singleton, we do +// not have to do anything to keep the DOMImplementation object alive +// for the lifetime of the wrapper. +ACCESSOR_GETTER(DocumentImplementation) { + ASSERT(info.Holder()->InternalFieldCount() >= + kDocumentMinimumInternalFieldCount); + // Check if the internal field already contains a wrapper. + v8::Local<v8::Value> implementation = + info.Holder()->GetInternalField(kDocumentImplementationIndex); + if (!implementation->IsUndefined()) { + return implementation; + } + // Generate a wrapper. + Document* doc = V8Proxy::DOMWrapperToNative<Document>(info.Holder()); + v8::Handle<v8::Value> wrapper = + V8Proxy::DOMImplementationToV8Object(doc->implementation()); + // Store the wrapper in the internal field. + info.Holder()->SetInternalField(kDocumentImplementationIndex, wrapper); + + return wrapper; +} + + +ACCESSOR_GETTER(DocumentLocation) { + Document* imp = V8Proxy::DOMWrapperToNative<Document>(info.Holder()); + if (!imp->frame()) + return v8::Null(); + + DOMWindow* window = imp->frame()->domWindow(); + return V8Proxy::ToV8Object(V8ClassIndex::LOCATION, window->location()); +} + + +ACCESSOR_SETTER(DocumentLocation) { + Document* imp = V8Proxy::DOMWrapperToNative<Document>(info.Holder()); + if (!imp->frame()) + return; + + DOMWindow* window = imp->frame()->domWindow(); + // WindowSetLocation does security checks. // XXXMB- verify! + WindowSetLocation(window, ToWebCoreString(value)); +} + + +INDEXED_PROPERTY_GETTER(HTMLFormElement) { + INC_STATS("DOM.HTMLFormElement.IndexedPropertyGetter"); + HTMLFormElement* form = + V8Proxy::DOMWrapperToNode<HTMLFormElement>(info.Holder()); + + RefPtr<Node> result = form->elements()->item(index); + if (!result) return v8::Handle<v8::Value>(); + return V8Proxy::NodeToV8Object(result.get()); +} + + +INDEXED_PROPERTY_GETTER(HTMLOptionsCollection) { + INC_STATS("DOM.HTMLOptionsCollection.IndexedPropertyGetter"); + HTMLOptionsCollection* collection = + V8Proxy::ToNativeObject<HTMLOptionsCollection>( + V8ClassIndex::HTMLOPTIONSCOLLECTION, info.Holder()); + + RefPtr<Node> result = collection->item(index); + if (!result) return v8::Handle<v8::Value>(); + + return V8Proxy::NodeToV8Object(result.get()); +} + +static v8::Handle<v8::Value> OptionsCollectionSetter(uint32_t index, + v8::Handle<v8::Value> value, HTMLSelectElement* base) { + if (value->IsNull() || value->IsUndefined()) { + base->remove(index); + return value; + } + + ExceptionCode ec = 0; + + // Check that the value is an HTMLOptionElement. If not, throw a + // TYPE_MISMATCH_ERR DOMException. + if (!V8HTMLOptionElement::HasInstance(value)) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return value; + } + + HTMLOptionElement* element = + V8Proxy::DOMWrapperToNode<HTMLOptionElement>( + v8::Handle<v8::Object>::Cast(value)); + base->setOption(index, element, ec); + + V8Proxy::SetDOMException(ec); + return value; +} + + +INDEXED_PROPERTY_SETTER(HTMLOptionsCollection) { + INC_STATS("DOM.HTMLOptionsCollection.IndexedPropertySetter"); + HTMLOptionsCollection* collection = + V8Proxy::ToNativeObject<HTMLOptionsCollection>( + V8ClassIndex::HTMLOPTIONSCOLLECTION, info.Holder()); + HTMLSelectElement* base = static_cast<HTMLSelectElement*>(collection->base()); + return OptionsCollectionSetter(index, value, base); +} + + +INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection) { + INC_STATS("DOM.HTMLSelectElementCollection.IndexedPropertySetter"); + HTMLSelectElement* select = + V8Proxy::DOMWrapperToNode<HTMLSelectElement>(info.Holder()); + return OptionsCollectionSetter(index, value, select); +} + +// CanvasRenderingContext2D ---------------------------------------------------- + +// Helper macro for converting v8 values into floats (expected by many of the +// canvas functions). +#define TO_FLOAT(a) static_cast<float>((a)->NumberValue()) + +// TODO: SetStrokeColor and SetFillColor are similar except function names, +// consolidate them into one. +CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetStrokeColor) { + INC_STATS("DOM.CanvasRenderingContext2D.setStrokeColor()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + switch (args.Length()) { + case 1: + if (args[0]->IsString()) { + context->setStrokeColor(ToWebCoreString(args[0])); + } else { + context->setStrokeColor(TO_FLOAT(args[0])); + } + break; + case 2: + if (args[0]->IsString()) { + context->setStrokeColor(ToWebCoreString(args[0]), + TO_FLOAT(args[1])); + } else { + context->setStrokeColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1])); + } + break; + case 4: + context->setStrokeColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3])); + break; + case 5: + context->setStrokeColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3]), + TO_FLOAT(args[4])); + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "setStrokeColor: Invalid number of arguments"); + break; + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetFillColor) { + INC_STATS("DOM.CanvasRenderingContext2D.setFillColor()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + switch (args.Length()) { + case 1: + if (args[0]->IsString()) { + context->setFillColor(ToWebCoreString(args[0])); + } else { + context->setFillColor(TO_FLOAT(args[0])); + } + break; + case 2: + if (args[0]->IsString()) { + context->setFillColor(ToWebCoreString(args[0]), TO_FLOAT(args[1])); + } else { + context->setFillColor(TO_FLOAT(args[0]), TO_FLOAT(args[1])); + } + break; + case 4: + context->setFillColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3])); + break; + case 5: + context->setFillColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3]), + TO_FLOAT(args[4])); + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "setFillColor: Invalid number of arguments"); + break; + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeRect) { + INC_STATS("DOM.CanvasRenderingContext2D.strokeRect()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + if (args.Length() == 5) { + context->strokeRect(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3]), + TO_FLOAT(args[4])); + } else if (args.Length() == 4) { + context->strokeRect(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3])); + } else { + V8Proxy::SetDOMException(INDEX_SIZE_ERR); + return v8::Handle<v8::Value>(); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetShadow) { + INC_STATS("DOM.CanvasRenderingContext2D.setShadow()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + switch (args.Length()) { + case 3: + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2])); + break; + case 4: + if (args[3]->IsString()) + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), ToWebCoreString(args[3])); + else + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), TO_FLOAT(args[3])); + break; + case 5: + if (args[3]->IsString()) + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), ToWebCoreString(args[3]), + TO_FLOAT(args[4])); + else + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), TO_FLOAT(args[3]), + TO_FLOAT(args[4])); + break; + case 7: + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), TO_FLOAT(args[3]), + TO_FLOAT(args[4]), TO_FLOAT(args[5]), + TO_FLOAT(args[6])); + break; + case 8: + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), TO_FLOAT(args[3]), + TO_FLOAT(args[4]), TO_FLOAT(args[5]), + TO_FLOAT(args[6]), TO_FLOAT(args[7])); + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "setShadow: Invalid number of arguments"); + break; + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImage) { + INC_STATS("DOM.CanvasRenderingContext2D.drawImage()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + v8::Handle<v8::Value> arg = args[0]; + + if (V8HTMLImageElement::HasInstance(arg)) { + ExceptionCode ec = 0; + HTMLImageElement* image_element = + V8Proxy::DOMWrapperToNode<HTMLImageElement>(arg); + switch (args.Length()) { + case 3: + context->drawImage(image_element, TO_FLOAT(args[1]), TO_FLOAT(args[2])); + break; + case 5: + context->drawImage(image_element, TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4]), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + break; + case 9: + context->drawImage(image_element, + FloatRect(TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4])), + FloatRect(TO_FLOAT(args[5]), TO_FLOAT(args[6]), + TO_FLOAT(args[7]), TO_FLOAT(args[8])), + ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "drawImage: Invalid number of arguments"); + return v8::Undefined(); + } + return v8::Undefined(); + } + + // HTMLCanvasElement + if (V8HTMLCanvasElement::HasInstance(arg)) { + ExceptionCode ec = 0; + HTMLCanvasElement* canvas_element = + V8Proxy::DOMWrapperToNode<HTMLCanvasElement>(arg); + switch (args.Length()) { + case 3: + context->drawImage(canvas_element, TO_FLOAT(args[1]), TO_FLOAT(args[2])); + break; + case 5: + context->drawImage(canvas_element, TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4]), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + break; + case 9: + context->drawImage(canvas_element, + FloatRect(TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4])), + FloatRect(TO_FLOAT(args[5]), TO_FLOAT(args[6]), + TO_FLOAT(args[7]), TO_FLOAT(args[8])), + ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "drawImage: Invalid number of arguments"); + return v8::Undefined(); + } + return v8::Undefined(); + } + + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImageFromRect) { + INC_STATS("DOM.CanvasRenderingContext2D.drawImageFromRect()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + v8::Handle<v8::Value> arg = args[0]; + + if (V8HTMLImageElement::HasInstance(arg)) { + HTMLImageElement* image_element = + V8Proxy::DOMWrapperToNode<HTMLImageElement>(arg); + context->drawImageFromRect(image_element, + TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4]), + TO_FLOAT(args[5]), TO_FLOAT(args[6]), + TO_FLOAT(args[7]), TO_FLOAT(args[8]), + ToWebCoreString(args[9])); + } else { + V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, + "drawImageFromRect: Invalid type of arguments"); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DCreatePattern) { + INC_STATS("DOM.CanvasRenderingContext2D.createPattern()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + v8::Handle<v8::Value> arg = args[0]; + + if (V8HTMLImageElement::HasInstance(arg)) { + HTMLImageElement* image_element = + V8Proxy::DOMWrapperToNode<HTMLImageElement>(arg); + ExceptionCode ec = 0; + RefPtr<CanvasPattern> pattern = + context->createPattern(image_element, valueToStringWithNullCheck(args[1]), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return V8Proxy::ToV8Object(V8ClassIndex::CANVASPATTERN, pattern.get()); + } + + if (V8HTMLCanvasElement::HasInstance(arg)) { + HTMLCanvasElement* canvas_element = + V8Proxy::DOMWrapperToNode<HTMLCanvasElement>(arg); + ExceptionCode ec = 0; + RefPtr<CanvasPattern> pattern = + context->createPattern(canvas_element, valueToStringWithNullCheck(args[1]), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return V8Proxy::ToV8Object(V8ClassIndex::CANVASPATTERN, pattern.get()); + } + + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DFillText) { + INC_STATS("DOM.CanvasRenderingContext2D.fillText()"); + + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + // Two forms: + // * fillText(text, x, y) + // * fillText(text, x, y, maxWidth) + if (args.Length() < 3 || args.Length() > 4) { + V8Proxy::SetDOMException(SYNTAX_ERR); + return v8::Handle<v8::Value>(); + } + + String text = ToWebCoreString(args[0]); + float x = TO_FLOAT(args[1]); + float y = TO_FLOAT(args[2]); + + if (args.Length() == 4) { + float maxWidth = TO_FLOAT(args[3]); + context->fillText(text, x, y, maxWidth); + } else { + context->fillText(text, x, y); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeText) { + INC_STATS("DOM.CanvasRenderingContext2D.strokeText()"); + + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + // Two forms: + // * strokeText(text, x, y) + // * strokeText(text, x, y, maxWidth) + if (args.Length() < 3 || args.Length() > 4) { + V8Proxy::SetDOMException(SYNTAX_ERR); + return v8::Handle<v8::Value>(); + } + + String text = ToWebCoreString(args[0]); + float x = TO_FLOAT(args[1]); + float y = TO_FLOAT(args[2]); + + if (args.Length() == 4) { + float maxWidth = TO_FLOAT(args[3]); + context->strokeText(text, x, y, maxWidth); + } else { + context->strokeText(text, x, y); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DPutImageData) { + INC_STATS("DOM.CanvasRenderingContext2D.putImageData()"); + + // Two froms: + // * putImageData(ImageData, x, y) + // * putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight) + if (args.Length() != 3 && args.Length() != 7) { + V8Proxy::SetDOMException(SYNTAX_ERR); + return v8::Handle<v8::Value>(); + } + + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + ImageData* imageData = 0; + + // Need to check that the argument is of the correct type, since + // ToNativeObject() expects it to be correct. If the argument was incorrect + // we leave it null, and putImageData() will throw the correct exception + // (TYPE_MISMATCH_ERR). + if (V8Proxy::IsWrapperOfType(args[0], V8ClassIndex::IMAGEDATA)) { + imageData = V8Proxy::ToNativeObject<ImageData>( + V8ClassIndex::IMAGEDATA, args[0]); + } + + ExceptionCode ec = 0; + + if (args.Length() == 7) { + context->putImageData(imageData, + TO_FLOAT(args[1]), TO_FLOAT(args[2]), TO_FLOAT(args[3]), + TO_FLOAT(args[4]), TO_FLOAT(args[5]), TO_FLOAT(args[6]), ec); + } else { + context->putImageData(imageData, TO_FLOAT(args[1]), TO_FLOAT(args[2]), ec); + } + + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + + return v8::Undefined(); +} + +static bool AllowSettingSrcToJavascriptURL(Element* element, String name, + String value) { + // Need to parse value as URL first in order to check its protocol. + // " javascript:", "java\0script:", "javascript\t:", "javascript\1:" + // are all parsed as "javascript:" url. + // When changing location in HTMLFrameElement, value is parsed as url. + // We must match the behavior there. + // See issue 804099. + // + // parseURL is defined in CSSHelper.cpp. + if ((element->hasTagName(HTMLNames::iframeTag) || + element->hasTagName(HTMLNames::frameTag)) && + equalIgnoringCase(name, "src") && + parseURL(value).startsWith("javascript:", false)) { + HTMLFrameElementBase* frame = static_cast<HTMLFrameElementBase*>(element); + Node* contentDoc = frame->contentDocument(); + if (contentDoc && !V8Proxy::CheckNodeSecurity(contentDoc)) + return false; + } + return true; +} + + +static bool AllowSettingFrameSrcToJavascriptUrl(HTMLFrameElementBase* frame, + String value) { + // See same issue in AllowSettingSrcToJavascriptURL. + if (parseURL(value).startsWith("javascript:", false)) { + Node* contentDoc = frame->contentDocument(); + if (contentDoc && !V8Proxy::CheckNodeSecurity(contentDoc)) + return false; + } + return true; +} + + +// HTMLIFrameElement ----------------------------------------------------------- + +// TODO(mbelshe): This should move into V8DOMWindowCustom.cpp +// Can't move it right now because it depends on V8ScheduledAction, +// which is private to this file (v8_custom.cpp). +v8::Handle<v8::Value> V8Custom::WindowSetTimeoutImpl(const v8::Arguments& args, + bool single_shot) { + int num_arguments = args.Length(); + + if (num_arguments < 1) return v8::Undefined(); + + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, args.Holder()); + + if (!imp->frame()) + return v8::Undefined(); + + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) + return v8::Undefined(); + + ScriptExecutionContext* script_context = + static_cast<ScriptExecutionContext*>(imp->frame()->document()); + + v8::Handle<v8::Value> function = args[0]; + + int32_t timeout = 0; + if (num_arguments >= 2) timeout = args[1]->Int32Value(); + + int id; + if (function->IsString()) { + // Don't allow setting timeouts to run empty functions! + // (Bug 1009597) + WebCore::String string_function = ToWebCoreString(function); + if (string_function.length() == 0) + return v8::Undefined(); + + id = DOMTimer::install(script_context, + new ScheduledAction(string_function), timeout, + single_shot); + } else if (function->IsFunction()) { + int param_count = num_arguments >= 2 ? num_arguments - 2 : 0; + v8::Local<v8::Value>* params = 0; + if (param_count > 0) { + params = new v8::Local<v8::Value>[param_count]; + for (int i = 0; i < param_count; i++) + // parameters must be globalized + params[i] = args[i+2]; + } + + // params is passed to action, and released in action's destructor + ScheduledAction* action = new ScheduledAction( + v8::Handle<v8::Function>::Cast(function), param_count, params); + + delete[] params; + + id = DOMTimer::install(script_context, action, timeout, single_shot); + } else { + // TODO(fqian): what's the right return value if failed. + return v8::Undefined(); + } + return v8::Integer::New(id); +} + + +// DOMWindow ------------------------------------------------------------------- + +static bool IsAscii(const String& str) { + for (size_t i = 0; i < str.length(); i++) { + if (str[i] > 0xFF) + return false; + } + return true; +} + +static v8::Handle<v8::Value> Base64Convert(const String& str, bool encode) { + if (!IsAscii(str)) { + V8Proxy::SetDOMException(INVALID_CHARACTER_ERR); + return v8::Handle<v8::Value>(); + } + + Vector<char> in(str.length()); + for (size_t i = 0; i < str.length(); i++) { + in[i] = static_cast<char>(str[i]); + } + Vector<char> out; + + if (encode) { + base64Encode(in, out); + } else { + if (!base64Decode(in, out)) { + V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, "Cannot decode base64"); + return v8::Undefined(); + } + } + + return v8String(String(out.data(), out.size())); +} + +CALLBACK_FUNC_DECL(DOMWindowAtob) { + INC_STATS("DOM.DOMWindow.atob()"); + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, args.Holder()); + + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) + return v8::Undefined(); + + if (args.Length() < 1) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + if (args[0]->IsNull()) return v8String(""); + + String str = ToWebCoreString(args[0]); + return Base64Convert(str, false); +} + +CALLBACK_FUNC_DECL(DOMWindowBtoa) { + INC_STATS("DOM.DOMWindow.btoa()"); + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, args.Holder()); + + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) + return v8::Undefined(); + + if (args.Length() < 1) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + if (args[0]->IsNull()) return v8String(""); + + String str = ToWebCoreString(args[0]); + return Base64Convert(str, true); +} + +// TODO(fqian): returning string is cheating, and we should +// fix this by calling toString function on the receiver. +// However, V8 implements toString in JavaScript, which requires +// switching context of receiver. I consider it is dangerous. +CALLBACK_FUNC_DECL(DOMWindowToString) +{ + INC_STATS("DOM.DOMWindow.toString()"); + return args.This()->ObjectProtoToString(); +} + +CALLBACK_FUNC_DECL(DOMWindowNOP) +{ + INC_STATS("DOM.DOMWindow.nop()"); + return v8::Undefined(); +} + + +CALLBACK_FUNC_DECL(HTMLFormElementSubmit) { + INC_STATS("DOM.HTMLFormElement.submit()"); + + HTMLFormElement* form = + V8Proxy::DOMWrapperToNative<HTMLFormElement>(args.Holder()); + + form->submit(0, false, false); + return v8::Undefined(); +} + +static String EventNameFromAttributeName(const String& name) { + ASSERT(name.startsWith("on")); + String event_type = name.substring(2); + + if (event_type.startsWith("w")) { + switch(event_type[event_type.length() - 1]) { + case 't': + event_type = "webkitAnimationStart"; + break; + case 'n': + event_type = "webkitAnimationIteration"; + break; + case 'd': + ASSERT(event_type.length() > 7); + if (event_type[7] == 'a') + event_type = "webkitAnimationEnd"; + else + event_type = "webkitTransitionEnd"; + break; + } + } + + return event_type; +} + + +ACCESSOR_SETTER(DOMWindowEventHandler) { + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper( + V8ClassIndex::DOMWINDOW, info.This()); + if (holder.IsEmpty()) + return; + + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, holder); + if (!imp->frame()) + return; + + Document* doc = imp->frame()->document(); + if (!doc) + return; + + String key = ToWebCoreString(name); + String event_type = EventNameFromAttributeName(key); + + if (value->IsNull()) { + // Clear the event listener + doc->removeWindowInlineEventListenerForType(event_type); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->frame()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateV8EventListener(value, true); + if (listener) { + doc->setWindowInlineEventListenerForType(event_type, listener); + } + } +} + + +ACCESSOR_GETTER(DOMWindowEventHandler) { + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper( + V8ClassIndex::DOMWINDOW, info.This()); + if (holder.IsEmpty()) + return v8::Undefined(); + + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, holder); + if (!imp->frame()) + return v8::Undefined(); + + Document* doc = imp->frame()->document(); + if (!doc) + return v8::Undefined(); + + String key = ToWebCoreString(name); + String event_type = EventNameFromAttributeName(key); + + EventListener* listener = doc->windowInlineEventListenerForType(event_type); + return V8Proxy::EventListenerToV8Object(listener); +} + + +// --------------- Security Checks ------------------------- +NAMED_ACCESS_CHECK(DOMWindow) { + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::DOMWINDOW); + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return false; // the frame is gone. + + DOMWindow* target_win = + V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); + + ASSERT(target_win); + + Frame* target = target_win->frame(); + if (!target) + return false; + + if (key->IsString()) { + String name = ToWebCoreString(key); + + // Allow access of GET and HAS if index is a subframe. + if ((type == v8::ACCESS_GET || type == v8::ACCESS_HAS) && + target->tree()->child(name)) { + return true; + } + } + + return V8Proxy::CanAccessFrame(target, false); +} + + +INDEXED_ACCESS_CHECK(DOMWindow) { + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::DOMWINDOW); + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return false; + + DOMWindow* target_win = + V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); + + ASSERT(target_win); + + Frame* target = target_win->frame(); + if (!target) + return false; + + // Allow access of GET and HAS if index is a subframe. + if ((type == v8::ACCESS_GET || type == v8::ACCESS_HAS) && + target->tree()->child(index)) { + return true; + } + + return V8Proxy::CanAccessFrame(target, false); +} + + +INDEXED_ACCESS_CHECK(History) { + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::HISTORY); + // Only allow same origin access + History* imp = + V8Proxy::ToNativeObject<History>(V8ClassIndex::HISTORY, host); + return V8Proxy::CanAccessFrame(imp->frame(), false); +} + + +NAMED_ACCESS_CHECK(History) { + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::HISTORY); + // Only allow same origin access + History* imp = + V8Proxy::ToNativeObject<History>(V8ClassIndex::HISTORY, host); + return V8Proxy::CanAccessFrame(imp->frame(), false); +} + + + +#undef INDEXED_ACCESS_CHECK +#undef NAMED_ACCESS_CHECK +#undef NAMED_PROPERTY_GETTER +#undef NAMED_PROPERTY_SETTER + + +// static +Frame* V8Custom::GetTargetFrame(v8::Local<v8::Object> host, + v8::Local<v8::Value> data) { + Frame* target = 0; + switch (V8ClassIndex::FromInt(data->Int32Value())) { + case V8ClassIndex::DOMWINDOW: { + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return target; + + DOMWindow* target_win = + V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); + target = target_win->frame(); + break; + } + case V8ClassIndex::LOCATION: { + History* imp = + V8Proxy::ToNativeObject<History>(V8ClassIndex::HISTORY, host); + target = imp->frame(); + break; + } + case V8ClassIndex::HISTORY: { + Location* imp = + V8Proxy::ToNativeObject<Location>(V8ClassIndex::LOCATION, host); + target = imp->frame(); + break; + } + default: + break; + } + return target; +} + +#if ENABLE(SVG) +V8ClassIndex::V8WrapperType V8Custom::DowncastSVGPathSeg(void* path_seg) { + WebCore::SVGPathSeg *real_path_seg = + reinterpret_cast<WebCore::SVGPathSeg*>(path_seg); + + switch (real_path_seg->pathSegType()) { +#define MAKE_CASE(svg_val, v8_val) \ + case WebCore::SVGPathSeg::svg_val: \ + return V8ClassIndex::v8_val; + +MAKE_CASE(PATHSEG_CLOSEPATH, SVGPATHSEGCLOSEPATH) +MAKE_CASE(PATHSEG_MOVETO_ABS, SVGPATHSEGMOVETOABS) +MAKE_CASE(PATHSEG_MOVETO_REL, SVGPATHSEGMOVETOREL) +MAKE_CASE(PATHSEG_LINETO_ABS, SVGPATHSEGLINETOABS) +MAKE_CASE(PATHSEG_LINETO_REL, SVGPATHSEGLINETOREL) +MAKE_CASE(PATHSEG_CURVETO_CUBIC_ABS, SVGPATHSEGCURVETOCUBICABS) +MAKE_CASE(PATHSEG_CURVETO_CUBIC_REL, SVGPATHSEGCURVETOCUBICREL) +MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_ABS, SVGPATHSEGCURVETOQUADRATICABS) +MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_REL, SVGPATHSEGCURVETOQUADRATICREL) +MAKE_CASE(PATHSEG_ARC_ABS, SVGPATHSEGARCABS) +MAKE_CASE(PATHSEG_ARC_REL, SVGPATHSEGARCREL) +MAKE_CASE(PATHSEG_LINETO_HORIZONTAL_ABS, SVGPATHSEGLINETOHORIZONTALABS) +MAKE_CASE(PATHSEG_LINETO_HORIZONTAL_REL, SVGPATHSEGLINETOHORIZONTALREL) +MAKE_CASE(PATHSEG_LINETO_VERTICAL_ABS, SVGPATHSEGLINETOVERTICALABS) +MAKE_CASE(PATHSEG_LINETO_VERTICAL_REL, SVGPATHSEGLINETOVERTICALREL) +MAKE_CASE(PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, SVGPATHSEGCURVETOCUBICSMOOTHABS) +MAKE_CASE(PATHSEG_CURVETO_CUBIC_SMOOTH_REL, SVGPATHSEGCURVETOCUBICSMOOTHREL) +MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, \ + SVGPATHSEGCURVETOQUADRATICSMOOTHABS) +MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, \ + SVGPATHSEGCURVETOQUADRATICSMOOTHREL) + +#undef MAKE_CASE + + default: + return V8ClassIndex::INVALID_CLASS_INDEX; + } +} + +#endif // ENABLE(SVG) + +} // namespace WebCore |