diff options
author | Feng Qian <fqian@google.com> | 2009-04-21 12:03:24 -0700 |
---|---|---|
committer | Feng Qian <fqian@google.com> | 2009-04-21 12:03:24 -0700 |
commit | ba8f92f666d8cdf3f6bdbe4b53d214fade995b74 (patch) | |
tree | 47cef663127948072d0f93cfff71508f4fdc2870 /V8Binding | |
parent | 08e785380f0bcfd49c4947289eb071a7a668a1cc (diff) | |
download | external_webkit-ba8f92f666d8cdf3f6bdbe4b53d214fade995b74.zip external_webkit-ba8f92f666d8cdf3f6bdbe4b53d214fade995b74.tar.gz external_webkit-ba8f92f666d8cdf3f6bdbe4b53d214fade995b74.tar.bz2 |
Import V8binding code from Chromium tree.
Sync'ed at Chromium trunk r12846.
http://src.chromium.org/viewvc/chrome?view=rev&revision=12846
Diffstat (limited to 'V8Binding')
43 files changed, 15436 insertions, 0 deletions
diff --git a/V8Binding/DerivedSources.make b/V8Binding/DerivedSources.make new file mode 100644 index 0000000..227aa5e --- /dev/null +++ b/V8Binding/DerivedSources.make @@ -0,0 +1,1185 @@ +# Copyright (C) 2006, 2007 Apple Inc. All rights reserved. +# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of +# its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +VPATH = \ + $(PORTROOT)/bindings/v8 \ + $(WebCore) \ + $(WebCore)/bindings/js \ + $(WebCore)/bindings/v8 \ + $(WebCore)/bindings/objc \ + $(WebCore)/css \ + $(WebCore)/dom \ + $(WebCore)/html \ + $(WebCore)/inspector \ + $(WebCore)/page \ + $(WebCore)/plugins \ + $(WebCore)/storage \ + $(WebCore)/xml \ + $(WebCore)/workers \ + $(WebCore)/svg \ +# + +.PHONY : all + +ifeq ($(OS),MACOS) +all : \ + CharsetData.cpp +endif + +# Not needed because we don't want obj-c bindings generated +# DOMAbstractView.h\ + DOMAttr.h \ + DOMCDATASection.h \ + DOMCSSCharsetRule.h \ + DOMCSSFontFaceRule.h \ + DOMCSSImportRule.h \ + DOMCSSMediaRule.h \ + DOMCSSPageRule.h \ + DOMCSSPrimitiveValue.h \ + DOMCSSRule.h \ + DOMCSSRuleList.h \ + DOMCSSStyleDeclaration.h \ + DOMCSSStyleRule.h \ + DOMCSSStyleSheet.h \ + DOMCSSUnknownRule.h \ + DOMCSSValue.h \ + DOMCSSValueList.h \ + DOMCharacterData.h \ + DOMComment.h \ + DOMCounter.h \ + DOMDOMImplementation.h \ + DOMDocument.h \ + DOMDocumentFragment.h \ + DOMDocumentType.h \ + DOMElement.h \ + DOMEntity.h \ + DOMEntityReference.h \ + DOMEvent.h \ + DOMEventListener.h \ + DOMEventTarget.h \ + DOMHTMLAnchorElement.h \ + DOMHTMLAppletElement.h \ + DOMHTMLAreaElement.h \ + DOMHTMLBRElement.h \ + DOMHTMLBaseElement.h \ + DOMHTMLBaseFontElement.h \ + DOMHTMLBodyElement.h \ + DOMHTMLButtonElement.h \ + DOMHTMLCanvasElement.h \ + DOMHTMLCollection.h \ + DOMHTMLDListElement.h \ + DOMHTMLDirectoryElement.h \ + DOMHTMLDivElement.h \ + DOMHTMLDocument.h \ + DOMHTMLElement.h \ + DOMHTMLEmbedElement.h \ + DOMHTMLFieldSetElement.h \ + DOMHTMLFontElement.h \ + DOMHTMLFormElement.h \ + DOMHTMLFrameElement.h \ + DOMHTMLFrameSetElement.h \ + DOMHTMLHRElement.h \ + DOMHTMLHeadElement.h \ + DOMHTMLHeadingElement.h \ + DOMHTMLHtmlElement.h \ + DOMHTMLIFrameElement.h \ + DOMHTMLImageElement.h \ + DOMHTMLInputElement.h \ + DOMHTMLIsIndexElement.h \ + DOMHTMLLIElement.h \ + DOMHTMLLabelElement.h \ + DOMHTMLLegendElement.h \ + DOMHTMLLinkElement.h \ + DOMHTMLMapElement.h \ + DOMHTMLMarqueeElement.h \ + DOMHTMLMenuElement.h \ + DOMHTMLMetaElement.h \ + DOMHTMLModElement.h \ + DOMHTMLOListElement.h \ + DOMHTMLObjectElement.h \ + DOMHTMLOptGroupElement.h \ + DOMHTMLOptionElement.h \ + DOMHTMLOptionsCollection.h \ + DOMHTMLParagraphElement.h \ + DOMHTMLParamElement.h \ + DOMHTMLPreElement.h \ + DOMHTMLQuoteElement.h \ + DOMHTMLScriptElement.h \ + DOMHTMLSelectElement.h \ + DOMHTMLStyleElement.h \ + DOMHTMLTableCaptionElement.h \ + DOMHTMLTableCellElement.h \ + DOMHTMLTableColElement.h \ + DOMHTMLTableElement.h \ + DOMHTMLTableRowElement.h \ + DOMHTMLTableSectionElement.h \ + DOMHTMLTextAreaElement.h \ + DOMHTMLTitleElement.h \ + DOMHTMLUListElement.h \ + DOMKeyboardEvent.h \ + DOMMessageEvent.h \ + DOMMediaList.h \ + DOMMouseEvent.h \ + DOMMutationEvent.h \ + DOMNamedNodeMap.h \ + DOMNode.h \ + DOMNodeFilter.h \ + DOMNodeIterator.h \ + DOMNodeList.h \ + DOMNotation.h \ + DOMOverflowEvent.h \ + DOMProcessingInstruction.h \ + DOMRGBColor.h \ + DOMRange.h \ + DOMRect.h \ + DOMSVGAElement.h \ + DOMSVGAngle.h \ + DOMSVGAnimateColorElement.h \ + DOMSVGAnimateElement.h \ + DOMSVGAnimateTransformElement.h \ + DOMSVGAnimatedAngle.h \ + DOMSVGAnimatedBoolean.h \ + DOMSVGAnimatedEnumeration.h \ + DOMSVGAnimatedInteger.h \ + DOMSVGAnimatedLength.h \ + DOMSVGAnimatedLengthList.h \ + DOMSVGAnimatedNumber.h \ + DOMSVGAnimatedNumberList.h \ + DOMSVGAnimatedPathData.h \ + DOMSVGAnimatedPoints.h \ + DOMSVGAnimatedPreserveAspectRatio.h \ + DOMSVGAnimatedRect.h \ + DOMSVGAnimatedString.h \ + DOMSVGAnimatedTransformList.h \ + DOMSVGAnimationElement.h \ + DOMSVGCircleElement.h \ + DOMSVGClipPathElement.h \ + DOMSVGColor.h \ + DOMSVGComponentTransferFunctionElement.h \ + DOMSVGCursorElement.h \ + DOMSVGDefinitionSrcElement.h \ + DOMSVGDefsElement.h \ + DOMSVGDescElement.h \ + DOMSVGDocument.h \ + DOMSVGElement.h \ + DOMSVGElementInstance.h \ + DOMSVGElementInstanceList.h \ + DOMSVGEllipseElement.h \ + DOMSVGExternalResourcesRequired.h \ + DOMSVGFEBlendElement.h \ + DOMSVGFEColorMatrixElement.h \ + DOMSVGFEComponentTransferElement.h \ + DOMSVGFECompositeElement.h \ + DOMSVGFEDiffuseLightingElement.h \ + DOMSVGFEDisplacementMapElement.h \ + DOMSVGFEDistantLightElement.h \ + DOMSVGFEFloodElement.h \ + DOMSVGFEFuncAElement.h \ + DOMSVGFEFuncBElement.h \ + DOMSVGFEFuncGElement.h \ + DOMSVGFEFuncRElement.h \ + DOMSVGFEGaussianBlurElement.h \ + DOMSVGFEImageElement.h \ + DOMSVGFEMergeElement.h \ + DOMSVGFEMergeNodeElement.h \ + DOMSVGFEOffsetElement.h \ + DOMSVGFEPointLightElement.h \ + DOMSVGFESpecularLightingElement.h \ + DOMSVGFESpotLightElement.h \ + DOMSVGFETileElement.h \ + DOMSVGFETurbulenceElement.h \ + DOMSVGFontElement.h \ + DOMSVGFontFaceElement.h \ + DOMSVGFontFaceFormatElement.h \ + DOMSVGFontFaceNameElement.h \ + DOMSVGFontFaceSrcElement.h \ + DOMSVGFontFaceUriElement.h \ + DOMSVGFilterElement.h \ + DOMSVGFilterPrimitiveStandardAttributes.h \ + DOMSVGFitToViewBox.h \ + DOMSVGForeignObjectElement.h \ + DOMSVGGElement.h \ + DOMSVGGlyphElement.h \ + DOMSVGGradientElement.h \ + DOMSVGImageElement.h \ + DOMSVGLangSpace.h \ + DOMSVGLength.h \ + DOMSVGLengthList.h \ + DOMSVGLineElement.h \ + DOMSVGLinearGradientElement.h \ + DOMSVGLocatable.h \ + DOMSVGMarkerElement.h \ + DOMSVGMaskElement.h \ + DOMSVGMatrix.h \ + DOMSVGMetadataElement.h \ + DOMSVGMissingGlyphElement.h \ + DOMSVGNumber.h \ + DOMSVGNumberList.h \ + DOMSVGPaint.h \ + DOMSVGPathElement.h \ + DOMSVGPathSeg.h \ + DOMSVGPathSegArcAbs.h \ + DOMSVGPathSegArcRel.h \ + DOMSVGPathSegClosePath.h \ + DOMSVGPathSegCurvetoCubicAbs.h \ + DOMSVGPathSegCurvetoCubicRel.h \ + DOMSVGPathSegCurvetoCubicSmoothAbs.h \ + DOMSVGPathSegCurvetoCubicSmoothRel.h \ + DOMSVGPathSegCurvetoQuadraticAbs.h \ + DOMSVGPathSegCurvetoQuadraticRel.h \ + DOMSVGPathSegCurvetoQuadraticSmoothAbs.h \ + DOMSVGPathSegCurvetoQuadraticSmoothRel.h \ + DOMSVGPathSegLinetoAbs.h \ + DOMSVGPathSegLinetoHorizontalAbs.h \ + DOMSVGPathSegLinetoHorizontalRel.h \ + DOMSVGPathSegLinetoRel.h \ + DOMSVGPathSegLinetoVerticalAbs.h \ + DOMSVGPathSegLinetoVerticalRel.h \ + DOMSVGPathSegList.h \ + DOMSVGPathSegMovetoAbs.h \ + DOMSVGPathSegMovetoRel.h \ + DOMSVGPatternElement.h \ + DOMSVGPoint.h \ + DOMSVGPointList.h \ + DOMSVGPolygonElement.h \ + DOMSVGPolylineElement.h \ + DOMSVGPreserveAspectRatio.h \ + DOMSVGRadialGradientElement.h \ + DOMSVGRect.h \ + DOMSVGRectElement.h \ + DOMSVGRenderingIntent.h \ + DOMSVGSVGElement.h \ + DOMSVGScriptElement.h \ + DOMSVGSetElement.h \ + DOMSVGStopElement.h \ + DOMSVGStringList.h \ + DOMSVGStylable.h \ + DOMSVGStyleElement.h \ + DOMSVGSwitchElement.h \ + DOMSVGSymbolElement.h \ + DOMSVGTRefElement.h \ + DOMSVGTSpanElement.h \ + DOMSVGTests.h \ + DOMSVGTextContentElement.h \ + DOMSVGTextElement.h \ + DOMSVGTextPathElement.h \ + DOMSVGTextPositioningElement.h \ + DOMSVGTitleElement.h \ + DOMSVGTransform.h \ + DOMSVGTransformList.h \ + DOMSVGTransformable.h \ + DOMSVGURIReference.h \ + DOMSVGUnitTypes.h \ + DOMSVGUseElement.h \ + DOMSVGViewElement.h \ + DOMSVGZoomAndPan.h \ + DOMSVGZoomEvent.h \ + DOMStyleSheet.h \ + DOMStyleSheetList.h \ + DOMText.h \ + DOMTextEvent.h \ + DOMTreeWalker.h \ + DOMUIEvent.h \ + DOMWheelEvent.h \ + DOMXPathExpression.h \ + DOMXPathNSResolver.h \ + DOMXPathResult.h \ +endif + +# Not needed for V8\ +all : \ + CSSGrammar.cpp \ + CSSPropertyNames.h \ + CSSValueKeywords.h \ + ColorData.c \ + DocTypeStrings.cpp \ + HTMLEntityNames.c \ + JSAttr.h \ + JSBarInfo.h \ + JSCDATASection.h \ + JSCSSCharsetRule.h \ + JSCSSFontFaceRule.h \ + JSCSSImportRule.h \ + JSCSSMediaRule.h \ + JSCSSPageRule.h \ + JSCSSPrimitiveValue.h \ + JSCSSRule.h \ + JSCSSRuleList.h \ + JSCSSStyleRule.h \ + JSCSSStyleSheet.h \ + JSCSSValue.h \ + JSCSSValueList.h \ + JSCanvasGradient.h \ + JSCanvasPattern.h \ + JSCanvasRenderingContext2D.h \ + JSCharacterData.h \ + JSComment.h \ + JSConsole.h \ + JSCounter.h \ + JSCSSStyleDeclaration.h \ + JSDOMCoreException.h \ + JSDOMImplementation.h \ + JSDOMParser.h \ + JSDOMSelection.h \ + JSDOMWindow.h \ + JSDatabase.h \ + JSDocument.h \ + JSDocumentFragment.h \ + JSDocumentType.h \ + JSElement.h \ + JSEntity.h \ + JSEntityReference.h \ + JSEvent.h \ + JSEventException.h \ + JSEventTargetBase.lut.h \ + JSHTMLAnchorElement.h \ + JSHTMLAppletElement.h \ + JSHTMLAreaElement.h \ + JSHTMLAudioElement.h \ + JSHTMLBaseElement.h \ + JSHTMLBaseFontElement.h \ + JSHTMLBlockquoteElement.h \ + JSHTMLBodyElement.h \ + JSHTMLBRElement.h \ + JSHTMLButtonElement.h \ + JSHTMLCanvasElement.h \ + JSHTMLCollection.h \ + JSHTMLDListElement.h \ + JSHTMLDirectoryElement.h \ + JSHTMLDivElement.h \ + JSHTMLDocument.h \ + JSHTMLElement.h \ + JSHTMLEmbedElement.h \ + JSHTMLFieldSetElement.h \ + JSHTMLFontElement.h \ + JSHTMLFormElement.h \ + JSHTMLFrameElement.h \ + JSHTMLFrameSetElement.h \ + JSHTMLHRElement.h \ + JSHTMLHeadElement.h \ + JSHTMLHeadingElement.h \ + JSHTMLHtmlElement.h \ + JSHTMLIFrameElement.h \ + JSHTMLImageElement.h \ + JSHTMLInputElement.h \ + JSHTMLInputElementBaseTable.cpp \ + JSHTMLIsIndexElement.h \ + JSHTMLLIElement.h \ + JSHTMLLabelElement.h \ + JSHTMLLegendElement.h \ + JSHTMLLinkElement.h \ + JSHTMLMapElement.h \ + JSHTMLMarqueeElement.h \ + JSHTMLMediaElement.h \ + JSHTMLMenuElement.h \ + JSHTMLMetaElement.h \ + JSHTMLModElement.h \ + JSHTMLOListElement.h \ + JSHTMLOptGroupElement.h \ + JSHTMLObjectElement.h \ + JSHTMLOptionElement.h \ + JSHTMLOptionsCollection.h \ + JSHTMLParagraphElement.h \ + JSHTMLParamElement.h \ + JSHTMLPreElement.h \ + JSHTMLQuoteElement.h \ + JSHTMLScriptElement.h \ + JSHTMLSelectElement.h \ + JSHTMLSourceElement.h \ + JSHTMLStyleElement.h \ + JSHTMLTableCaptionElement.h \ + JSHTMLTableCellElement.h \ + JSHTMLTableColElement.h \ + JSHTMLTableElement.h \ + JSHTMLTableRowElement.h \ + JSHTMLTableSectionElement.h \ + JSHTMLTextAreaElement.h \ + JSHTMLTitleElement.h \ + JSHTMLUListElement.h \ + JSHTMLVideoElement.h \ + JSHistory.h \ + JSKeyboardEvent.h \ + JSLocation.lut.h \ + JSMediaError.h \ + JSMediaList.h \ + JSMessageEvent.h \ + JSMouseEvent.h \ + JSMutationEvent.h \ + JSNamedNodeMap.h \ + JSNode.h \ + JSNodeFilter.h \ + JSNodeIterator.h \ + JSNodeList.h \ + JSNotation.h \ + JSOverflowEvent.h \ + JSProcessingInstruction.h \ + JSProgressEvent.h \ + JSRange.h \ + JSRangeException.h \ + JSRect.h \ + JSSQLError.h \ + JSSQLResultSet.h \ + JSSQLResultSetRowList.h \ + JSSQLTransaction.h \ + JSSVGAElement.h \ + JSSVGAngle.h \ + JSSVGAnimatedAngle.h \ + JSSVGAnimateColorElement.h \ + JSSVGAnimateElement.h \ + JSSVGAnimateTransformElement.h \ + JSSVGAnimatedBoolean.h \ + JSSVGAnimatedEnumeration.h \ + JSSVGAnimatedInteger.h \ + JSSVGAnimatedLength.h \ + JSSVGAnimatedLengthList.h \ + JSSVGAnimatedNumber.h \ + JSSVGAnimatedNumberList.h \ + JSSVGAnimatedPreserveAspectRatio.h \ + JSSVGAnimatedRect.h \ + JSSVGAnimatedString.h \ + JSSVGAnimatedTransformList.h \ + JSSVGAnimationElement.h \ + JSSVGColor.h \ + JSSVGCircleElement.h \ + JSSVGClipPathElement.h \ + JSSVGComponentTransferFunctionElement.h \ + JSSVGCursorElement.h \ + JSSVGDefsElement.h \ + JSSVGDefinitionSrcElement.h \ + JSSVGDescElement.h \ + JSSVGDocument.h \ + JSSVGException.h \ + JSSVGLength.h \ + JSSVGMatrix.h \ + JSSVGMetadataElement.h \ + JSSVGPathElement.h \ + JSSVGPathSeg.h \ + JSSVGPathSegArcAbs.h \ + JSSVGPathSegArcRel.h \ + JSSVGPathSegClosePath.h \ + JSSVGPathSegCurvetoCubicAbs.h \ + JSSVGPathSegCurvetoCubicRel.h \ + JSSVGPathSegCurvetoCubicSmoothAbs.h \ + JSSVGPathSegCurvetoCubicSmoothRel.h \ + JSSVGPathSegCurvetoQuadraticAbs.h \ + JSSVGPathSegCurvetoQuadraticRel.h \ + JSSVGPathSegCurvetoQuadraticSmoothAbs.h \ + JSSVGPathSegCurvetoQuadraticSmoothRel.h \ + JSSVGPathSegLinetoAbs.h \ + JSSVGPathSegLinetoHorizontalAbs.h \ + JSSVGPathSegLinetoHorizontalRel.h \ + JSSVGPathSegLinetoRel.h \ + JSSVGPathSegLinetoVerticalAbs.h \ + JSSVGPathSegLinetoVerticalRel.h \ + JSSVGPathSegMovetoAbs.h \ + JSSVGPathSegMovetoRel.h \ + JSSVGNumber.h \ + JSSVGNumberList.h \ + JSSVGPaint.h \ + JSSVGPathSegList.h \ + JSSVGPatternElement.h \ + JSSVGPoint.h \ + JSSVGPointList.h \ + JSSVGPolygonElement.h \ + JSSVGPolylineElement.h \ + JSSVGRadialGradientElement.h \ + JSSVGRect.h \ + JSSVGRectElement.h \ + JSSVGRenderingIntent.h \ + JSSVGSetElement.h \ + JSSVGScriptElement.h \ + JSSVGStyleElement.h \ + JSSVGSwitchElement.h \ + JSSVGStopElement.h \ + JSSVGStringList.h \ + JSSVGSymbolElement.h \ + JSSVGTRefElement.h \ + JSSVGTSpanElement.h \ + JSSVGTextElement.h \ + JSSVGTextContentElement.h \ + JSSVGTextPathElement.h \ + JSSVGTextPositioningElement.h \ + JSSVGTitleElement.h \ + JSSVGTransform.h \ + JSSVGTransformList.h \ + JSSVGUnitTypes.h \ + JSSVGUseElement.h \ + JSSVGViewElement.h \ + JSSVGPreserveAspectRatio.h \ + JSSVGElement.h \ + JSSVGElementInstance.h \ + JSSVGElementInstanceList.h \ + JSSVGSVGElement.h \ + JSSVGEllipseElement.h \ + JSSVGFEBlendElement.h \ + JSSVGFEColorMatrixElement.h \ + JSSVGFEComponentTransferElement.h \ + JSSVGFECompositeElement.h \ + JSSVGFEDiffuseLightingElement.h \ + JSSVGFEDisplacementMapElement.h \ + JSSVGFEDistantLightElement.h \ + JSSVGFEFloodElement.h \ + JSSVGFEFuncAElement.h \ + JSSVGFEFuncBElement.h \ + JSSVGFEFuncGElement.h \ + JSSVGFEFuncRElement.h \ + JSSVGFEGaussianBlurElement.h \ + JSSVGFEImageElement.h \ + JSSVGFEMergeElement.h \ + JSSVGFEMergeNodeElement.h \ + JSSVGFEOffsetElement.h \ + JSSVGFEPointLightElement.h \ + JSSVGFESpecularLightingElement.h \ + JSSVGFESpotLightElement.h \ + JSSVGFETileElement.h \ + JSSVGFETurbulenceElement.h \ + JSSVGFilterElement.h \ + JSSVGFontElement.h \ + JSSVGFontFaceElement.h \ + JSSVGFontFaceFormatElement.h \ + JSSVGFontFaceNameElement.h \ + JSSVGFontFaceSrcElement.h \ + JSSVGFontFaceUriElement.h \ + JSSVGForeignObjectElement.h \ + JSSVGGElement.h \ + JSSVGGlyphElement.h \ + JSSVGGradientElement.h \ + JSSVGImageElement.h \ + JSSVGLength.h \ + JSSVGLengthList.h \ + JSSVGLineElement.h \ + JSSVGLinearGradientElement.h \ + JSSVGMaskElement.h \ + JSSVGMarkerElement.h \ + JSSVGMissingGlyphElement.h \ + JSSVGTransform.h \ + JSSVGZoomEvent.h \ + JSScreen.h \ + JSStyleSheet.h \ + JSStyleSheetList.h \ + JSText.h \ + JSTextEvent.h \ + JSTimeRanges.h \ + JSTreeWalker.h \ + JSUIEvent.h \ + JSVoidCallback.h \ + JSWheelEvent.h \ + JSXMLHttpRequest.lut.h \ + JSXMLHttpRequestException.h \ + JSXMLSerializer.h \ + JSXPathEvaluator.h \ + JSXPathException.h \ + JSXPathExpression.h \ + JSXPathNSResolver.h \ + JSXPathResult.h \ + JSXSLTProcessor.lut.h \ + SVGElementFactory.cpp \ + SVGNames.cpp \ + HTMLNames.cpp \ + UserAgentStyleSheets.h \ + XLinkNames.cpp \ + XMLNames.cpp \ + XPathGrammar.cpp \ + kjs_css.lut.h \ + kjs_events.lut.h \ + kjs_navigator.lut.h \ + kjs_window.lut.h \ + tokenizer.cpp \ + WebCore.exp \ +# + +all : \ + CSSGrammar.cpp \ + CSSPropertyNames.h \ + CSSValueKeywords.h \ + ColorData.c \ + DocTypeStrings.cpp \ + HTMLElementFactory.cpp \ + HTMLEntityNames.c \ + V8Attr.h \ + V8BarInfo.h \ + V8CanvasPixelArray.h \ + V8ClientRect.h \ + V8ClientRectList.h \ + V8CDATASection.h \ + V8CSSCharsetRule.h \ + V8CSSFontFaceRule.h \ + V8CSSImportRule.h \ + V8CSSMediaRule.h \ + V8CSSPageRule.h \ + V8CSSPrimitiveValue.h \ + V8CSSRule.h \ + V8CSSRuleList.h \ + V8CSSStyleRule.h \ + V8CSSStyleSheet.h \ + V8CSSValue.h \ + V8CSSValueList.h \ + V8CanvasGradient.h \ + V8CanvasPattern.h \ + V8CanvasRenderingContext2D.h \ + V8CharacterData.h \ + V8Comment.h \ + V8Console.h \ + V8Counter.h \ + V8CSSStyleDeclaration.h \ + V8CSSVariablesDeclaration.h \ + V8CSSVariablesRule.h \ + V8DOMCoreException.h \ + V8DOMImplementation.h \ + V8DOMParser.h \ + V8DOMSelection.h \ + V8DOMStringList.h \ + V8DOMWindow.h \ + V8Database.h \ + V8Document.h \ + V8DocumentFragment.h \ + V8DocumentType.h \ + V8Element.h \ + V8Entity.h \ + V8EntityReference.h \ + V8Event.h \ + V8EventException.h \ + V8File.h \ + V8FileList.h \ + V8HTMLAnchorElement.h \ + V8HTMLAppletElement.h \ + V8HTMLAreaElement.h \ + V8HTMLAudioElement.h \ + V8HTMLBaseElement.h \ + V8HTMLBaseFontElement.h \ + V8HTMLBlockquoteElement.h \ + V8HTMLBodyElement.h \ + V8HTMLBRElement.h \ + V8HTMLButtonElement.h \ + V8HTMLCanvasElement.h \ + V8HTMLCollection.h \ + V8HTMLDListElement.h \ + V8HTMLDirectoryElement.h \ + V8HTMLDivElement.h \ + V8HTMLDocument.h \ + V8HTMLElement.h \ + V8HTMLEmbedElement.h \ + V8HTMLFieldSetElement.h \ + V8HTMLFontElement.h \ + V8HTMLFormElement.h \ + V8HTMLFrameElement.h \ + V8HTMLFrameSetElement.h \ + V8HTMLHRElement.h \ + V8HTMLHeadElement.h \ + V8HTMLHeadingElement.h \ + V8HTMLHtmlElement.h \ + V8HTMLIFrameElement.h \ + V8HTMLImageElement.h \ + V8HTMLInputElement.h \ + V8HTMLIsIndexElement.h \ + V8HTMLLIElement.h \ + V8HTMLLabelElement.h \ + V8HTMLLegendElement.h \ + V8HTMLLinkElement.h \ + V8HTMLMapElement.h \ + V8HTMLMarqueeElement.h \ + V8HTMLMediaElement.h \ + V8HTMLMenuElement.h \ + V8HTMLMetaElement.h \ + V8HTMLModElement.h \ + V8HTMLOListElement.h \ + V8HTMLOptGroupElement.h \ + V8HTMLObjectElement.h \ + V8HTMLOptionElement.h \ + V8HTMLOptionsCollection.h \ + V8HTMLParagraphElement.h \ + V8HTMLParamElement.h \ + V8HTMLPreElement.h \ + V8HTMLQuoteElement.h \ + V8HTMLScriptElement.h \ + V8HTMLSelectElement.h \ + V8HTMLSourceElement.h \ + V8HTMLStyleElement.h \ + V8HTMLTableCaptionElement.h \ + V8HTMLTableCellElement.h \ + V8HTMLTableColElement.h \ + V8HTMLTableElement.h \ + V8HTMLTableRowElement.h \ + V8HTMLTableSectionElement.h \ + V8HTMLTextAreaElement.h \ + V8HTMLTitleElement.h \ + V8HTMLUListElement.h \ + V8HTMLVideoElement.h \ + V8History.h \ + V8ImageData.h \ + V8KeyboardEvent.h \ + V8MediaError.h \ + V8MediaList.h \ + V8MessageChannel.h \ + V8MessageEvent.h \ + V8MessagePort.h \ + V8MouseEvent.h \ + V8MutationEvent.h \ + V8NamedNodeMap.h \ + V8Node.h \ + V8NodeFilter.h \ + V8NodeIterator.h \ + V8NodeList.h \ + V8Notation.h \ + V8OverflowEvent.h \ + V8ProcessingInstruction.h \ + V8ProgressEvent.h \ + V8Range.h \ + V8RangeException.h \ + V8Rect.h \ + V8SQLError.h \ + V8SQLResultSet.h \ + V8SQLResultSetRowList.h \ + V8SQLTransaction.h \ + V8SVGAElement.h \ + V8SVGAltGlyphElement.h \ + V8SVGAngle.h \ + V8SVGAnimatedAngle.h \ + V8SVGAnimateColorElement.h \ + V8SVGAnimateElement.h \ + V8SVGAnimateTransformElement.h \ + V8SVGAnimatedBoolean.h \ + V8SVGAnimatedEnumeration.h \ + V8SVGAnimatedInteger.h \ + V8SVGAnimatedLength.h \ + V8SVGAnimatedLengthList.h \ + V8SVGAnimatedNumber.h \ + V8SVGAnimatedNumberList.h \ + V8SVGAnimatedPreserveAspectRatio.h \ + V8SVGAnimatedRect.h \ + V8SVGAnimatedString.h \ + V8SVGAnimatedTransformList.h \ + V8SVGAnimationElement.h \ + V8SVGColor.h \ + V8SVGCircleElement.h \ + V8SVGClipPathElement.h \ + V8SVGComponentTransferFunctionElement.h \ + V8SVGCursorElement.h \ + V8SVGDefsElement.h \ + V8SVGDefinitionSrcElement.h \ + V8SVGDescElement.h \ + V8SVGDocument.h \ + V8SVGException.h \ + V8SVGLength.h \ + V8SVGMatrix.h \ + V8SVGMetadataElement.h \ + V8SVGPathElement.h \ + V8SVGPathSeg.h \ + V8SVGPathSegArcAbs.h \ + V8SVGPathSegArcRel.h \ + V8SVGPathSegClosePath.h \ + V8SVGPathSegCurvetoCubicAbs.h \ + V8SVGPathSegCurvetoCubicRel.h \ + V8SVGPathSegCurvetoCubicSmoothAbs.h \ + V8SVGPathSegCurvetoCubicSmoothRel.h \ + V8SVGPathSegCurvetoQuadraticAbs.h \ + V8SVGPathSegCurvetoQuadraticRel.h \ + V8SVGPathSegCurvetoQuadraticSmoothAbs.h \ + V8SVGPathSegCurvetoQuadraticSmoothRel.h \ + V8SVGPathSegLinetoAbs.h \ + V8SVGPathSegLinetoHorizontalAbs.h \ + V8SVGPathSegLinetoHorizontalRel.h \ + V8SVGPathSegLinetoRel.h \ + V8SVGPathSegLinetoVerticalAbs.h \ + V8SVGPathSegLinetoVerticalRel.h \ + V8SVGPathSegMovetoAbs.h \ + V8SVGPathSegMovetoRel.h \ + V8SVGNumber.h \ + V8SVGNumberList.h \ + V8SVGPaint.h \ + V8SVGPathSegList.h \ + V8SVGPatternElement.h \ + V8SVGPoint.h \ + V8SVGPointList.h \ + V8SVGPolygonElement.h \ + V8SVGPolylineElement.h \ + V8SVGRadialGradientElement.h \ + V8SVGRect.h \ + V8SVGRectElement.h \ + V8SVGRenderingIntent.h \ + V8SVGSetElement.h \ + V8SVGScriptElement.h \ + V8SVGStyleElement.h \ + V8SVGSwitchElement.h \ + V8SVGStopElement.h \ + V8SVGStringList.h \ + V8SVGSymbolElement.h \ + V8SVGTRefElement.h \ + V8SVGTSpanElement.h \ + V8SVGTextElement.h \ + V8SVGTextContentElement.h \ + V8SVGTextPathElement.h \ + V8SVGTextPositioningElement.h \ + V8SVGTitleElement.h \ + V8SVGTransform.h \ + V8SVGTransformList.h \ + V8SVGUnitTypes.h \ + V8SVGUseElement.h \ + V8SVGViewElement.h \ + V8SVGPreserveAspectRatio.h \ + V8SVGElement.h \ + V8SVGElementInstance.h \ + V8SVGElementInstanceList.h \ + V8SVGSVGElement.h \ + V8SVGEllipseElement.h \ + V8SVGFEBlendElement.h \ + V8SVGFEColorMatrixElement.h \ + V8SVGFEComponentTransferElement.h \ + V8SVGFECompositeElement.h \ + V8SVGFEDiffuseLightingElement.h \ + V8SVGFEDisplacementMapElement.h \ + V8SVGFEDistantLightElement.h \ + V8SVGFEFloodElement.h \ + V8SVGFEFuncAElement.h \ + V8SVGFEFuncBElement.h \ + V8SVGFEFuncGElement.h \ + V8SVGFEFuncRElement.h \ + V8SVGFEGaussianBlurElement.h \ + V8SVGFEImageElement.h \ + V8SVGFEMergeElement.h \ + V8SVGFEMergeNodeElement.h \ + V8SVGFEOffsetElement.h \ + V8SVGFEPointLightElement.h \ + V8SVGFESpecularLightingElement.h \ + V8SVGFESpotLightElement.h \ + V8SVGFETileElement.h \ + V8SVGFETurbulenceElement.h \ + V8SVGFilterElement.h \ + V8SVGFontElement.h \ + V8SVGFontFaceElement.h \ + V8SVGFontFaceFormatElement.h \ + V8SVGFontFaceNameElement.h \ + V8SVGFontFaceSrcElement.h \ + V8SVGFontFaceUriElement.h \ + V8SVGForeignObjectElement.h \ + V8SVGGElement.h \ + V8SVGGlyphElement.h \ + V8SVGGradientElement.h \ + V8SVGImageElement.h \ + V8SVGLength.h \ + V8SVGLengthList.h \ + V8SVGLineElement.h \ + V8SVGLinearGradientElement.h \ + V8SVGMaskElement.h \ + V8SVGMarkerElement.h \ + V8SVGMissingGlyphElement.h \ + V8SVGTransform.h \ + V8SVGZoomEvent.h \ + V8Screen.h \ + V8StyleSheet.h \ + V8StyleSheetList.h \ + V8Text.h \ + V8TextMetrics.h \ + V8TextEvent.h \ + V8TimeRanges.h \ + V8TreeWalker.h \ + V8UIEvent.h \ + V8VoidCallback.h \ + V8WebKitAnimationEvent.h \ + V8WebKitCSSKeyframeRule.h \ + V8WebKitCSSKeyframesRule.h \ + V8WebKitCSSMatrix.h \ + V8WebKitCSSTransformValue.h \ + V8WebKitPoint.h \ + V8WebKitTransitionEvent.h \ + V8WheelEvent.h \ + V8Worker.h \ + V8WorkerContext.h \ + V8WorkerLocation.h \ + V8WorkerNavigator.h \ + V8XMLHttpRequest.h \ + V8XMLHttpRequestException.h \ + V8XMLHttpRequestProgressEvent.h \ + V8XMLHttpRequestUpload.h \ + V8XMLSerializer.h \ + V8XPathEvaluator.h \ + V8XPathException.h \ + V8XPathExpression.h \ + V8XPathNSResolver.h \ + V8XPathResult.h \ + V8XSLTProcessor.h \ + SVGElementFactory.cpp \ + SVGNames.cpp \ + HTMLNames.cpp \ + UserAgentStyleSheets.h \ + XLinkNames.cpp \ + XMLNames.cpp \ + XPathGrammar.cpp \ + tokenizer.cpp \ + V8Clipboard.h \ + V8InspectorController.h \ + V8Location.h \ + V8Navigator.h \ + V8MimeType.h \ + V8MimeTypeArray.h \ + V8Plugin.h \ + V8PluginArray.h \ + V8RGBColor.h \ + V8SVGAnimatedPoints.h \ + V8SVGURIReference.h \ + V8UndetectableHTMLCollection.h \ +# + +# CSS property names and value keywords + +WEBCORE_CSS_PROPERTY_NAMES := $(WebCore)/css/CSSPropertyNames.in +WEBCORE_CSS_VALUE_KEYWORDS := $(WebCore)/css/CSSValueKeywords.in + +ifeq ($(findstring ENABLE_SVG,$(FEATURE_DEFINES)), ENABLE_SVG) + WEBCORE_CSS_PROPERTY_NAMES := $(WEBCORE_CSS_PROPERTY_NAMES) $(WebCore)/css/SVGCSSPropertyNames.in + WEBCORE_CSS_VALUE_KEYWORDS := $(WEBCORE_CSS_VALUE_KEYWORDS) $(WebCore)/css/SVGCSSValueKeywords.in +endif + +# Chromium does not support this. +#ifeq ($(ENABLE_DASHBOARD_SUPPORT), 1) +# WEBCORE_CSS_PROPERTY_NAMES := $(WEBCORE_CSS_PROPERTY_NAMES) $(WebCore)/css/DashboardSupportCSSPropertyNames.in +#endif + +CSSPropertyNames.h : $(WEBCORE_CSS_PROPERTY_NAMES) css/makeprop.pl + if dos2unix $(WEBCORE_CSS_PROPERTY_NAMES) | sort | uniq -d | grep -E '^[^#]'; then echo 'Duplicate value!'; exit 1; fi + cat $(WEBCORE_CSS_PROPERTY_NAMES) > CSSPropertyNames.in + perl "$(WebCore)/css/makeprop.pl" + +CSSValueKeywords.h : $(WEBCORE_CSS_VALUE_KEYWORDS) css/makevalues.pl + # Lower case all the values, as CSS values are case-insensitive + perl -ne 'print lc' $(WEBCORE_CSS_VALUE_KEYWORDS) > CSSValueKeywords.in + if dos2unix CSSValueKeywords.in | sort | uniq -d | grep -E '^[^#]'; then echo 'Duplicate value!'; exit 1; fi + perl "$(WebCore)/css/makevalues.pl" + +# DOCTYPE strings + +DocTypeStrings.cpp : html/DocTypeStrings.gperf + gperf -CEot -L ANSI-C -k "*" -N findDoctypeEntry -F ,PubIDInfo::eAlmostStandards,PubIDInfo::eAlmostStandards $< > $@ + +# HTML entity names + +HTMLEntityNames.c : html/HTMLEntityNames.gperf + gperf -a -L ANSI-C -C -G -c -o -t -k '*' -N findEntity -D -s 2 $< > $@ + +# color names + +ColorData.c : platform/ColorData.gperf + gperf -CDEot -L ANSI-C -k '*' -N findColor -D -s 2 $< > $@ + +# CSS tokenizer + +tokenizer.cpp : css/tokenizer.flex css/maketokenizer + flex -t $< | perl $(WebCore)/css/maketokenizer > $@ + +# CSS grammar +# NOTE: older versions of bison do not inject an inclusion guard, so we do it + +CSSGrammar.cpp : css/CSSGrammar.y + bison -d -p cssyy $< -o $@ + touch CSSGrammar.cpp.h + touch CSSGrammar.hpp + echo '#ifndef CSSGrammar_h' > CSSGrammar.h + echo '#define CSSGrammar_h' >> CSSGrammar.h + cat CSSGrammar.cpp.h CSSGrammar.hpp >> CSSGrammar.h + echo '#endif' >> CSSGrammar.h + rm -f CSSGrammar.cpp.h CSSGrammar.hpp + +# XPath grammar +# NOTE: older versions of bison do not inject an inclusion guard, so we do it + +XPathGrammar.cpp : xml/XPathGrammar.y $(PROJECT_FILE) + bison -d -p xpathyy $< -o $@ + touch XPathGrammar.cpp.h + touch XPathGrammar.hpp + echo '#ifndef XPathGrammar_h' > XPathGrammar.h + echo '#define XPathGrammar_h' >> XPathGrammar.h + cat XPathGrammar.cpp.h XPathGrammar.hpp >> XPathGrammar.h + echo '#endif' >> XPathGrammar.h + rm -f XPathGrammar.cpp.h XPathGrammar.hpp + +# user agent style sheets + +USER_AGENT_STYLE_SHEETS = $(WebCore)/css/html4.css $(WebCore)/css/quirks.css $(WebCore)/css/view-source.css $(WebCore)/css/themeWin.css $(WebCore)/css/themeWinQuirks.css + +ifeq ($(findstring ENABLE_SVG,$(FEATURE_DEFINES)), ENABLE_SVG) + USER_AGENT_STYLE_SHEETS := $(USER_AGENT_STYLE_SHEETS) $(WebCore)/css/svg.css +endif + +ifeq ($(findstring ENABLE_WML,$(FEATURE_DEFINES)), ENABLE_WML) + USER_AGENT_STYLE_SHEETS := $(USER_AGENT_STYLE_SHEETS) $(WebCore)/css/wml.css +endif + +ifeq ($(findstring ENABLE_VIDEO,$(FEATURE_DEFINES)), ENABLE_VIDEO) + USER_AGENT_STYLE_SHEETS := $(USER_AGENT_STYLE_SHEETS) $(WebCore)/css/mediaControls.css +endif + +UserAgentStyleSheets.h : css/make-css-file-arrays.pl $(USER_AGENT_STYLE_SHEETS) + perl $< $@ UserAgentStyleSheetsData.cpp $(USER_AGENT_STYLE_SHEETS) + +# character set name table + +CharsetData.cpp : platform/text/mac/make-charset-table.pl platform/text/mac/character-sets.txt $(ENCODINGS_FILE) + perl $^ $(ENCODINGS_PREFIX) > $@ + +# lookup tables for old-style JavaScript bindings + +%.lut.h: %.cpp $(CREATE_HASH_TABLE) + $(CREATE_HASH_TABLE) $< > $@ +%Table.cpp: %.cpp $(CREATE_HASH_TABLE) + $(CREATE_HASH_TABLE) $< > $@ + +# -------- + +# HTML tag and attribute names + +ifeq ($(findstring ENABLE_VIDEO,$(FEATURE_DEFINES)), ENABLE_VIDEO) + HTML_FLAGS := $(HTML_FLAGS) ENABLE_VIDEO=1 +endif + +ifdef HTML_FLAGS + +HTMLElementFactory.cpp HTMLNames.cpp : dom/make_names.pl html/HTMLTagNames.in html/HTMLAttributeNames.in + perl -I $(WebCore)/bindings/scripts $< --tags $(WebCore)/html/HTMLTagNames.in --attrs $(WebCore)/html/HTMLAttributeNames.in --factory --wrapperFactory --extraDefines "$(HTML_FLAGS)" + +else + +HTMLElementFactory.cpp HTMLNames.cpp : dom/make_names.pl html/HTMLTagNames.in html/HTMLAttributeNames.in + perl -I $(WebCore)/bindings/scripts $< --tags $(WebCore)/html/HTMLTagNames.in --attrs $(WebCore)/html/HTMLAttributeNames.in --factory --wrapperFactory + +endif + +XMLNames.cpp : dom/make_names.pl xml/xmlattrs.in + perl -I $(WebCore)/bindings/scripts $< --attrs $(WebCore)/xml/xmlattrs.in + +# -------- + +ifeq ($(findstring ENABLE_SVG,$(FEATURE_DEFINES)), ENABLE_SVG) + +WEBCORE_EXPORT_DEPENDENCIES := $(WEBCORE_EXPORT_DEPENDENCIES) WebCore.SVG.exp + +ifeq ($(findstring ENABLE_SVG_USE,$(FEATURE_DEFINES)), ENABLE_SVG_USE) + SVG_FLAGS := $(SVG_FLAGS) ENABLE_SVG_USE=1 +endif + +ifeq ($(findstring ENABLE_SVG_FONTS,$(FEATURE_DEFINES)), ENABLE_SVG_FONTS) + SVG_FLAGS := $(SVG_FLAGS) ENABLE_SVG_FONTS=1 +endif + +ifeq ($(findstring ENABLE_SVG_FILTERS,$(FEATURE_DEFINES)), ENABLE_SVG_FILTERS) + SVG_FLAGS := $(SVG_FLAGS) ENABLE_SVG_FILTERS=1 + WEBCORE_EXPORT_DEPENDENCIES := $(WEBCORE_EXPORT_DEPENDENCIES) WebCore.SVG.Filters.exp +endif + +ifeq ($(findstring ENABLE_SVG_AS_IMAGE,$(FEATURE_DEFINES)), ENABLE_SVG_AS_IMAGE) + SVG_FLAGS := $(SVG_FLAGS) ENABLE_SVG_AS_IMAGE=1 +endif + +ifeq ($(findstring ENABLE_SVG_ANIMATION,$(FEATURE_DEFINES)), ENABLE_SVG_ANIMATION) + SVG_FLAGS := $(SVG_FLAGS) ENABLE_SVG_ANIMATION=1 + WEBCORE_EXPORT_DEPENDENCIES := $(WEBCORE_EXPORT_DEPENDENCIES) WebCore.SVG.Animation.exp +endif + +ifeq ($(findstring ENABLE_SVG_FOREIGN_OBJECT,$(FEATURE_DEFINES)), ENABLE_SVG_FOREIGN_OBJECT) + SVG_FLAGS := $(SVG_FLAGS) ENABLE_SVG_FOREIGN_OBJECT=1 + WEBCORE_EXPORT_DEPENDENCIES := $(WEBCORE_EXPORT_DEPENDENCIES) WebCore.SVG.ForeignObject.exp +endif + +# SVG tag and attribute names (need to pass an extra flag if svg experimental features are enabled) + +ifdef SVG_FLAGS + +SVGElementFactory.cpp SVGNames.cpp : dom/make_names.pl svg/svgtags.in svg/svgattrs.in + perl -I $(WebCore)/bindings/scripts $< --tags $(WebCore)/svg/svgtags.in --attrs $(WebCore)/svg/svgattrs.in --extraDefines "$(SVG_FLAGS)" --factory --wrapperFactory +else + +SVGElementFactory.cpp SVGNames.cpp : dom/make_names.pl svg/svgtags.in svg/svgattrs.in + perl -I $(WebCore)/bindings/scripts $< --tags $(WebCore)/svg/svgtags.in --attrs $(WebCore)/svg/svgattrs.in --factory --wrapperFactory + +endif + +JSSVGElementWrapperFactory.cpp : SVGNames.cpp + +XLinkNames.cpp : dom/make_names.pl svg/xlinkattrs.in + perl -I $(WebCore)/bindings/scripts $< --attrs $(WebCore)/svg/xlinkattrs.in + +else + +SVGElementFactory.cpp : + echo > $@ + +SVGNames.cpp : + echo > $@ + +XLinkNames.cpp : + echo > $@ + +# This file is autogenerated by make_names.pl when SVG is enabled. + +JSSVGElementWrapperFactory.cpp : + echo > $@ + +endif + +# new-style Objective-C bindings + +OBJC_BINDINGS_SCRIPTS = \ + bindings/scripts/CodeGenerator.pm \ + bindings/scripts/CodeGeneratorObjC.pm \ + bindings/scripts/IDLParser.pm \ + bindings/scripts/IDLStructure.pm \ + bindings/scripts/generate-bindings.pl \ +# + +DOM%.h : %.idl $(OBJC_BINDINGS_SCRIPTS) $(PUBLICDOMINTERFACES) + perl -I $(WebCore)/bindings/scripts $(WebCore)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_OBJECTIVE_C" --generator ObjC --include dom --include html --include css --include page --include xml --include svg --include bindings/js --include plugins --outputdir . $< + +# new-style JavaScript bindings + +JS_BINDINGS_SCRIPTS = \ + bindings/scripts/CodeGenerator.pm \ + bindings/scripts/CodeGeneratorJS.pm \ + bindings/scripts/IDLParser.pm \ + bindings/scripts/IDLStructure.pm \ + bindings/scripts/generate-bindings.pl \ +# + +JS%.h : %.idl $(JS_BINDINGS_SCRIPTS) + perl -I $(WebCore)/bindings/scripts $(WebCore)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --include css --include page --include xml --include svg --include bindings/js --include plugins --outputdir . $< + +# new-style V8 bindings + +V8_SCRIPTS = \ + $(PORTROOT)/bindings/scripts/CodeGenerator.pm \ + $(PORTROOT)/bindings/scripts/CodeGeneratorV8.pm \ + $(PORTROOT)/bindings/scripts/IDLParser.pm \ + $(WebCore)/bindings/scripts/IDLStructure.pm \ + $(PORTROOT)/bindings/scripts/generate-bindings.pl \ +# + +# Sometimes script silently fails (Cygwin problem?), +# use a bounded loop to retry if so, but not do so forever. +V8%.h : %.idl $(V8_SCRIPTS) + rm -f $@; \ + for i in 1 2 3 4 5 6 7 8 9 10; do \ + if test -e $@; then break; fi; \ + perl -w -I $(PORTROOT)/bindings/scripts -I $(WebCore)/bindings/scripts $(PORTROOT)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT V8_BINDING" --generator V8 --include svg --include dom --include html --include css --include page --include xml --include plugins --outputdir . $< ; \ + done diff --git a/V8Binding/scripts/CodeGenerator.pm b/V8Binding/scripts/CodeGenerator.pm new file mode 100644 index 0000000..d115459 --- /dev/null +++ b/V8Binding/scripts/CodeGenerator.pm @@ -0,0 +1,334 @@ +# +# KDOM IDL parser +# +# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org> +# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> +# +# This file is part of the KDE project +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# aint with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +package CodeGenerator; + +my $useDocument = ""; +my $useGenerator = ""; +my $useOutputDir = ""; +my $useDirectories = ""; +my $useLayerOnTop = 0; +my $preprocessor; + +my $codeGenerator = 0; + +my $verbose = 0; + +my %primitiveTypeHash = ("int" => 1, "short" => 1, "long" => 1, "long long" => 1, + "unsigned int" => 1, "unsigned short" => 1, + "unsigned long" => 1, "float" => 1, + "unsigned long long" => 1, + "double" => 1, "boolean" => 1, "void" => 1); + +my %podTypeHash = ("SVGNumber" => 1, "SVGTransform" => 1); +my %podTypeWithWriteablePropertiesHash = ("SVGLength" => 1, "SVGMatrix" => 1, "SVGPoint" => 1, "SVGRect" => 1); +my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1); + +my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1, "SVGPaintType" => 1); + +my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1, + "SVGAnimatedEnumeration" => 1, "SVGAnimatedInteger" => 1, + "SVGAnimatedLength" => 1, "SVGAnimatedLengthList" => 1, + "SVGAnimatedNumber" => 1, "SVGAnimatedNumberList" => 1, + "SVGAnimatedPreserveAspectRatio" => 1, + "SVGAnimatedRect" => 1, "SVGAnimatedString" => 1, + "SVGAnimatedTransformList" => 1); + +# Helpers for 'ScanDirectory' +my $endCondition = 0; +my $foundFilename = ""; +my @foundFilenames = (); +my $ignoreParent = 1; +my $defines = ""; + +# Default constructor +sub new +{ + my $object = shift; + my $reference = { }; + + $useDirectories = shift; + $useGenerator = shift; + $useOutputDir = shift; + $useLayerOnTop = shift; + $preprocessor = shift; + + bless($reference, $object); + return $reference; +} + +sub StripModule($) +{ + my $object = shift; + my $name = shift; + $name =~ s/[a-zA-Z0-9]*:://; + return $name; +} + +sub ProcessDocument +{ + my $object = shift; + $useDocument = shift; + $defines = shift; + + my $ifaceName = "CodeGenerator" . $useGenerator; + + # Dynamically load external code generation perl module + require $ifaceName . ".pm"; + $codeGenerator = $ifaceName->new($object, $useOutputDir, $useLayerOnTop, $preprocessor); + unless (defined($codeGenerator)) { + my $classes = $useDocument->classes; + foreach my $class (@$classes) { + print "Skipping $useGenerator code generation for IDL interface \"" . $class->name . "\".\n" if $verbose; + } + return; + } + + # Start the actual code generation! + $codeGenerator->GenerateModule($useDocument, $defines); + + my $classes = $useDocument->classes; + foreach my $class (@$classes) { + print "Generating $useGenerator bindings code for IDL interface \"" . $class->name . "\"...\n" if $verbose; + $codeGenerator->GenerateInterface($class, $defines); + $codeGenerator->finish(); + } +} + + +sub FindParentsRecursively +{ + my $object = shift; + my $dataNode = shift; + my @parents = ($dataNode->name); + foreach (@{$dataNode->parents}) { + my $interface = $object->StripModule($_); + + $endCondition = 0; + $foundFilename = ""; + foreach (@{$useDirectories}) { + $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq ""); + } + + if ($foundFilename ne "") { + print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose; + + # Step #2: Parse the found IDL file (in quiet mode). + my $parser = IDLParser->new(1); + my $document = $parser->ParseInheritance($foundFilename, $defines, $preprocessor); + + foreach my $class (@{$document->classes}) { + @parents = (@parents, FindParentsRecursively($object, $class)); + } + } else { + die("Could NOT find specified parent interface \"$interface\"!\n") + } + } + return @parents; +} + + +sub AddMethodsConstantsAndAttributesFromParentClasses +{ + # For the passed interface, recursively parse all parent + # IDLs in order to find out all inherited properties/methods. + + my $object = shift; + my $dataNode = shift; + + my @parents = @{$dataNode->parents}; + my $parentsMax = @{$dataNode->parents}; + + my $constantsRef = $dataNode->constants; + my $functionsRef = $dataNode->functions; + my $attributesRef = $dataNode->attributes; + + # Exception: For the DOM 'Node' is our topmost baseclass, not EventTargetNode. + foreach (@{$dataNode->parents}) { + my $interface = $object->StripModule($_); + + # Don't ignore the first class EventTarget + if ($interface ne "EventTarget" && $ignoreParent) { + # Ignore first parent class, already handled by the generation itself. + $ignoreParent = 0; + next; + } + + # Step #1: Find the IDL file associated with 'interface' + $endCondition = 0; + $foundFilename = ""; + + foreach (@{$useDirectories}) { + $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq ""); + } + + if ($foundFilename ne "") { + print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose; + + # Step #2: Parse the found IDL file (in quiet mode). + my $parser = IDLParser->new(1); + my $document = $parser->Parse($foundFilename, $defines, $preprocessor); + + foreach my $class (@{$document->classes}) { + # Step #3: Enter recursive parent search + AddMethodsConstantsAndAttributesFromParentClasses($object, $class); + + # Step #4: Collect constants & functions & attributes of this parent-class + my $constantsMax = @{$class->constants}; + my $functionsMax = @{$class->functions}; + my $attributesMax = @{$class->attributes}; + + print " | |> -> Inheriting $constantsMax constants, $functionsMax functions, $attributesMax attributes...\n | |>\n" if $verbose; + + # Step #5: Concatenate data + push(@$constantsRef, $_) foreach (@{$class->constants}); + push(@$functionsRef, $_) foreach (@{$class->functions}); + push(@$attributesRef, $_) foreach (@{$class->attributes}); + } + } else { + die("Could NOT find specified parent interface \"$interface\"!\n"); + } + } +} + +# Append an attribute to an array if its name does not exist in the array. +sub AppendAttribute +{ + my $attributes = shift; + my $newAttr = shift; + foreach (@$attributes) { + if ($_->signature->name eq $newAttr->signature->name) { + print " | |> -> $newAttr->signature->name is overridden.\n | |>\n" if $verbose; + return; + } + } + push(@$attributes, $newAttr); +} + +# Helpers for all CodeGenerator***.pm modules +sub IsPodType +{ + my $object = shift; + my $type = shift; + + return 1 if $podTypeHash{$type}; + return 1 if $podTypeWithWriteablePropertiesHash{$type}; + return 0; +} + +sub IsPodTypeWithWriteableProperties +{ + my $object = shift; + my $type = shift; + + return 1 if $podTypeWithWriteablePropertiesHash{$type}; + return 0; +} + +sub IsPrimitiveType +{ + my $object = shift; + my $type = shift; + + return 1 if $primitiveTypeHash{$type}; + return 0; +} + +sub IsStringType +{ + my $object = shift; + my $type = shift; + + return 1 if $stringTypeHash{$type}; + return 0; +} + +sub IsNonPointerType +{ + my $object = shift; + my $type = shift; + + return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type}; + return 0; +} + +sub IsSVGAnimatedType +{ + my $object = shift; + my $type = shift; + + return 1 if $svgAnimatedTypeHash{$type}; + return 0; +} + +# Internal Helper +sub ScanDirectory +{ + my $object = shift; + + my $interface = shift; + my $directory = shift; + my $useDirectory = shift; + my $reportAllFiles = shift; + + print "Scanning interface " . $interface . " in " . $directory . "\n" if $verbose; + + return if ($endCondition eq 1) and ($reportAllFiles eq 0); + + my $sourceRoot = $ENV{SOURCE_ROOT}; + my $thisDir = $sourceRoot ? "$sourceRoot/$directory" : $directory; + + opendir(DIR, $thisDir) or die "[ERROR] Can't open directory $thisDir: \"$!\"\n"; + + my @names = readdir(DIR) or die "[ERROR] Cant't read directory $thisDir \"$!\"\n"; + closedir(DIR); + + foreach my $name (@names) { + # Skip if we already found the right file or + # if we encounter 'exotic' stuff (ie. '.', '..', '.svn') + next if ($endCondition eq 1) or ($name =~ /^\./); + + # Recurisvely enter directory + if (-d "$thisDir/$name") { + $object->ScanDirectory($interface, "$directory/$name", $useDirectory, $reportAllFiles); + next; + } + + # Check wheter we found the desired file + my $condition = ($name eq $interface); + $condition = 1 if ($interface eq "allidls") and ($name =~ /\.idl$/); + + if ($condition) { + $foundFilename = "$thisDir/$name"; + + if ($reportAllFiles eq 0) { + $endCondition = 1; + } else { + push(@foundFilenames, $foundFilename); + } + } + } +} + +1; diff --git a/V8Binding/scripts/CodeGeneratorV8.pm b/V8Binding/scripts/CodeGeneratorV8.pm new file mode 100644 index 0000000..5bb69cb --- /dev/null +++ b/V8Binding/scripts/CodeGeneratorV8.pm @@ -0,0 +1,2178 @@ + +# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> +# Copyright (C) 2006 Anders Carlsson <andersca@mac.com> +# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> +# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> +# Copyright (C) 2006 Apple Computer, Inc. +# Copyright (C) 2007 Google Inc. +# +# This file is part of the KDE project +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# aint with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +package CodeGeneratorV8; + +use File::stat; + +my $module = ""; +my $outputDir = ""; + +my @headerContent = (); +my @implContentHeader = (); +my @implFixedHeader = (); +my @implContent = (); +my @implContentDecls = (); +my %implIncludes = (); + +my @allParents = (); + +# Default .h template +my $headerTemplate = << "EOF"; +/* + This file is part of the WebKit open source project. + This file has been generated by generate-bindings.pl. DO NOT MODIFY! + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +EOF + +# Default constructor +sub new +{ + my $object = shift; + my $reference = { }; + + $codeGenerator = shift; + $outputDir = shift; + + bless($reference, $object); + return $reference; +} + +sub finish +{ + my $object = shift; + + # Commit changes! + $object->WriteData(); +} + +sub leftShift($$) { + my ($value, $distance) = @_; + return (($value << $distance) & 0xFFFFFFFF); +} + +# Uppercase the first letter, while respecting WebKit style guidelines. +# E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang. +sub WK_ucfirst +{ + my $param = shift; + my $ret = ucfirst($param); + $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/; + return $ret; +} + +# Lowercase the first letter while respecting WebKit style guidelines. +# URL becomes url, but SetURL becomes setURL. +sub WK_lcfirst +{ + my $param = shift; + my $ret = lcfirst($param); + $ret =~ s/uRL/url/; + return $ret; +} + +# Params: 'domClass' struct +sub GenerateInterface +{ + my $object = shift; + my $dataNode = shift; + my $defines = shift; + + # Start actual generation + $object->GenerateHeader($dataNode); + $object->GenerateImplementation($dataNode); + + my $name = $dataNode->name; + + # Open files for writing + my $headerFileName = "$outputDir/V8$name.h"; + my $implFileName = "$outputDir/V8$name.cpp"; + + open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName"; + open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName"; +} + +# Params: 'idlDocument' struct +sub GenerateModule +{ + my $object = shift; + my $dataNode = shift; + + $module = $dataNode->module; +} + +sub GetLegacyHeaderIncludes +{ + my $legacyParent = shift; + + die "Don't know what headers to include for module $module"; +} + +sub AvoidInclusionOfType +{ + my $type = shift; + + # Special case: SVGRect.h / SVGPoint.h / SVGNumber.h / SVGMatrix.h do not exist. + return 1 if $type eq "SVGRect" or $type eq "SVGPoint" or $type eq "SVGNumber" or $type eq "SVGMatrix"; + return 0; +} + +sub UsesManualToJSImplementation +{ + my $type = shift; + + return 1 if $type eq "SVGPathSeg"; + return 0; +} + +sub AddIncludesForType +{ + my $type = $codeGenerator->StripModule(shift); + + # When we're finished with the one-file-per-class + # reorganization, we won't need these special cases. + if ($codeGenerator->IsPrimitiveType($type) or AvoidInclusionOfType($type) +# jhaas: there doesn't seem to be any harm in leaving these in +# or $type eq "DOMString" or $type eq "DOMObject" or $type eq "RGBColor" or $type eq "Rect") { + ) { + } elsif ($type =~ /SVGPathSeg/) { + $joinedName = $type; + $joinedName =~ s/Abs|Rel//; + $implIncludes{"${joinedName}.h"} = 1; + } else { + # default, include the same named file + $implIncludes{GetImplementationFileName(${type})} = 1; + } + + # additional includes (things needed to compile the bindings but not the header) + + if ($type eq "CanvasRenderingContext2D") { + $implIncludes{"CanvasGradient.h"} = 1; + $implIncludes{"CanvasPattern.h"} = 1; + $implIncludes{"CanvasStyle.h"} = 1; + } + + if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") { + $implIncludes{"PlatformString.h"} = 1; + } + + if ($type eq "CSSStyleDeclaration") { + $implIncludes{"CSSMutableStyleDeclaration.h"} = 1; + } + + if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") { + # So we can get String -> AtomicString conversion for namedItem(). + $implIncludes{"AtomicString.h"} = 1; + } +} + +sub AddIncludesForSVGAnimatedType +{ + my $type = shift; + $type =~ s/SVGAnimated//; + + if ($type eq "Point" or $type eq "Rect") { + $implIncludes{"Float$type.h"} = 1; + } elsif ($type eq "String") { + $implIncludes{"PlatformString.h"} = 1; + } + + $implIncludes{"SVGAnimatedTemplate.h"} = 1; +} + +sub AddClassForwardIfNeeded +{ + my $implClassName = shift; + + # SVGAnimatedLength/Number/etc.. are typedefs to SVGAnimtatedTemplate, so don't use class forwards for them! + push(@headerContent, "class $implClassName;\n\n") unless $codeGenerator->IsSVGAnimatedType($implClassName); +} + +sub GetImplementationFileName +{ + my $iface = shift; + return "HTMLCollection.h" if $iface eq "UndetectableHTMLCollection"; + return "Event.h" if $iface eq "DOMTimeStamp"; + return "NamedAttrMap.h" if $iface eq "NamedNodeMap"; + return "NameNodeList.h" if $iface eq "NodeList"; + return "XMLHttpRequest.h" if $iface eq "XMLHttpRequest"; + + return "${iface}.h"; +} + +sub GenerateHeader +{ + my $object = shift; + my $dataNode = shift; + + my $interfaceName = $dataNode->name; + my $className = "V8$interfaceName"; + my $implClassName = $interfaceName; + + # Copy contents of parent classes except the first parent or if it is + # EventTarget. + $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode); + + my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; + my $conditional = $dataNode->extendedAttributes->{"Conditional"}; + + # - Add default header template + @headerContent = split("\r", $headerTemplate); + + # - Add header protection + if ($className =~ /^V8SVG/) { + push(@headerContent, "\n#if ENABLE(SVG)\n"); + } elsif (IsVideoClassName($className)) { + push(@headerContent, "\n#if ENABLE(VIDEO)\n"); + } elsif (IsWorkerClassName($className)) { + push(@headerContent, "\n#if ENABLE(WORKERS)\n"); + } + + push(@headerContent, "\n#ifndef $className" . "_H"); + push(@headerContent, "\n#define $className" . "_H\n\n"); + + # Get correct pass/store types respecting PODType flag + my $podType = $dataNode->extendedAttributes->{"PODType"}; + my $passType = $podType ? "JSSVGPODTypeWrapper<$podType>*" : "$implClassName*"; + + push(@headerContent, "#include \"$podType.h\"\n") if $podType and ($podType ne "double" and $podType ne "float" and $podType ne "RGBA32"); + + push(@headerContent, "#include <v8.h>\n"); + push(@headerContent, "#include <wtf/HashMap.h>\n"); + push(@headerContent, "#include \"StringHash.h\"\n"); + + push(@headerContent, "\nnamespace WebCore {\n\n"); + push(@headerContent, "class V8ClassIndex;\n"); + push(@headerContent, "\nclass $className {\n"); + push(@headerContent, <<END); + + public: + static bool HasInstance(v8::Handle<v8::Value> value); + static v8::Persistent<v8::FunctionTemplate> GetRawTemplate(); +END + + if ($implClassName eq "DOMWindow") { + push(@headerContent, <<END); + static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate(); +END + } + + push(@headerContent, <<END); + + private: + static v8::Persistent<v8::FunctionTemplate> GetTemplate(); + + friend class V8ClassIndex; +}; + +END + + push(@headerContent, "}\n\n"); + push(@headerContent, "#endif // $className" . "_H\n"); + + if ($className =~ /^V8SVG/) { + push(@headerContent, "\n#endif // ENABLE(SVG)\n"); + } elsif (IsVideoClassName($className)) { + push(@headerContent, "\n#endif // ENABLE(VIDEO)\n"); + } elsif (IsWorkerClassName($className)) { + push(@headerContent, "\n#endif // ENABLE(WORKERS)\n"); + } +} + + +sub GenerateSetDOMException +{ + my $indent = shift; + my $result = ""; + + $result .= $indent . "if (ec) {\n"; + $result .= $indent . " V8Proxy::SetDOMException(ec);\n"; + $result .= $indent . " return v8::Handle<v8::Value>();\n"; + $result .= $indent . "}\n"; + + return $result; +} + +sub IsNodeSubType +{ + my $dataNode = shift; + return 1 if ($dataNode->name eq "Node"); + foreach (@allParents) { + my $parent = $codeGenerator->StripModule($_); + return 1 if $parent eq "Node"; + } + return 0; +} + +sub HolderToNative +{ + my $dataNode = shift; + my $implClassName = shift; + my $classIndex = shift; + + if (IsNodeSubType($dataNode)) { + push(@implContentDecls, <<END); + $implClassName* imp = V8Proxy::DOMWrapperToNode<$implClassName>(holder); +END + + } else { + push(@implContentDecls, <<END); + $implClassName* imp = V8Proxy::ToNativeObject<$implClassName>(V8ClassIndex::$classIndex, holder); +END + + } +} + +sub GenerateDomainSafeFunctionGetter +{ + my $function = shift; + my $dataNode = shift; + my $classIndex = shift; + my $implClassName = shift; + + my $className = "V8" . $dataNode->name; + my $funcName = $function->signature->name; + + my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())"; + if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) { + $signature = "v8::Local<v8::Signature>()"; + } + + my $newTemplateString = GenerateNewFunctionTemplate($function, $dataNode, $signature); + + $implIncludes{"v8_proxy.h"} = 1; + + push(@implContentDecls, <<END); + static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { + INC_STATS(\"DOM.$implClassName.$funcName._get\"); + static v8::Persistent<v8::FunctionTemplate> private_template = + v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This()); + if (holder.IsEmpty()) { + // can only reach here by 'object.__proto__.func', and it should passed + // domain security check already + + return private_template->GetFunction(); + } +END + + HolderToNative($dataNode, $implClassName, $classIndex); + + push(@implContentDecls, <<END); + if (!V8Proxy::CanAccessFrame(imp->frame(), false)) { + static v8::Persistent<v8::FunctionTemplate> shared_template = + v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); + return shared_template->GetFunction(); + + } else { + return private_template->GetFunction(); + } + } + +END +} + +sub GenerateConstructorGetter +{ + my $implClassName = shift; + my $classIndex = shift; + + push(@implContentDecls, <<END); + static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { + INC_STATS(\"DOM.$implClassName.constructors._get\"); + v8::Handle<v8::Value> data = info.Data(); + ASSERT(data->IsNumber()); + V8ClassIndex::V8WrapperType type = V8ClassIndex::FromInt(data->Int32Value()); +END + + if ($classIndex eq "DOMWINDOW") { + push(@implContentDecls, <<END); + DOMWindow* window = V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder()); + Frame* frame = window->frame(); + if (frame) { + // Get the proxy corresponding to the DOMWindow if possible to + // make sure that the constructor function is constructed in the + // context of the DOMWindow and not in the context of the caller. + return V8Proxy::retrieve(frame)->GetConstructor(type); + } +END + } + + if ($classIndex eq "WORKERCONTEXT") { + $implIncludes{"WorkerContextExecutionProxy.h"} = 1; + push(@implContentDecls, <<END); + return WorkerContextExecutionProxy::retrieve()->GetConstructor(type); +END + } else { + push(@implContentDecls, " return V8Proxy::retrieve()->GetConstructor(type);"); + } + + push(@implContentDecls, <<END); + } + +END +} + +sub GenerateNormalAttrGetter +{ + my $attribute = shift; + my $dataNode = shift; + my $classIndex = shift; + my $implClassName = shift; + + my $attrExt = $attribute->signature->extendedAttributes; + + my $attrName = $attribute->signature->name; + $implIncludes{"v8_proxy.h"} = 1; + + my $attrType = $codeGenerator->StripModule($attribute->signature->type); + my $attrIsPodType = $codeGenerator->IsPodType($attrType); + my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0); + my $isPodType = $codeGenerator->IsPodType($implClassName); + my $skipContext = 0; + + + if ($isPodType) { + $implClassName = GetNativeType($implClassName); + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + } + + # Special case: SVGZoomEvent's attributes are all read-only + if ($implClassName eq "SVGZoomEvent") { + $attrIsPodType = 0; + $skipContext = 1; + } + + # Special case: SVGSVGEelement::viewport is read-only + if (($implClassName eq "SVGSVGElement") and ($attrName eq "viewport")) { + $attrIsPodType = 0; + $skipContext = 1; + } + + # Special case for SVGColor + if (($implClassName eq "SVGColor") and ($attrName eq "rgbColor")) { + $attrIsPodType = 0; + } + + my $getterStringUsesImp = $implClassName ne "double"; + + # Getter + push(@implContentDecls, <<END); + static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { + INC_STATS(\"DOM.$implClassName.$attrName._get\"); +END + + if ($isPodType) { + push(@implContentDecls, <<END); + V8SVGPODTypeWrapper<$implClassName>* imp_wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder()); + $implClassName imp_instance = *imp_wrapper; +END + if ($getterStringUsesImp) { + push(@implContentDecls, <<END); + $implClassName* imp = &imp_instance; +END + } + + } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) { + # perform lookup first + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This()); + if (holder.IsEmpty()) return v8::Undefined(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } else { + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = info.Holder(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } + + # Generate security checks if necessary + if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) { + push(@implContentDecls, " if (!V8Proxy::CheckNodeSecurity(imp->$attrName())) return v8::Undefined();\n\n"); + } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) { + push(@implContentDecls, " if (!V8Proxy::CheckNodeSecurity(imp->contentDocument())) return v8::Undefined();\n\n"); + } + + my $useExceptions = 1 if @{$attribute->getterExceptions} and !($isPodType); + if ($useExceptions) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, " ExceptionCode ec = 0;\n"); + } + + if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) { + $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"}; + } + + my $getterFunc = WK_lcfirst($attrName); + $getterFunc .= "Animated" if $codeGenerator->IsSVGAnimatedType($attribute->signature->type); + + my $returnType = $codeGenerator->StripModule($attribute->signature->type); + + my $getterString; + if ($getterStringUsesImp) { + $getterString = "imp->$getterFunc("; + $getterString .= "ec" if $useExceptions; + $getterString .= ")"; + if (IsRefPtrType($returnType)) { + $implIncludes{"wtf/GetPtr.h"} = 1; + $getterString = "WTF::getPtr(" . $getterString . ")"; + } + if ($nativeType eq "int" and + $attribute->signature->extendedAttributes->{"ConvertFromString"}) { + $getterString .= ".toInt()"; + } + } else { + $getterString = "imp_instance"; + } + if ($nativeType eq "String") { + $getterString = "ToString($getterString)"; + } + + my $result; + my $wrapper; + + if ($attrIsPodType) { + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + + my $getter = $getterString; + $getter =~ s/imp->//; + $getter =~ s/\(\)//; + my $setter = "set" . WK_ucfirst($getter); + + my $implClassIsAnimatedType = $codeGenerator->IsSVGAnimatedType($implClassName); + if (not $implClassIsAnimatedType + and $codeGenerator->IsPodTypeWithWriteableProperties($attrType) + and not defined $attribute->signature->extendedAttributes->{"Immutable"}) { + if ($codeGenerator->IsPodType($implClassName)) { + $wrapper = "new V8SVGStaticPODTypeWrapperWithPODTypeParent<$nativeType, $implClassName>($getterString, imp_wrapper)"; + } else { + $wrapper = "new V8SVGStaticPODTypeWrapperWithParent<$nativeType, $implClassName>(imp, &${implClassName}::$getter, &${implClassName}::$setter)"; + } + } else { + if ($implClassIsAnimatedType) { + $wrapper = "V8SVGDynamicPODTypeWrapperCache<$nativeType, $implClassName>::lookupOrCreateWrapper(imp, &${implClassName}::$getter, &${implClassName}::$setter)"; + } else { + $wrapper = GenerateSVGStaticPodTypeWrapper($returnType, $getterString); + } + } + + push(@implContentDecls, " void* wrapper = $wrapper;\n"); + } elsif ($nativeType ne "RGBColor") { + push(@implContentDecls, " $nativeType v = "); + + push(@implContentDecls, "$getterString;\n"); + + if ($useExceptions) { + push(@implContentDecls, GenerateSetDOMException(" ")); + } + + $result = "v"; + if (IsRefPtrType($returnType)) { + $result = "WTF::getPtr(" . $result . ")"; + } + } else { + # Special case: RGBColor is noncopyable + $result = $getterString; + } + + + if (IsSVGTypeNeedingContextParameter($attrType) && !$skipContext) { + my $resultObject = $result; + if ($attrIsPodType) { + $resultObject = "wrapper"; + } + + push(@implContentDecls, GenerateSVGContextAssignment($implClassName, $resultObject, " ")); + } + + if ($attrIsPodType) { + my $classIndex = uc($attrType); + push(@implContentDecls, " return V8Proxy::ToV8Object(V8ClassIndex::$classIndex, wrapper);\n"); + } else { + push(@implContentDecls, " return " . NativeToJSValue($attribute->signature, $result). ";\n"); + } + + push(@implContentDecls, " }\n\n"); # end of getter +} + + +sub GenerateReplaceableAttrSetter +{ + my $implClassName = shift; + + $implIncludes{"v8_proxy.h"} = 1; + + push(@implContentDecls, + " static void ${attrName}AttrSetter(v8::Local<v8::String> name," . + " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n"); + + push(@implContentDecls, " INC_STATS(\"DOM.$implClassName.$attrName._set\");\n"); + + push(@implContentDecls, " v8::Local<v8::String> ${attrName}_string = v8::String::New(\"${attrName}\");\n"); + push(@implContentDecls, " info.Holder()->Delete(${attrName}_string);\n"); + push(@implContentDecls, " info.This()->Set(${attrName}_string, value);\n"); + push(@implContentDecls, " }\n\n"); +} + + +sub GenerateNormalAttrSetter +{ + my $attribute = shift; + my $dataNode = shift; + my $classIndex = shift; + my $implClassName = shift; + + my $attrExt = $attribute->signature->extendedAttributes; + + $implIncludes{"v8_proxy.h"} = 1; + + push(@implContentDecls, + " static void ${attrName}AttrSetter(v8::Local<v8::String> name," . + " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n"); + + push(@implContentDecls, " INC_STATS(\"DOM.$implClassName.$attrName._set\");\n"); + + my $isPodType = $codeGenerator->IsPodType($implClassName); + + if ($isPodType) { + $implClassName = GetNativeType($implClassName); + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + push(@implContentDecls, " V8SVGPODTypeWrapper<$implClassName>* wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());\n"); + push(@implContentDecls, " $implClassName imp_instance = *wrapper;\n"); + push(@implContentDecls, " $implClassName* imp = &imp_instance;\n"); + + } elsif ($attrExt->{"v8OnProto"}) { + # perform lookup first + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This()); + if (holder.IsEmpty()) return v8::Undefined(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } else { + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = info.Holder(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } + + my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0); + push(@implContentDecls, " $nativeType v = " . JSValueToNative($attribute->signature, "value") . ";\n"); + + my $result = ""; + if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) { + $result .= "WebCore::String::number("; + } + $result .= "v"; + if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) { + $result .= ")"; + } + my $returnType = $codeGenerator->StripModule($attribute->signature->type); + if (IsRefPtrType($returnType)) { + $result = "WTF::getPtr(" . $result . ")"; + } + + my $useExceptions = 1 if @{$attribute->setterExceptions} and !($isPodType); + + if ($useExceptions) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, " ExceptionCode ec = 0;\n"); + } + + if ($implClassName eq "double") { + push(@implContentDecls, " *imp = $result;\n"); + } else { + push(@implContentDecls, " imp->set" . WK_ucfirst($attrName) . "(" . $result); + push(@implContentDecls, ", ec") if $useExceptions; + push(@implContentDecls, ");\n"); + } + + if ($useExceptions) { + push(@implContentDecls, " V8Proxy::SetDOMException(ec);\n"); + } + + if ($isPodType) { + push(@implContentDecls, " wrapper->commitChange(*imp, V8Proxy::GetSVGContext(wrapper));\n"); + } elsif (IsSVGTypeNeedingContextParameter($implClassName)) { + $implIncludes{"SVGElement.h"} = 1; + + my $currentObject = "imp"; + if ($isPodType) { + $currentObject = "wrapper"; + } + + push(@implContentDecls, " if (SVGElement* context = V8Proxy::GetSVGContext($currentObject)) {\n"); + push(@implContentDecls, " context->svgAttributeChanged(imp->associatedAttributeName());\n"); + push(@implContentDecls, " }\n"); + } + + push(@implContentDecls, " return;\n"); + push(@implContentDecls, " }\n\n"); # end of setter +} + + +sub GenerateNewFunctionTemplate +{ + $function = shift; + $dataNode = shift; + $signature = shift; + + my $interfaceName = $dataNode->name; + my $name = $function->signature->name; + + if ($function->signature->extendedAttributes->{"Custom"} || + $function->signature->extendedAttributes->{"V8Custom"}) { + if ($function->signature->extendedAttributes->{"Custom"} && + $function->signature->extendedAttributes->{"V8Custom"}) { + die "Custom and V8Custom should be mutually exclusive!" + } + my $customFunc = $function->signature->extendedAttributes->{"Custom"} || + $function->signature->extendedAttributes->{"V8Custom"}; + if ($customFunc eq 1) { + $customFunc = $interfaceName . WK_ucfirst($name); + } + return "v8::FunctionTemplate::New(V8Custom::v8${customFunc}Callback, v8::Handle<v8::Value>(), $signature)"; + } else { + return "v8::FunctionTemplate::New(${interfaceName}Internal::${name}Callback, v8::Handle<v8::Value>(), $signature)"; + } +} + + +sub GenerateFunctionCallback +{ + my $function = shift; + my $dataNode = shift; + my $classIndex = shift; + my $implClassName = shift; + + my $interfaceName = $dataNode->name; + my $name = $function->signature->name; + + push(@implContentDecls, +" static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) {\n" . +" INC_STATS(\"DOM.$implClassName.$name\");\n"); + + my $numParameters = @{$function->parameters}; + + if ($function->signature->extendedAttributes->{"RequiresAllArguments"}) { + push(@implContentDecls, + " if (args.Length() < $numParameters) return v8::Undefined();\n"); + } + + if ($codeGenerator->IsPodType($implClassName)) { + my $nativeClassName = GetNativeType($implClassName); + push(@implContentDecls, " V8SVGPODTypeWrapper<$nativeClassName>* imp_wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$nativeClassName> >(V8ClassIndex::$classIndex, args.Holder());\n"); + push(@implContentDecls, " $nativeClassName imp_instance = *imp_wrapper;\n"); + push(@implContentDecls, " $nativeClassName* imp = &imp_instance;\n"); + } else { + push(@implContentDecls, <<END); + v8::Handle<v8::Value> holder = args.Holder(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } + + # Check domain security if needed + if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} + || $interfaceName eq "DOMWindow") + && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) { + # We have not find real use cases yet. + push(@implContentDecls, +" if (!V8Proxy::CanAccessFrame(imp->frame(), true)) {\n". +" return v8::Undefined();\n" . +" }\n"); + } + + + if (@{$function->raisesExceptions}) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, " ExceptionCode ec = 0;\n"); + } + + if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { + push(@implContentDecls, " ScriptCallStack callStack(args, $numParameters);\n"); + $implIncludes{"ScriptCallStack.h"} = 1; + } + + my $paramIndex = 0; + foreach my $parameter (@{$function->parameters}) { + TranslateParameter($parameter); + + my $parameterName = $parameter->name; + + if ($parameter->extendedAttributes->{"Optional"}) { + # Generate early call if there are not enough parameters. + push(@implContentDecls, " if (args.Length() <= $paramIndex) {\n"); + my $functionCall = GenerateFunctionCallString($function, $paramIndex, " " x 2, $implClassName); + push(@implContentDecls, $functionCall); + push(@implContentDecls, " }\n"); + } + + if (BasicTypeCanFailConversion($parameter)) { + push(@implContentDecls, " bool ${parameterName}Ok;\n"); + } + + push(@implContentDecls, " " . GetNativeTypeFromSignature($parameter, 1) . " $parameterName = "); + push(@implContentDecls, JSValueToNative($parameter, "args[$paramIndex]", + BasicTypeCanFailConversion($parameter) ? "${parameterName}Ok" : undef) . ";\n"); + + if (TypeCanFailConversion($parameter)) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, +" if (!$parameterName" . (BasicTypeCanFailConversion($parameter) ? "Ok" : "") . ") {\n" . +" V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);\n" . +" return v8::Handle<v8::Value>();\n" . +" }\n"); + } + + if ($parameter->extendedAttributes->{"IsIndex"}) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, +" if ($parameterName < 0) {\n" . +" V8Proxy::SetDOMException(INDEX_SIZE_ERR);\n" . +" return v8::Handle<v8::Value>();\n" . +" }\n"); + } + + $paramIndex++; + } + + # Build the function call string. + my $callString = GenerateFunctionCallString($function, $paramIndex, " ", $implClassName); + push(@implContentDecls, "$callString"); + push(@implContentDecls, " }\n\n"); +} + + +sub GenerateBatchedAttributeData +{ + my $interfaceName = shift; + my $attributes = shift; + + foreach my $attribute (@$attributes) { + my $attrName = $attribute->signature->name; + my $attrExt = $attribute->signature->extendedAttributes; + + my $accessControl = "v8::DEFAULT"; + if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) { + $accessControl = "v8::ALL_CAN_READ"; + } elsif ($attrExt->{"DoNotCheckDomainSecurityOnSet"}) { + $accessControl = "v8::ALL_CAN_WRITE"; + } elsif ($attrExt->{"DoNotCheckDomainSecurity"}) { + $accessControl = "v8::ALL_CAN_READ"; + if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) { + $accessControl .= "|v8::ALL_CAN_WRITE"; + } + } + if ($attrExt->{"V8DisallowShadowing"}) { + $accessControl .= "|v8::PROHIBITS_OVERWRITING"; + } + $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")"; + + + my $customAccessor = + $attrExt->{"Custom"} || + $attrExt->{"CustomSetter"} || + $attrExt->{"CustomGetter"} || + $attrExt->{"V8Custom"} || + $attrExt->{"V8CustomSetter"} || + $attrExt->{"V8CustomGetter"} || + ""; + if ($customAccessor eq 1) { + # use the naming convension, interface + (capitalize) attr name + $customAccessor = $interfaceName . WK_ucfirst($attrName); + } + + my $getter; + my $setter; + my $propAttr = "v8::None"; + + # Check attributes. + if ($attrExt->{"DontEnum"}) { + $propAttr .= "|v8::DontEnum"; + } + if ($attrExt->{"V8DisallowShadowing"}) { + $propAttr .= "|v8::DontDelete"; + } + + my $on_proto = "0 /* on instance */"; + my $data = "V8ClassIndex::INVALID_CLASS_INDEX /* no data */"; + + # Constructor + if ($attribute->signature->type =~ /Constructor$/) { + my $constructorType = $codeGenerator->StripModule($attribute->signature->type); + $constructorType =~ s/Constructor$//; + my $constructorIndex = uc($constructorType); + $data = "V8ClassIndex::${constructorIndex}"; + $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter"; + $setter = "0"; + $propAttr = "v8::ReadOnly"; + + # EventListeners + } elsif ($attrExt->{"ProtectedListener"}) { + if ($interfaceName eq "DOMWindow") { + $getter = "V8Custom::v8DOMWindowEventHandlerAccessorGetter"; + $setter = "V8Custom::v8DOMWindowEventHandlerAccessorSetter"; + } else { + $getter = "V8Custom::v8ElementEventHandlerAccessorGetter"; + $setter = "V8Custom::v8ElementEventHandlerAccessorSetter"; + } + + # Custom Getter and Setter + } elsif ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { + $getter = "V8Custom::v8${customAccessor}AccessorGetter"; + if ($interfaceName eq "WorkerContext" and $attrName eq "self") { + $setter = "0"; + $propAttr = "v8::ReadOnly"; + } else { + $setter = "V8Custom::v8${customAccessor}AccessorSetter"; + } + + # Custom Setter + } elsif ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"}) { + $getter = "${interfaceName}Internal::${attrName}AttrGetter"; + $setter = "V8Custom::v8${customAccessor}AccessorSetter"; + + # Custom Getter + } elsif ($attrExt->{"CustomGetter"}) { + $getter = "V8Custom::v8${customAccessor}AccessorGetter"; + $setter = "${interfaceName}Internal::${attrName}AttrSetter"; + + # Replaceable + } elsif ($attrExt->{"Replaceable"}) { + # Replaceable accessor is put on instance template with ReadOnly attribute. + $getter = "${interfaceName}Internal::${attrName}AttrGetter"; + $setter = "0"; + $propAttr .= "|v8::ReadOnly"; + + # Normal + } else { + $getter = "${interfaceName}Internal::${attrName}AttrGetter"; + $setter = "${interfaceName}Internal::${attrName}AttrSetter"; + } + + # Read only attributes + if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) { + $setter = "0"; + } + + # An accessor can be installed on the proto + if ($attrExt->{"v8OnProto"}) { + $on_proto = "1 /* on proto */"; + } + + my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type . + "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; + push(@implContent, <<END); + // $commentInfo + { "$attrName", + $getter, + $setter, + $data, + $accessControl, + static_cast<v8::PropertyAttribute>($propAttr), + $on_proto }, +END + } +} + + +sub GenerateImplementation +{ + my $object = shift; + my $dataNode = shift; + my $interfaceName = $dataNode->name; + my $className = "V8$interfaceName"; + my $implClassName = $interfaceName; + my $classIndex = uc($codeGenerator->StripModule($interfaceName)); + + my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; + my $conditional = $dataNode->extendedAttributes->{"Conditional"}; + + @allParents = $codeGenerator->FindParentsRecursively($dataNode); + + # - Add default header template + @implContentHeader = split("\r", $headerTemplate); + + push(@implFixedHeader, + "#include \"config.h\"\n" . + "#include \"v8_proxy.h\"\n" . + "#include \"v8_binding.h\"\n\n" . + "#undef LOG\n\n"); + + if ($className =~ /^V8SVG/) { + push(@implFixedHeader, "#if ENABLE(SVG)\n\n"); + } elsif (IsVideoClassName($className)) { + push(@implFixedHeader, "#if ENABLE(VIDEO)\n\n"); + } elsif (IsWorkerClassName($className)) { + push(@implFixedHeader, "#if ENABLE(WORKERS)\n\n"); + } + + if ($className =~ /^V8SVGAnimated/) { + AddIncludesForSVGAnimatedType($interfaceName); + } + + $implIncludes{"${className}.h"} = 1; + + AddIncludesForType($interfaceName); + $implIncludes{"v8_proxy.h"} = 1; + + push(@implContentDecls, "namespace WebCore {\n"); + push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n"); + push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n"); + + my $hasConstructors = 0; + + # Generate property accessors for attributes. + for ($index = 0; $index < @{$dataNode->attributes}; $index++) { + $attribute = @{$dataNode->attributes}[$index]; + $attrName = $attribute->signature->name; + $attrType = $attribute->signature->type; + + # Generate special code for the constructor attributes. + if ($attrType =~ /Constructor$/) { + $hasConstructors = 1; + next; + } + + # Make EventListeners always custom. + # TODO(mbelshe): make the perl code capable of generating the + # event setters/getters. For now, WebKit has started removing the + # [Custom] attribute, so just automatically insert it to avoid forking + # other files. This should be okay because we can't generate stubs + # for any event getter/setters anyway. + if ($attrType eq "EventListener") { + $attribute->signature->extendedAttributes->{"Custom"} = 1; + $implIncludes{"v8_custom.h"} = 1; + next; + } + + # Do not generate accessor if this is a custom attribute. The + # call will be forwarded to a hand-written accessor + # implementation. + if ($attribute->signature->extendedAttributes->{"Custom"} || + $attribute->signature->extendedAttributes->{"V8Custom"}) { + $implIncludes{"v8_custom.h"} = 1; + next; + } + + # Generate the accessor. + if ($attribute->signature->extendedAttributes->{"CustomGetter"}) { + $implIncludes{"v8_custom.h"} = 1; + } else { + GenerateNormalAttrGetter($attribute, $dataNode, $classIndex, $implClassName); + } + if ($attribute->signature->extendedAttributes->{"CustomSetter"} || + $attribute->signature->extendedAttributes->{"V8CustomSetter"}) { + $implIncludes{"v8_custom.h"} = 1; + } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) { + $dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"} || die "Replaceable attribute can only be used in interface that defines ExtendsDOMGlobalObject attribute!"; +# GenerateReplaceableAttrSetter($implClassName); + } elsif ($attribute->type !~ /^readonly/ && + !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) { + GenerateNormalAttrSetter($attribute, $dataNode, $classIndex, $implClassName); + } + } + + if ($hasConstructors) { + GenerateConstructorGetter($implClassName, $classIndex); + } + + # Generate methods for functions. + foreach my $function (@{$dataNode->functions}) { + # hack for addEventListener/RemoveEventListener + # TODO(fqian): avoid naming conflict + if ($function->signature->extendedAttributes->{"Custom"} || + $function->signature->extendedAttributes->{"V8Custom"}) { + $implIncludes{"v8_custom.h"} = 1; + + } else { + GenerateFunctionCallback($function, $dataNode, $classIndex, $implClassName); + } + + + # If the function does not need domain security check, we need to + # generate an access getter that returns different function objects + # for different calling context. + if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} + || ($interfaceName eq "DOMWindow")) + && $function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}){ + GenerateDomainSafeFunctionGetter($function, $dataNode, $classIndex, $implClassName); + } + } + + # Attributes + my $attributes = $dataNode->attributes; + + # For the DOMWindow interface we partition the attributes into the + # ones that disallows shadowing and the rest. + my @disallows_shadowing; + my @normal; + if ($interfaceName eq "DOMWindow") { + foreach my $attribute (@$attributes) { + if ($attribute->signature->extendedAttributes->{"V8DisallowShadowing"}) { + push(@disallows_shadowing, $attribute); + } else { + push(@normal, $attribute); + } + } + # Put the attributes that disallow shadowing on the shadow object. + $attributes = \@normal; + push(@implContent, "static const BatchedAttribute shadow_attrs[] = {\n"); + GenerateBatchedAttributeData($interfaceName, \@disallows_shadowing); + push(@implContent, "};\n"); + + } + + my $has_attributes = 0; + if (@$attributes) { + $has_attributes = 1; + push(@implContent, "static const BatchedAttribute attrs[] = {\n"); + GenerateBatchedAttributeData($interfaceName, $attributes); + push(@implContent, "};\n"); + } + + # Setup constants + my $has_constants = 0; + if (@{$dataNode->constants}) { + $has_constants = 1; + push(@implContent, "static const BatchedConstant consts[] = {\n"); + } + foreach my $constant (@{$dataNode->constants}) { + my $name = $constant->name; + my $value = $constant->value; + # TODO we need the static_cast here only because of one constant, NodeFilter.idl + # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF". It would be better if we + # handled this here, and converted it to a -1 constant in the c++ output. + push(@implContent, <<END); + { "${name}", static_cast<signed int>($value) }, +END + } + if ($has_constants) { + push(@implContent, "};\n"); + } + + push(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n"); + + my $access_check = "/* no access check */"; + if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && + !($interfaceName eq "DOMWindow")) { + $access_check = "instance->SetAccessCheckCallbacks(V8Custom::v8${interfaceName}NamedSecurityCheck, V8Custom::v8${interfaceName}IndexedSecurityCheck, v8::Integer::New(V8ClassIndex::ToInt(V8ClassIndex::${classIndex})));"; + } + + # For the DOMWindow interface, generate the shadow object template + # configuration method. + if ($implClassName eq "DOMWindow") { + push(@implContent, <<END); +static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ) { + BatchConfigureAttributes(templ, + v8::Handle<v8::ObjectTemplate>(), + shadow_attrs, + sizeof(shadow_attrs)/sizeof(*shadow_attrs)); + return templ; +} +END + } + + # Generate the template configuration method + push(@implContent, <<END); +static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc) { + v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate(); + instance->SetInternalFieldCount(2); + v8::Local<v8::Signature> default_signature = v8::Signature::New(desc); + v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate(); + $access_check +END + + + # Set up our attributes if we have them + if ($has_attributes) { + push(@implContent, <<END); + BatchConfigureAttributes(instance, proto, attrs, sizeof(attrs)/sizeof(*attrs)); +END + } + + # Define our functions with Set() or SetAccessor() + foreach my $function (@{$dataNode->functions}) { + my $attrExt = $function->signature->extendedAttributes; + my $name = $function->signature->name; + + my $property_attributes = "v8::DontDelete"; + if ($attrExt->{"DontEnum"}) { + $property_attributes .= "|v8::DontEnum"; + } + if ($attrExt->{"V8ReadOnly"}) { + $property_attributes .= "|v8::ReadOnly"; + } + + my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; + + my $template = "proto"; + if ($attrExt->{"V8OnInstance"}) { + $template = "instance"; + } + + if ($attrExt->{"DoNotCheckDomainSecurity"} && + ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) { + # Mark the accessor as ReadOnly and set it on the proto object so + # it can be shadowed. This is really a hack to make it work. + # There are several sceneria to call into the accessor: + # 1) from the same domain: "window.open": + # the accessor finds the DOM wrapper in the proto chain; + # 2) from the same domain: "window.__proto__.open": + # the accessor will NOT find a DOM wrapper in the prototype chain + # 3) from another domain: "window.open": + # the access find the DOM wrapper in the prototype chain + # "window.__proto__.open" from another domain will fail when + # accessing '__proto__' + # + # The solution is very hacky and fragile, it really needs to be replaced + # by a better solution. + $property_attributes .= "|v8::ReadOnly"; + push(@implContent, <<END); + + // $commentInfo + $template->SetAccessor( + v8::String::New("$name"), + ${interfaceName}Internal::${name}AttrGetter, + 0, + v8::Handle<v8::Value>(), + v8::ALL_CAN_READ, + static_cast<v8::PropertyAttribute>($property_attributes)); +END + next; + } + + my $signature = "default_signature"; + if ($attrExt->{"V8DoNotCheckSignature"}){ + $signature = "v8::Local<v8::Signature>()"; + } + + if (RequiresCustomSignature($function)) { + $signature = "${name}_signature"; + push(@implContent, "\n // Custom Signature '$name'\n", CreateCustomSignature($function)); + } + + # Normal function call is a template + my $templateFunction = GenerateNewFunctionTemplate($function, $dataNode, $signature); + + + push(@implContent, <<END); + + // $commentInfo + ${template}->Set( + v8::String::New("$name"), + $templateFunction, + static_cast<v8::PropertyAttribute>($property_attributes)); +END + } + + # set the super descriptor + foreach (@{$dataNode->parents}) { + my $parent = $codeGenerator->StripModule($_); + if ($parent eq "EventTarget") { next; } + $implIncludes{"V8${parent}.h"} = 1; + my $parentClassIndex = uc($codeGenerator->StripModule($parent)); + push(@implContent, " desc->Inherit(V8Proxy::GetTemplate(V8ClassIndex::${parentClassIndex}));\n"); + last; + } + + # Set the class name. This is used when printing objects. + push(@implContent, " desc->SetClassName(v8::String::New(\"" . GetClassName(${interfaceName}) . "\"));\n"); + + if ($has_constants) { + push(@implContent, <<END); + BatchConfigureConstants(desc, proto, consts, sizeof(consts)/sizeof(*consts)); +END + } + + push(@implContent, <<END); + return desc; +} + +v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate() { + static v8::Persistent<v8::FunctionTemplate> ${className}_raw_cache_; + if (${className}_raw_cache_.IsEmpty()) { + v8::HandleScope scope; + v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8Proxy::CheckNewLegal); + ${className}_raw_cache_ = v8::Persistent<v8::FunctionTemplate>::New(result); + } + return ${className}_raw_cache_; +} + +v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate() { + static v8::Persistent<v8::FunctionTemplate> ${className}_cache_; + if (${className}_cache_.IsEmpty()) + ${className}_cache_ = Configure${className}Template(GetRawTemplate()); + return ${className}_cache_; +} + +bool ${className}::HasInstance(v8::Handle<v8::Value> value) { + return GetRawTemplate()->HasInstance(value); +} + +END + + if ($implClassName eq "DOMWindow") { + push(@implContent, <<END); +v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate() { + static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObject_cache_; + if (V8DOMWindowShadowObject_cache_.IsEmpty()) { + V8DOMWindowShadowObject_cache_ = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New()); + ConfigureShadowObjectTemplate(V8DOMWindowShadowObject_cache_); + } + return V8DOMWindowShadowObject_cache_; +} +END + } + + push(@implContent, <<END); +} // namespace WebCore +END + + if ($className =~ /^V8SVG/) { + push(@implContent, "\n#endif // ENABLE(SVG)\n"); + } elsif (IsVideoClassName($className)) { + push(@implContent, "\n#endif // ENABLE(VIDEO)\n"); + } elsif (IsWorkerClassName($className)) { + push(@implContent, "\n#endif // ENABLE(WORKERS)\n"); + } +} + + +sub GenerateFunctionCallString() +{ + my $function = shift; + my $numberOfParameters = shift; + my $indent = shift; + my $implClassName = shift; + + my $name = $function->signature->name; + my $isPodType = $codeGenerator->IsPodType($implClassName); + my $returnType = $codeGenerator->StripModule($function->signature->type); + my $returnsPodType = $codeGenerator->IsPodType($returnType); + my $nativeReturnType = GetNativeType($returnType, 0); + my $result = ""; + + # Special case: SVG matrix transform methods should not mutate + # the matrix but return a copy + my $copyFirst = 0; + if ($implClassName eq "SVGMatrix" && $function->signature->type eq "SVGMatrix") { + $copyFirst = 1; + } + + if ($function->signature->extendedAttributes->{"v8implname"}) { + $name = $function->signature->extendedAttributes->{"v8implname"}; + } + + if ($function->signature->extendedAttributes->{"ImplementationFunction"}) { + $name = $function->signature->extendedAttributes->{"ImplementationFunction"}; + } + + my $functionString = "imp->${name}("; + + if ($copyFirst) { + $functionString = "result.${name}("; + } + + my $returnsListItemPodType = 0; + # SVG lists functions that return POD types require special handling + if (IsSVGListTypeNeedingSpecialHandling($implClassName) && IsSVGListMethod($name) && $returnsPodType) { + $returnsListItemPodType = 1; + $result .= $indent . "SVGList<RefPtr<SVGPODListItem<$nativeReturnType> > >* listImp = imp;\n"; + $functionString = "listImp->${name}("; + } + + my $first = 1; + my $index = 0; + my $nodeToReturn = 0; + + foreach my $parameter (@{$function->parameters}) { + if ($index eq $numberOfParameters) { + last; + } + if ($first) { $first = 0; } + else { $functionString .= ", "; } + my $paramName = $parameter->name; + my $paramType = $parameter->type; + + # This is a bit of a hack... we need to convert parameters to methods on SVG lists + # of POD types which are items in the list to appropriate SVGList<> instances + if ($returnsListItemPodType && $paramType . "List" eq $implClassName) { + $paramName = "SVGPODListItem<" . GetNativeType($paramType, 1) . ">::copy($paramName)"; + } + + if ($parameter->type eq "NodeFilter") { + $functionString .= "$paramName.get()"; + } else { + $functionString .= $paramName; + } + + if ($parameter->extendedAttributes->{"Return"}) { + $nodeToReturn = $parameter->name; + } + $index++; + } + + if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { + $functionString .= ", " if not $first; + $functionString .= "&callStack"; + if ($first) { $first = 0; } + } + + if (@{$function->raisesExceptions}) { + $functionString .= ", " if not $first; + $functionString .= "ec"; + } + $functionString .= ")"; + + if ((IsRefPtrType($returnType) || $returnsListItemPodType) && + !$nodeToReturn) { + # We don't use getPtr when $nodeToReturn because that situation is + # special-cased below to return a bool. + $implIncludes{"wtf/GetPtr.h"} = 1; + $functionString = "WTF::getPtr(" . $functionString . ")"; + } + + if ($nodeToReturn) { + # Special case for insertBefore, replaceChild, removeChild and + # appendChild functions from Node. + $result .= $indent . "bool success = $functionString;\n"; + if (@{$function->raisesExceptions}) { + $result .= GenerateSetDOMException($indent); + } + $result .= $indent . "if (success)\n"; + $result .= $indent . " " . + "return V8Proxy::NodeToV8Object($nodeToReturn);\n"; + $result .= $indent . "return v8::Null();\n"; + return $result; + } elsif ($returnType eq "void") { + $result .= $indent . "$functionString;\n"; + } elsif ($copyFirst) { + $result .= + $indent . GetNativeType($returnType, 0) . " result = *imp;\n" . + $indent . "$functionString;\n"; + } elsif ($returnsListItemPodType) { + $result .= $indent . "RefPtr<SVGPODListItem<$nativeReturnType> > result = $functionString;\n"; + } else { + $result .= $indent . $nativeReturnType . " result = $functionString;\n"; + } + + if (@{$function->raisesExceptions}) { + $result .= GenerateSetDOMException($indent); + } + + my $return = "result"; + if (IsRefPtrType($returnType) || $returnsListItemPodType) { + $implIncludes{"wtf/GetPtr.h"} = 1; + $return = "WTF::getPtr(" . $return . ")"; + } + + # If the return type is a POD type, separate out the wrapper generation + if ($returnsListItemPodType) { + $result .= $indent . "V8SVGPODTypeWrapper<" . $nativeReturnType . ">* wrapper = new "; + $result .= "V8SVGPODTypeWrapperCreatorForList<" . $nativeReturnType . ">($return, imp->associatedAttributeName());\n"; + $return = "wrapper"; + } elsif ($returnsPodType) { + $result .= $indent . "V8SVGPODTypeWrapper<" . $nativeReturnType . ">* wrapper = "; + $result .= GenerateSVGStaticPodTypeWrapper($returnType, $return) . ";\n"; + $return = "wrapper"; + } + + my $generatedSVGContextRetrieval = 0; + # If the return type needs an SVG context, output it + if (IsSVGTypeNeedingContextParameter($returnType)) { + $result .= GenerateSVGContextAssignment($implClassName, $return, $indent); + $generatedSVGContextRetrieval = 1; + } + + if (IsSVGTypeNeedingContextParameter($implClassName) && $implClassName =~ /List$/ && IsSVGListMutator($name)) { + if (!$generatedSVGContextRetrieval) { + $result .= GenerateSVGContextRetrieval($implClassName, $indent); + $generatedSVGContextRetrieval = 1; + } + + $result .= $indent . "context->svgAttributeChanged(imp->associatedAttributeName());\n"; + $implIncludes{"SVGElement.h"} = 1; + } + + # If the implementing class is a POD type, commit changes + if ($isPodType) { + if (!$generatedSVGContextRetrieval) { + $result .= GenerateSVGContextRetrieval($implClassName, $indent); + $generatedSVGContextRetrieval = 1; + } + + $result .= $indent . "imp_wrapper->commitChange(imp_instance, context);\n"; + } + + if ($returnsPodType) { + my $classIndex = uc($returnType); + $result .= $indent . "return V8Proxy::ToV8Object(V8ClassIndex::$classIndex, wrapper);\n"; + } else { + $result .= $indent . "return " . NativeToJSValue($function->signature, $return) . ";\n"; + } + + return $result; +} + + +# Get the class name used for printing javascript DOM-object wrappers. +sub GetClassName +{ + my $type = shift; + return "HTMLCollection" if $type eq "UndetectableHTMLCollection"; + return $type; +} + + +sub GetNativeTypeFromSignature +{ + my $signature = shift; + my $isParameter = shift; + + my $type = $codeGenerator->StripModule($signature->type); + + return GetNativeType($type, $isParameter); +} + +sub IsRefPtrType +{ + my $type = shift; + return 1 if $type eq "Attr"; + return 1 if $type eq "CanvasGradient"; + return 1 if $type eq "ClientRect"; + return 1 if $type eq "ClientRectList"; + return 1 if $type eq "CDATASection"; + return 1 if $type eq "Comment"; + return 1 if $type eq "CSSRule"; + return 1 if $type eq "CSSStyleRule"; + return 1 if $type eq "CSSCharsetRule"; + return 1 if $type eq "CSSImportRule"; + return 1 if $type eq "CSSMediaRule"; + return 1 if $type eq "CSSFontFaceRule"; + return 1 if $type eq "CSSPageRule"; + return 1 if $type eq "CSSPrimitiveValue"; + return 1 if $type eq "CSSStyleSheet"; + return 1 if $type eq "CSSStyleDeclaration"; + return 1 if $type eq "CSSValue"; + return 1 if $type eq "CSSRuleList"; + return 1 if $type eq "Document"; + return 1 if $type eq "DocumentFragment"; + return 1 if $type eq "DocumentType"; + return 1 if $type eq "Element"; + return 1 if $type eq "EntityReference"; + return 1 if $type eq "Event"; + return 1 if $type eq "HTMLCollection"; + return 1 if $type eq "HTMLDocument"; + return 1 if $type eq "HTMLElement"; + return 1 if $type eq "HTMLOptionsCollection"; + return 1 if $type eq "ImageData"; + return 1 if $type eq "MediaError"; + return 1 if $type eq "MimeType"; + return 1 if $type eq "Node"; + return 1 if $type eq "NodeList"; + return 1 if $type eq "NodeFilter"; + return 1 if $type eq "NodeIterator"; + return 1 if $type eq "NSResolver"; + return 1 if $type eq "Plugin"; + return 1 if $type eq "ProcessingInstruction"; + return 1 if $type eq "Range"; + return 1 if $type eq "Text"; + return 1 if $type eq "TextMetrics"; + return 1 if $type eq "TimeRanges"; + return 1 if $type eq "TreeWalker"; + return 1 if $type eq "WebKitCSSMatrix"; + return 1 if $type eq "WebKitPoint"; + return 1 if $type eq "XPathExpression"; + return 1 if $type eq "XPathNSResolver"; + return 1 if $type eq "XPathResult"; + + return 1 if $type eq "SVGAngle"; + return 1 if $type eq "SVGElementInstance"; + return 1 if $type eq "SVGElementInstanceList"; + return 1 if $type =~ /^SVGPathSeg/; + + return 1 if $type =~ /^SVGAnimated/; + + return 0; +} + +sub IsVideoClassName +{ + my $class = shift; + return 1 if $class eq "V8HTMLAudioElement"; + return 1 if $class eq "V8HTMLMediaElement"; + return 1 if $class eq "V8HTMLSourceElement"; + return 1 if $class eq "V8HTMLVideoElement"; + return 1 if $class eq "V8MediaError"; + return 1 if $class eq "V8TimeRanges"; + + return 0; +} + +sub IsWorkerClassName +{ + my $class = shift; + return 1 if $class eq "V8Worker"; + return 1 if $class eq "V8WorkerContext"; + return 1 if $class eq "V8WorkerLocation"; + return 1 if $class eq "V8WorkerNavigator"; + + return 0; +} + +sub GetNativeType +{ + my $type = shift; + my $isParameter = shift; + + if ($type eq "float" or $type eq "AtomicString" or $type eq "double") { + return $type + } + + return "int" if $type eq "short" or $type eq "unsigned short"; + return "int" if $type eq "long" or $type eq "unsigned long"; + return "unsigned long long" if $type eq "unsigned long long"; + return "bool" if $type eq "boolean"; + return "String" if $type eq "DOMString"; + return "Range::CompareHow" if $type eq "CompareHow"; + return "FloatRect" if $type eq "SVGRect"; + return "FloatPoint" if $type eq "SVGPoint"; + return "TransformationMatrix" if $type eq "SVGMatrix"; + return "SVGTransform" if $type eq "SVGTransform"; + return "SVGLength" if $type eq "SVGLength"; + return "double" if $type eq "SVGNumber"; + return "SVGPaint::SVGPaintType" if $type eq "SVGPaintType"; + return "DOMTimeStamp" if $type eq "DOMTimeStamp"; + return "unsigned" if $type eq "RGBColor"; + return "Node*" if $type eq "EventTarget" and $isParameter; + + return "String" if $type eq "DOMUserData"; # temporary hack, TODO + + # temporary hack + return "RefPtr<NodeFilter>" if $type eq "NodeFilter"; + + return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter; + + # Default, assume native type is a pointer with same type name as idl type + return "${type}*"; +} + + +my %typeCanFailConversion = ( + "AtomicString" => 0, + "Attr" => 1, + "CompareHow" => 0, + "DOMString" => 0, + "DOMWindow" => 0, + "DocumentType" => 0, + "Element" => 0, + "Event" => 0, + "EventListener" => 0, + "EventTarget" => 0, + "HTMLElement" => 0, + "HTMLOptionElement" => 0, + "Node" => 0, + "NodeFilter" => 0, + "MessagePort" => 0, + "NSResolver" => 0, + "Range" => 0, + "SQLResultSet" => 0, + "SVGAngle" => 0, + "SVGElement" => 0, + "SVGLength" => 0, + "SVGMatrix" => 0, + "SVGNumber" => 0, + "SVGPaintType" => 0, + "SVGPathSeg" => 0, + "SVGPoint" => 0, + "SVGRect" => 0, + "SVGTransform" => 0, + "VoidCallback" => 1, + "WebKitCSSMatrix" => 0, + "WebKitPoint" => 0, + "XPathEvaluator" => 0, + "XPathNSResolver" => 0, + "XPathResult" => 0, + "boolean" => 0, + "double" => 0, + "float" => 0, + "long" => 0, + "unsigned long" => 0, + "unsigned short" => 0, +); + + +sub TranslateParameter +{ + my $signature = shift; + + # The IDL uses some pseudo-types which don't really exist. + if ($signature->type eq "TimeoutHandler") { + $signature->type("DOMString"); + } +} + +sub BasicTypeCanFailConversion +{ + # As can been seen from the above, no basic types can fail conversion. + return 0; +} + +sub TypeCanFailConversion +{ + my $signature = shift; + + my $type = $codeGenerator->StripModule($signature->type); + + $implIncludes{"ExceptionCode.h"} = 1 if $type eq "Attr"; + + return $typeCanFailConversion{$type} if exists $typeCanFailConversion{$type}; + + die "Don't know whether a JS value can fail conversion to type $type."; +} + +sub JSValueToNative +{ + my $signature = shift; + my $value = shift; + my $okParam = shift; + my $maybeOkParam = $okParam ? ", ${okParam}" : ""; + + my $type = $codeGenerator->StripModule($signature->type); + + return "$value" if $type eq "JSObject"; + return "$value->BooleanValue()" if $type eq "boolean"; + return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double"; + return "$value->NumberValue()" if $type eq "SVGNumber"; + + return "ToInt32($value${maybeOkParam})" if $type eq "unsigned long" or $type eq "unsigned short" or $type eq "long"; + return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow"; + return "static_cast<SVGPaint::SVGPaintType>($value->ToInt32()->Int32Value())" if $type eq "SVGPaintType"; + + return "ToWebCoreString($value)" if $type eq "AtomicString" or $type eq "DOMUserData"; + if ($type eq "DOMString") { + return "valueToStringWithNullCheck($value)" if $signature->extendedAttributes->{"ConvertNullToNullString"}; + return "valueToStringWithNullOrUndefinedCheck($value)" if $signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"}; + return "ToWebCoreString($value)"; + } + + if ($type eq "NodeFilter") { + return "V8Proxy::ToNativeNodeFilter($value)"; + } + + if ($type eq "SVGRect") { + $implIncludes{"FloatRect.h"} = 1; + } + + if ($type eq "SVGPoint") { + $implIncludes{"FloatPoint.h"} = 1; + } + + # Default, assume autogenerated type conversion routines + $implIncludes{"v8_proxy.h"} = 1; + if ($type eq "EventTarget") { + $implIncludes{"V8Node.h"} = 1; + + # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget. + return "V8Node::HasInstance($value) ? V8Proxy::DOMWrapperToNode<Node>($value) : 0"; + } + + AddIncludesForType($type); + # $implIncludes{"$type.h"} = 1 unless AvoidInclusionOfType($type); + + if (IsDOMNodeType($type)) { + $implIncludes{"V8${type}.h"} = 1; + + # Perform type checks on the parameter, if it is expected Node type, + # return NULL. + return "V8${type}::HasInstance($value) ? V8Proxy::DOMWrapperToNode<${type}>($value) : 0"; + + } else { + # TODO: Temporary to avoid Window name conflict. + my $classIndex = uc($type); + my $implClassName = ${type}; + + $implIncludes{"V8$type.h"} = 1; + + if ($codeGenerator->IsPodType($type)) { + my $nativeType = GetNativeType($type); + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + + # TODO(jhass): perform type checking like others??? + return "*V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<${nativeType}> >(V8ClassIndex::${classIndex}, $value)" + } + + $implIncludes{"V8${type}.h"} = 1; + + # Perform type checks on the parameter, if it is expected Node type, + # return NULL. + return "V8${type}::HasInstance($value) ? V8Proxy::ToNativeObject<${implClassName}>(V8ClassIndex::${classIndex}, $value) : 0"; + } +} + + +sub GetV8HeaderName +{ + my $type = shift; + return "V8" . GetImplementationFileName($type); +} + + +sub CreateCustomSignature +{ + my $function = shift; + my $count = @{$function->parameters}; + my $name = $function->signature->name; + my $result = " const int ${name}_argc = ${count};\n" . + " v8::Handle<v8::FunctionTemplate> ${name}_argv[${name}_argc] = { "; + my $first = 1; + foreach my $parameter (@{$function->parameters}) { + if ($first) { $first = 0; } + else { $result .= ", "; } + if (IsWrapperType($parameter->type)) { + my $type = $parameter->type; + my $header = GetV8HeaderName($type); + $implIncludes{$header} = 1; + $result .= "V8${type}::GetRawTemplate()"; + } else { + $result .= "v8::Handle<v8::FunctionTemplate>()"; + } + } + $result .= " };\n"; + $result .= " v8::Handle<v8::Signature> ${name}_signature = v8::Signature::New(desc, ${name}_argc, ${name}_argv);\n"; + return $result; +} + + +sub RequiresCustomSignature +{ + my $function = shift; + # No signature needed for Custom function + if ($function->signature->extendedAttributes->{"Custom"} || + $function->signature->extendedAttributes->{"V8Custom"}) { + return 0; + } + + foreach my $parameter (@{$function->parameters}) { + if (IsWrapperType($parameter->type)) { + return 1; + } + } + return 0; +} + + +my %non_wrapper_types = ( + 'float' => 1, + 'AtomicString' => 1, + 'double' => 1, + 'short' => 1, + 'unsigned short' => 1, + 'long' => 1, + 'unsigned long' => 1, + 'boolean' => 1, + 'DOMString' => 1, + 'CompareHow' => 1, + 'SVGRect' => 1, + 'SVGPoint' => 1, + 'SVGMatrix' => 1, + 'SVGTransform' => 1, + 'SVGLength' => 1, + 'SVGNumber' => 1, + 'SVGPaintType' => 1, + 'DOMTimeStamp' => 1, + 'JSObject' => 1, + 'EventTarget' => 1, + 'NodeFilter' => 1, + 'EventListener' => 1 +); + + +sub IsWrapperType +{ + my $type = $codeGenerator->StripModule(shift); + return !($non_wrapper_types{$type}); +} + +sub IsDOMNodeType +{ + my $type = shift; + + return 1 if $type eq 'Attr'; + return 1 if $type eq 'CDATASection'; + return 1 if $type eq 'Comment'; + return 1 if $type eq 'Document'; + return 1 if $type eq 'DocumentFragment'; + return 1 if $type eq 'DocumentType'; + return 1 if $type eq 'Element'; + return 1 if $type eq 'EntityReference'; + return 1 if $type eq 'HTMLCanvasElement'; + return 1 if $type eq 'HTMLDocument'; + return 1 if $type eq 'HTMLElement'; + return 1 if $type eq 'HTMLFormElement'; + return 1 if $type eq 'HTMLTableCaptionElement'; + return 1 if $type eq 'HTMLTableSectionElement'; + return 1 if $type eq 'Node'; + return 1 if $type eq 'ProcessingInstruction'; + return 1 if $type eq 'SVGElement'; + return 1 if $type eq 'SVGDocument'; + return 1 if $type eq 'SVGSVGElement'; + return 1 if $type eq 'SVGUseElement'; + return 1 if $type eq 'Text'; + + return 0; +} + + +sub NativeToJSValue +{ + my $signature = shift; + my $value = shift; + my $type = $codeGenerator->StripModule($signature->type); + my $className= "V8$type"; + + return "v8::Date::New(static_cast<double>($value))" if $type eq "DOMTimeStamp"; + return "$value ? v8::True() : v8::False()" if $type eq "boolean"; + return "v8::Undefined()" if $type eq "void"; + + # For all the types where we use 'int' as the representation type, + # we use Integer::New which has a fast Smi conversion check. + return "v8::Integer::New($value)" if GetNativeType($type) eq "int"; + + return "v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type) or $type eq "SVGPaintType"; + + if ($codeGenerator->IsStringType($type)) { + my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"}; + if (defined $conv) { + return "v8StringOrNull($value)" if $conv eq "Null"; + return "v8StringOrUndefined($value)" if $conv eq "Undefined"; + return "v8StringOrFalse($value)" if $conv eq "False"; + + die "Unknown value for ConvertNullStringTo extended attribute"; + } + return "v8String($value)"; + } + + # V8 specific. + my $implClassName = $type; + AddIncludesForType($type); + # $implIncludes{GetImplementationFileName($type)} = 1 unless AvoidInclusionOfType($type); + + # special case for non-DOM node interfaces + if (IsDOMNodeType($type)) { + return "V8Proxy::NodeToV8Object($value)"; + } + + if ($type eq "EventTarget" or $type eq "SVGElementInstance") { + return "V8Proxy::EventTargetToV8Object($value)"; + } + + if ($type eq "Event") { + return "V8Proxy::EventToV8Object($value)"; + } + + if ($type eq "EventListener") { + return "V8Proxy::EventListenerToV8Object($value)"; + } + + if ($type eq "RGBColor") { + return "V8Proxy::ToV8Object(V8ClassIndex::RGBCOLOR, new RGBColor($value))"; + } + + if ($type eq "WorkerLocation" or $type eq "WorkerNavigator") { + $implIncludes{"WorkerContextExecutionProxy.h"} = 1; + my $classIndex = uc($type); + + return "WorkerContextExecutionProxy::ToV8Object(V8ClassIndex::$classIndex, $value)"; + } + + else { + $implIncludes{"wtf/RefCounted.h"} = 1; + $implIncludes{"wtf/RefPtr.h"} = 1; + my $classIndex = uc($type); + + if ($codeGenerator->IsPodType($type)) { + $value = GenerateSVGStaticPodTypeWrapper($type, $value); + } + + return "V8Proxy::ToV8Object(V8ClassIndex::$classIndex, $value)"; + } +} + +sub GenerateSVGStaticPodTypeWrapper { + my $type = shift; + my $value = shift; + + $implIncludes{"V8$type.h"}=1; + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + + my $nativeType = GetNativeType($type); + return "new V8SVGStaticPODTypeWrapper<$nativeType>($value)"; +} + +# Internal helper +sub WriteData +{ + if (defined($IMPL)) { + # Write content to file. + print $IMPL @implContentHeader; + + print $IMPL @implFixedHeader; + + foreach my $implInclude (sort keys(%implIncludes)) { + my $checkType = $implInclude; + $checkType =~ s/\.h//; + + print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType); + } + + print $IMPL "\n"; + print $IMPL @implContentDecls; + print $IMPL @implContent; + close($IMPL); + undef($IMPL); + + %implIncludes = (); + @implFixedHeader = (); + @implHeaderContent = (); + @implContentDecls = (); + @implContent = (); + } + + if (defined($HEADER)) { + # Write content to file. + print $HEADER @headerContent; + close($HEADER); + undef($HEADER); + + @headerContent = (); + } +} + +sub IsSVGTypeNeedingContextParameter +{ + my $implClassName = shift; + + if ($implClassName =~ /SVG/ and not $implClassName =~ /Element/) { + return 1 unless $implClassName =~ /SVGPaint/ or $implClassName =~ /SVGColor/ or $implClassName =~ /SVGDocument/; + } + + return 0; +} + +sub GenerateSVGContextAssignment +{ + my $srcType = shift; + my $value = shift; + my $indent = shift; + + $result = GenerateSVGContextRetrieval($srcType, $indent); + $result .= $indent . "V8Proxy::SetSVGContext($value, context);\n"; + + return $result; +} + +sub GenerateSVGContextRetrieval +{ + my $srcType = shift; + my $indent = shift; + + my $srcIsPodType = $codeGenerator->IsPodType($srcType); + + my $srcObject = "imp"; + if ($srcIsPodType) { + $srcObject = "imp_wrapper"; + } + + my $contextDecl; + + if (IsSVGTypeNeedingContextParameter($srcType)) { + $contextDecl = "V8Proxy::GetSVGContext($srcObject)"; + } else { + $contextDecl = $srcObject; + } + + return $indent . "SVGElement* context = $contextDecl;\n"; +} + +sub IsSVGListMutator +{ + my $functionName = shift; + + return 1 if $functionName eq "clear"; + return 1 if $functionName eq "initialize"; + return 1 if $functionName eq "insertItemBefore"; + return 1 if $functionName eq "replaceItem"; + return 1 if $functionName eq "removeItem"; + return 1 if $functionName eq "appendItem"; + + return 0; +} + +sub IsSVGListMethod +{ + my $functionName = shift; + + return 1 if $functionName eq "getFirst"; + return 1 if $functionName eq "getLast"; + return 1 if $functionName eq "getItem"; + + return IsSVGListMutator($functionName); +} + +sub IsSVGListTypeNeedingSpecialHandling +{ + my $className = shift; + + return 1 if $className eq "SVGPointList"; + return 1 if $className eq "SVGTransformList"; + + return 0; +} + +sub DebugPrint +{ + my $output = shift; + + print $output; + print "\n"; +} diff --git a/V8Binding/scripts/IDLParser.pm b/V8Binding/scripts/IDLParser.pm new file mode 100644 index 0000000..eb0eab5 --- /dev/null +++ b/V8Binding/scripts/IDLParser.pm @@ -0,0 +1,441 @@ +# +# KDOM IDL parser +# +# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org> +# +# This file is part of the KDE project +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# aint with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +package IDLParser; + +use IDLStructure; + +use constant MODE_UNDEF => 0; # Default mode. + +use constant MODE_MODULE => 10; # 'module' section +use constant MODE_INTERFACE => 11; # 'interface' section +use constant MODE_EXCEPTION => 12; # 'exception' section +use constant MODE_ALIAS => 13; # 'alias' section + +# Helper variables +my @temporaryContent = ""; + +my $parseMode = MODE_UNDEF; +my $preservedParseMode = MODE_UNDEF; + +my $beQuiet; # Should not display anything on STDOUT? +my $document = 0; # Will hold the resulting 'idlDocument' + +my $directive = ""; + +# Default Constructor +sub new +{ + my $object = shift; + my $reference = { }; + + $document = 0; + $beQuiet = shift; + + bless($reference, $object); + return $reference; +} + + +sub ParseInheritance +{ + my $object = shift; + my $fileName = shift; + my $defines = shift; + my $preprocessor = shift; + + $directive = "inheritance"; + return $object->ParseImpl($fileName, $defines, $preprocessor); +} + +# Returns the parsed 'idlDocument' +sub Parse +{ + my $object = shift; + my $fileName = shift; + my $defines = shift; + my $preprocessor = shift; + + $directive = ""; + return $object->ParseImpl($fileName, $defines, $preprocessor); +} + +sub ParseImpl +{ + my $object = shift; + my $fileName = shift; + my $defines = shift; + my $preprocessor = shift; + + if (!$preprocessor) { + $preprocessor = "/usr/bin/gcc -E -P -x c++"; + } + + if (!$defines) { + $defines = ""; + } + + print " | *** Starting to parse $fileName...\n |\n" unless $beQuiet; + + open FILE, $preprocessor . " " . join(" ", (map { "-D$_" } split(/ /, $defines))) . " ". $fileName . "|" or die "Could not open $fileName"; + my @documentContent = <FILE>; + close FILE; + + my $dataAvailable = 0; + + # Simple IDL Parser (tm) + foreach (@documentContent) { + my $newParseMode = $object->DetermineParseMode($_); + + if ($newParseMode ne MODE_UNDEF) { + if ($dataAvailable eq 0) { + $dataAvailable = 1; # Start node building... + } else { + $object->ProcessSection(); + } + } + + # Update detected data stream mode... + if ($newParseMode ne MODE_UNDEF) { + $parseMode = $newParseMode; + } + + push(@temporaryContent, $_); + } + + # Check if there is anything remaining to parse... + if (($parseMode ne MODE_UNDEF) and ($#temporaryContent > 0)) { + $object->ProcessSection(); + } + + print " | *** Finished parsing!\n" unless $beQuiet; + + $document->fileName($fileName); + + return $document; +} + +sub ParseModule +{ + my $object = shift; + my $dataNode = shift; + + print " |- Trying to parse module...\n" unless $beQuiet; + + my $data = join("", @temporaryContent); + $data =~ /$IDLStructure::moduleSelector/; + + my $moduleName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)")); + $dataNode->module($moduleName); + + print " |----> Module; NAME \"$moduleName\"\n |-\n |\n" unless $beQuiet; +} + +sub dumpExtendedAttributes +{ + my $padStr = shift; + my $attrs = shift; + + if (!%{$attrs}) { + return ""; + } + + my @temp; + while (($name, $value) = each(%{$attrs})) { + push(@temp, "$name=$value"); + } + + return $padStr . "[" . join(", ", @temp) . "]"; +} + +sub parseExtendedAttributes +{ + my $str = shift; + $str =~ s/\[\s*(.*)\]/$1/g; + + my %attrs = (); + + foreach my $value (split(/\s*,\s*/, $str)) { + ($name,$value) = split(/\s*=\s*/, $value, 2); + + # Attributes with no value are set to be true + $value = 1 unless defined $value; + $attrs{$name} = $value; + } + + return \%attrs; +} + +sub ParseInterface +{ + my $object = shift; + my $dataNode = shift; + my $sectionName = shift; + + my $data = join("", @temporaryContent); + + # Look for end-of-interface mark + $data =~ /};/g; + $data = substr($data, index($data, $sectionName), pos($data) - length($data)); + + $data =~ s/[\n\r]/ /g; + + # Beginning of the regexp parsing magic + if ($sectionName eq "exception") { + print " |- Trying to parse exception...\n" unless $beQuiet; + + my $exceptionName = ""; + my $exceptionData = ""; + my $exceptionDataName = ""; + my $exceptionDataType = ""; + + # Match identifier of the exception, and enclosed data... + $data =~ /$IDLStructure::exceptionSelector/; + $exceptionName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)")); + $exceptionData = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)")); + + ('' =~ /^/); # Reset variables needed for regexp matching + + # ... parse enclosed data (get. name & type) + $exceptionData =~ /$IDLStructure::exceptionSubSelector/; + $exceptionDataType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)")); + $exceptionDataName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)")); + + # Fill in domClass datastructure + $dataNode->name($exceptionName); + + my $newDataNode = new domAttribute(); + $newDataNode->type("readonly attribute"); + $newDataNode->signature(new domSignature()); + + $newDataNode->signature->name($exceptionDataName); + $newDataNode->signature->type($exceptionDataType); + + my $arrayRef = $dataNode->attributes; + push(@$arrayRef, $newDataNode); + + print " |----> Exception; NAME \"$exceptionName\" DATA TYPE \"$exceptionDataType\" DATA NAME \"$exceptionDataName\"\n |-\n |\n" unless $beQuiet; + } elsif ($sectionName eq "interface") { + print " |- Trying to parse interface...\n" unless $beQuiet; + + my $interfaceName = ""; + my $interfaceData = ""; + + # Match identifier of the interface, and enclosed data... + $data =~ /$IDLStructure::interfaceSelector/; + + $interfaceExtendedAttributes = (defined($1) ? $1 : " "); chop($interfaceExtendedAttributes); + $interfaceName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)")); + $interfaceBase = (defined($3) ? $3 : ""); + $interfaceData = (defined($4) ? $4 : die("Parsing error!\nSource:\n$data\n)")); + + # Fill in known parts of the domClass datastructure now... + $dataNode->name($interfaceName); + $dataNode->extendedAttributes(parseExtendedAttributes($interfaceExtendedAttributes)); + + # Inheritance detection + my @interfaceParents = split(/,/, $interfaceBase); + foreach(@interfaceParents) { + my $line = $_; + $line =~ s/\s*//g; + + my $arrayRef = $dataNode->parents; + push(@$arrayRef, $line); + } + + return if ($directive eq "inheritance"); + + $interfaceData =~ s/[\n\r]/ /g; + my @interfaceMethods = split(/;/, $interfaceData); + + foreach my $line (@interfaceMethods) { + if ($line =~ /[ \t]attribute[ \t]/) { + $line =~ /$IDLStructure::interfaceAttributeSelector/; + + my $attributeType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)")); + my $attributeExtendedAttributes = (defined($2) ? $2 : " "); chop($attributeExtendedAttributes); + + my $attributeDataType = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)")); + my $attributeDataName = (defined($4) ? $4 : die("Parsing error!\nSource:\n$line\n)")); + + ('' =~ /^/); # Reset variables needed for regexp matching + + $line =~ /$IDLStructure::getterRaisesSelector/; + my $getterException = (defined($1) ? $1 : ""); + + $line =~ /$IDLStructure::setterRaisesSelector/; + my $setterException = (defined($1) ? $1 : ""); + + my $newDataNode = new domAttribute(); + $newDataNode->type($attributeType); + $newDataNode->signature(new domSignature()); + + $newDataNode->signature->name($attributeDataName); + $newDataNode->signature->type($attributeDataType); + $newDataNode->signature->extendedAttributes(parseExtendedAttributes($attributeExtendedAttributes)); + + my $arrayRef = $dataNode->attributes; + push(@$arrayRef, $newDataNode); + + print " | |> Attribute; TYPE \"$attributeType\" DATA NAME \"$attributeDataName\" DATA TYPE \"$attributeDataType\" GET EXCEPTION? \"$getterException\" SET EXCEPTION? \"$setterException\"" . + dumpExtendedAttributes("\n | ", $newDataNode->signature->extendedAttributes) . "\n" unless $beQuiet; + + $getterException =~ s/\s+//g; + $setterException =~ s/\s+//g; + @{$newDataNode->getterExceptions} = split(/,/, $getterException); + @{$newDataNode->setterExceptions} = split(/,/, $setterException); + } elsif (($line !~ s/^\s*$//g) and ($line !~ /^\s*const/)) { + $line =~ /$IDLStructure::interfaceMethodSelector/ or die "Parsing error!\nSource:\n$line\n)"; + + my $methodExtendedAttributes = (defined($1) ? $1 : " "); chop($methodExtendedAttributes); + my $methodType = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)")); + my $methodName = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)")); + my $methodSignature = (defined($4) ? $4 : die("Parsing error!\nSource:\n$line\n)")); + + ('' =~ /^/); # Reset variables needed for regexp matching + + $line =~ /$IDLStructure::raisesSelector/; + my $methodException = (defined($1) ? $1 : ""); + + my $newDataNode = new domFunction(); + + $newDataNode->signature(new domSignature()); + $newDataNode->signature->name($methodName); + $newDataNode->signature->type($methodType); + $newDataNode->signature->extendedAttributes(parseExtendedAttributes($methodExtendedAttributes)); + + print " | |- Method; TYPE \"$methodType\" NAME \"$methodName\" EXCEPTION? \"$methodException\"" . + dumpExtendedAttributes("\n | ", $newDataNode->signature->extendedAttributes) . "\n" unless $beQuiet; + + $methodException =~ s/\s+//g; + @{$newDataNode->raisesExceptions} = split(/,/, $methodException); + + my @params = split(/,/, $methodSignature); + foreach(@params) { + my $line = $_; + + $line =~ /$IDLStructure::interfaceParameterSelector/; + my $paramExtendedAttributes = (defined($1) ? $1 : " "); chop($paramExtendedAttributes); + my $paramType = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)")); + my $paramName = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)")); + + my $paramDataNode = new domSignature(); + $paramDataNode->name($paramName); + $paramDataNode->type($paramType); + $paramDataNode->extendedAttributes(parseExtendedAttributes($paramExtendedAttributes)); + + my $arrayRef = $newDataNode->parameters; + push(@$arrayRef, $paramDataNode); + + print " | |> Param; TYPE \"$paramType\" NAME \"$paramName\"" . + dumpExtendedAttributes("\n | ", $paramDataNode->extendedAttributes) . "\n" unless $beQuiet; + } + + my $arrayRef = $dataNode->functions; + push(@$arrayRef, $newDataNode); + } elsif ($line =~ /^\s*const/) { + $line =~ /$IDLStructure::constantSelector/; + my $constType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)")); + my $constName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)")); + my $constValue = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)")); + + my $newDataNode = new domConstant(); + $newDataNode->name($constName); + $newDataNode->type($constType); + $newDataNode->value($constValue); + + my $arrayRef = $dataNode->constants; + push(@$arrayRef, $newDataNode); + + print " | |> Constant; TYPE \"$constType\" NAME \"$constName\" VALUE \"$constValue\"\n" unless $beQuiet; + } + } + + print " |----> Interface; NAME \"$interfaceName\"" . + dumpExtendedAttributes("\n | ", $dataNode->extendedAttributes) . "\n |-\n |\n" unless $beQuiet; + } +} + +# Internal helper +sub DetermineParseMode +{ + my $object = shift; + my $line = shift; + + my $mode = MODE_UNDEF; + if ($_ =~ /module/) { + $mode = MODE_MODULE; + } elsif ($_ =~ /interface/) { + $mode = MODE_INTERFACE; + } elsif ($_ =~ /exception/) { + $mode = MODE_EXCEPTION; + } elsif ($_ =~ /alias/) { + $mode = MODE_ALIAS; + } + + return $mode; +} + +# Internal helper +sub ProcessSection +{ + my $object = shift; + + if ($parseMode eq MODE_MODULE) { + die ("Two modules in one file! Fatal error!\n") if ($document ne 0); + $document = new idlDocument(); + $object->ParseModule($document); + } elsif ($parseMode eq MODE_INTERFACE) { + my $node = new domClass(); + $object->ParseInterface($node, "interface"); + + die ("No module specified! Fatal Error!\n") if ($document eq 0); + my $arrayRef = $document->classes; + push(@$arrayRef, $node); + } elsif($parseMode eq MODE_EXCEPTION) { + my $node = new domClass(); + $object->ParseInterface($node, "exception"); + + die ("No module specified! Fatal Error!\n") if ($document eq 0); + my $arrayRef = $document->classes; + push(@$arrayRef, $node); + } elsif($parseMode eq MODE_ALIAS) { + print " |- Trying to parse alias...\n" unless $beQuiet; + + my $line = join("", @temporaryContent); + $line =~ /$IDLStructure::aliasSelector/; + + my $interfaceName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)")); + my $wrapperName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)")); + + print " |----> Alias; INTERFACE \"$interfaceName\" WRAPPER \"$wrapperName\"\n |-\n |\n" unless $beQuiet; + + # FIXME: Check if alias is already in aliases + my $aliases = $document->aliases; + $aliases->{$interfaceName} = $wrapperName; + } + + @temporaryContent = ""; +} + +1; diff --git a/V8Binding/scripts/generate-bindings.pl b/V8Binding/scripts/generate-bindings.pl new file mode 100644 index 0000000..da5d09a --- /dev/null +++ b/V8Binding/scripts/generate-bindings.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2005 Apple Computer, Inc. +# Copyright (C) 2006 Anders Carlsson <andersca@mac.com> +# +# This file is part of WebKit +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# aint with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +# This script is a temporary hack. +# Files are generated in the source directory, when they really should go +# to the DerivedSources directory. +# This should also eventually be a build rule driven off of .idl files +# however a build rule only solution is blocked by several radars: +# <rdar://problems/4251781&4251785> + +use strict; + +use File::Path; +use Getopt::Long; +use Cwd; + +use IDLParser; +use CodeGenerator; + +my @idlDirectories; +my $outputDirectory; +my $generator; +my $defines; +my $preprocessor; + +GetOptions('include=s@' => \@idlDirectories, + 'outputdir=s' => \$outputDirectory, + 'generator=s' => \$generator, + 'defines=s' => \$defines, + 'preprocessor=s' => \$preprocessor); + +my $idlFile = $ARGV[0]; + +die('Must specify input file.') unless defined($idlFile); +die('Must specify IDL search path.') unless @idlDirectories; +die('Must specify generator') unless defined($generator); +die('Must specify input file.') unless defined($idlFile); +die('Must specify output directory.') unless defined($outputDirectory); +die('Must specify defines') unless defined($defines); + +$defines =~ s/^\s+|\s+$//g; # trim whitespace + +# Parse the given IDL file. +my $parser = IDLParser->new(1); +my $document = $parser->Parse($idlFile, $defines, $preprocessor); + +# Generate desired output for given IDL file. +my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, 0, $preprocessor); +$codeGen->ProcessDocument($document, $defines); diff --git a/V8Binding/v8/DOMObjectsInclude.h b/V8Binding/v8/DOMObjectsInclude.h new file mode 100644 index 0000000..5e067b4 --- /dev/null +++ b/V8Binding/v8/DOMObjectsInclude.h @@ -0,0 +1,182 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DOMObjectsInclude_h +#define DOMObjectsInclude_h + +#include "BarInfo.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasPixelArray.h" +#include "CanvasRenderingContext2D.h" +#include "CanvasStyle.h" +#include "CharacterData.h" +#include "ClientRect.h" +#include "ClientRectList.h" +#include "Clipboard.h" +#include "Console.h" +#include "Counter.h" +#include "CSSCharsetRule.h" +#include "CSSFontFaceRule.h" +#include "CSSImportRule.h" +#include "CSSMediaRule.h" +#include "CSSPageRule.h" +#include "CSSRule.h" +#include "CSSRuleList.h" +#include "CSSValueList.h" +#include "CSSStyleRule.h" +#include "CSSStyleSheet.h" +#include "CSSVariablesDeclaration.h" +#include "CSSVariablesRule.h" +#include "Database.h" +#include "DocumentType.h" +#include "DocumentFragment.h" +#include "DOMCoreException.h" +#include "DOMImplementation.h" +#include "DOMParser.h" +#include "DOMSelection.h" +#include "DOMStringList.h" +#include "DOMWindow.h" +#include "Entity.h" +#include "EventListener.h" +#include "EventTarget.h" +#include "Event.h" +#include "EventException.h" +#include "ExceptionCode.h" +#include "File.h" +#include "FileList.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "History.h" +#include "HTMLNames.h" +#include "HTMLDocument.h" +#include "HTMLElement.h" +#include "HTMLImageElement.h" +#include "HTMLInputElement.h" +#include "HTMLSelectElement.h" +#include "HTMLOptionsCollection.h" +#include "ImageData.h" +#include "InspectorController.h" +#include "KeyboardEvent.h" +#include "Location.h" +#include "MediaError.h" +#include "MediaList.h" +#include "MediaPlayer.h" +#include "MessageChannel.h" +#include "MessageEvent.h" +#include "MessagePort.h" +#include "MimeTypeArray.h" +#include "MouseEvent.h" +#include "MutationEvent.h" +#include "Navigator.h" // for MimeTypeArray +#include "NodeFilter.h" +#include "Notation.h" +#include "NodeList.h" +#include "NodeIterator.h" +#include "OverflowEvent.h" +#include "Page.h" +#include "Plugin.h" +#include "PluginArray.h" +#include "ProcessingInstruction.h" +#include "ProgressEvent.h" +#include "Range.h" +#include "RangeException.h" +#include "Rect.h" +#include "RGBColor.h" +#include "Screen.h" +#include "ScriptExecutionContext.h" +#include "SecurityOrigin.h" +#include "Settings.h" +#include "SQLTransaction.h" +#include "SQLResultSet.h" +#include "SQLResultSetRowList.h" +#include "StyleSheet.h" +#include "StyleSheetList.h" +#include "SVGColor.h" +#include "SVGPaint.h" +#include "TextEvent.h" +#include "TextMetrics.h" +#include "TimeRanges.h" +#include "TreeWalker.h" +#include "XSLTProcessor.h" +#include "V8AbstractEventListener.h" +#include "V8CustomEventListener.h" +#include "V8DOMWindow.h" +#include "V8HTMLElement.h" +#include "V8LazyEventListener.h" +#include "V8NodeFilterCondition.h" +#include "V8ObjectEventListener.h" +#include "WebKitAnimationEvent.h" +#include "WebKitCSSKeyframeRule.h" +#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSMatrix.h" +#include "WebKitCSSTransformValue.h" +#include "WebKitPoint.h" +#include "WebKitTransitionEvent.h" +#include "WheelEvent.h" +#include "XMLHttpRequest.h" +#include "XMLHttpRequestException.h" +#include "XMLHttpRequestProgressEvent.h" +#include "XMLHttpRequestUpload.h" +#include "XMLSerializer.h" +#include "XPathException.h" +#include "XPathExpression.h" +#include "XPathNSResolver.h" +#include "XPathResult.h" + +#if ENABLE(SVG) +#include "SVGAngle.h" +#include "SVGAnimatedPoints.h" +#include "SVGElement.h" +#include "SVGElementInstance.h" +#include "SVGElementInstanceList.h" +#include "SVGException.h" +#include "SVGLength.h" +#include "SVGLengthList.h" +#include "SVGNumberList.h" +#include "SVGPathSeg.h" +#include "SVGPathSegArc.h" +#include "SVGPathSegClosePath.h" +#include "SVGPathSegCurvetoCubic.h" +#include "SVGPathSegCurvetoCubicSmooth.h" +#include "SVGPathSegCurvetoQuadratic.h" +#include "SVGPathSegCurvetoQuadraticSmooth.h" +#include "SVGPathSegLineto.h" +#include "SVGPathSegLinetoHorizontal.h" +#include "SVGPathSegLinetoVertical.h" +#include "SVGPathSegList.h" +#include "SVGPathSegMoveto.h" +#include "SVGPointList.h" +#include "SVGPreserveAspectRatio.h" +#include "SVGRenderingIntent.h" +#include "SVGStringList.h" +#include "SVGTransform.h" +#include "SVGTransformList.h" +#include "SVGUnitTypes.h" +#include "SVGURIReference.h" +#include "SVGZoomEvent.h" +#include "V8SVGPODTypeWrapper.h" +#endif // SVG + +#if ENABLE(WORKERS) +#include "Worker.h" +#include "WorkerContext.h" +#include "WorkerLocation.h" +#include "WorkerNavigator.h" +#endif // WORKERS + +#if ENABLE(XPATH) +#include "XPathEvaluator.h" +#endif // XPATH + +namespace WebCore { + +// A helper class for undetectable document.all +class UndetectableHTMLCollection : public HTMLCollection { +}; + +} // namespace WebCore + +#endif // DOMObjectsInclude_h diff --git a/V8Binding/v8/JSDOMBinding.cpp b/V8Binding/v8/JSDOMBinding.cpp new file mode 100644 index 0000000..c72a92b --- /dev/null +++ b/V8Binding/v8/JSDOMBinding.cpp @@ -0,0 +1,52 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "JSDOMBinding.h" + +#include "Document.h" +#include "Node.h" + +namespace WebCore { + +void updateDOMNodeDocument(Node* node, Document* oldDocument, + Document* newDocument) +{ + // We don't do anything here in V8 bindings +} + +ScriptState* scriptStateFromNode(Node* node) +{ + // This should be never reached with V8 bindings (WebKit only uses it + // for non-JS bindings) + ASSERT_NOT_REACHED(); + return 0; +} + +} // namespace WebCore diff --git a/V8Binding/v8/JSDOMBinding.h b/V8Binding/v8/JSDOMBinding.h new file mode 100644 index 0000000..8ed5602 --- /dev/null +++ b/V8Binding/v8/JSDOMBinding.h @@ -0,0 +1,50 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Masquerade to pretend that we support JSC namespace and avoid unforking +// This is not a reimplementation of the JSC namespace. It's just enough code +// to avoid #ifdefs in WebKit code. + +#ifndef JSDOMBinding_h +#define JSDOMBinding_h + +namespace WebCore { + class Node; + class Document; + class ScriptState; + + void updateDOMNodeDocument(Node*, Document* oldDocument, + Document* newDocument); + + ScriptState* scriptStateFromNode(Node*); + +} + + +#endif // JSDOMBinding_h diff --git a/V8Binding/v8/JSXPathNSResolver.cpp b/V8Binding/v8/JSXPathNSResolver.cpp new file mode 100644 index 0000000..2fb2849 --- /dev/null +++ b/V8Binding/v8/JSXPathNSResolver.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "JSXPathNSResolver.h" + +#if ENABLE(XPATH) + +#include "v8_proxy.h" +#include "v8_binding.h" +#include "PlatformString.h" + +namespace WebCore { + +JSXPathNSResolver::JSXPathNSResolver(v8::Handle<v8::Object> resolver) +: m_resolver(resolver) { +} + +JSXPathNSResolver::~JSXPathNSResolver() { +} + +String JSXPathNSResolver::lookupNamespaceURI(const String& prefix) { + v8::Handle<v8::Function> lookupNamespaceURIFunc; + v8::Handle<v8::String> lookupNamespaceURIName = v8::String::New("lookupNamespaceURI"); + + // Check if the resolver has a function property named lookupNamespaceURI. + if (m_resolver->Has(lookupNamespaceURIName)) { + v8::Handle<v8::Value> lookupNamespaceURI = m_resolver->Get(lookupNamespaceURIName); + if (lookupNamespaceURI->IsFunction()) { + lookupNamespaceURIFunc = v8::Handle<v8::Function>::Cast(lookupNamespaceURI); + } + } + + if (lookupNamespaceURIFunc.IsEmpty() && !m_resolver->IsFunction()) { + Frame* frame = V8Proxy::retrieveActiveFrame(); + log_info(frame, "XPathNSResolver does not have a lookupNamespaceURI method.", String()); + return String(); + } + + // Catch exceptions from calling the namespace resolver. + v8::TryCatch try_catch; + try_catch.SetVerbose(true); // Print exceptions to console. + + const int argc = 1; + v8::Handle<v8::Value> argv[argc] = { v8String(prefix) }; + v8::Handle<v8::Function> function = lookupNamespaceURIFunc.IsEmpty() + ? v8::Handle<v8::Function>::Cast(m_resolver) + : lookupNamespaceURIFunc; + + V8Proxy* proxy = V8Proxy::retrieve(); + v8::Handle<v8::Value> retval = proxy->CallFunction(function, m_resolver, argc, argv); + + // Eat exceptions from namespace resolver and return an empty string. This + // will most likely cause NAMESPACE_ERR. + if (try_catch.HasCaught()) { + return String(); + } + + return ToWebCoreString(retval); +} + +} + +#endif // ENABLE(XPATH) diff --git a/V8Binding/v8/JSXPathNSResolver.h b/V8Binding/v8/JSXPathNSResolver.h new file mode 100644 index 0000000..f0c340c --- /dev/null +++ b/V8Binding/v8/JSXPathNSResolver.h @@ -0,0 +1,33 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef JSXPATHNSRESOLVER_H__ +#define JSXPATHNSRESOLVER_H__ + +#if ENABLE(XPATH) + +#include <v8.h> +#include <wtf/RefCounted.h> +#include "XPathNSResolver.h" + +namespace WebCore { + + class String; + + class JSXPathNSResolver : public XPathNSResolver { + public: + + JSXPathNSResolver(v8::Handle<v8::Object> resolver); + virtual ~JSXPathNSResolver(); + + virtual String lookupNamespaceURI(const String& prefix); + + private: + v8::Handle<v8::Object> m_resolver; // Handle to resolver object. + }; +} + +#endif // ENABLE(XPATH) + +#endif // JSXPATHNSRESOLVER_H__ diff --git a/V8Binding/v8/NPV8Object.cpp b/V8Binding/v8/NPV8Object.cpp new file mode 100644 index 0000000..411439f --- /dev/null +++ b/V8Binding/v8/NPV8Object.cpp @@ -0,0 +1,495 @@ +/* + * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2009 Google, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <stdio.h> + +#define max max +#define min min +#include <v8.h> +#include "NPV8Object.h" +#include "ChromiumBridge.h" +#include "Frame.h" +#include "bindings/npruntime.h" +#include "npruntime_priv.h" +#include "PlatformString.h" +#include "ScriptController.h" +#include "v8_custom.h" +#include "v8_helpers.h" +#include "V8NPUtils.h" +#include "v8_proxy.h" +#include "DOMWindow.h" + +using WebCore::V8ClassIndex; +using WebCore::V8Custom; +using WebCore::V8Proxy; + +// FIXME(mbelshe): comments on why use malloc and free. +static NPObject* AllocV8NPObject(NPP, NPClass*) +{ + return static_cast<NPObject*>(malloc(sizeof(V8NPObject))); +} + +static void FreeV8NPObject(NPObject* npobj) +{ + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); +#ifndef NDEBUG + V8Proxy::UnregisterGlobalHandle(object, object->v8Object); +#endif + object->v8Object.Dispose(); + free(object); +} + +static v8::Handle<v8::Value>* listFromVariantArgs(const NPVariant* args, + uint32_t argCount, + NPObject *owner) +{ + v8::Handle<v8::Value>* argv = new v8::Handle<v8::Value>[argCount]; + for (uint32_t index = 0; index < argCount; index++) { + const NPVariant *arg = &args[index]; + argv[index] = convertNPVariantToV8Object(arg, owner); + } + return argv; +} + +// Create an identifier (null terminated utf8 char*) from the NPIdentifier. +static v8::Local<v8::String> NPIdentifierToV8Identifier(NPIdentifier name) +{ + PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>(name); + if (identifier->isString) + return v8::String::New(static_cast<const char *>(identifier->value.string)); + + char buf[32]; + sprintf(buf, "%d", identifier->value.number); + return v8::String::New(buf); +} + +static NPClass V8NPObjectClass = { NP_CLASS_STRUCT_VERSION, + AllocV8NPObject, + FreeV8NPObject, + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +// NPAPI's npruntime functions +NPClass* npScriptObjectClass = &V8NPObjectClass; + +NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, WebCore::DOMWindow* root) +{ + // Check to see if this object is already wrapped. + if (object->InternalFieldCount() == V8Custom::kNPObjectInternalFieldCount && + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->IsNumber() && + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->Uint32Value() == V8ClassIndex::NPOBJECT) { + + NPObject* rv = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, object); + NPN_RetainObject(rv); + return rv; + } + + V8NPObject* obj = reinterpret_cast<V8NPObject*>(NPN_CreateObject(npp, &V8NPObjectClass)); + obj->v8Object = v8::Persistent<v8::Object>::New(object); +#ifndef NDEBUG + V8Proxy::RegisterGlobalHandle(WebCore::NPOBJECT, obj, obj->v8Object); +#endif + obj->rootObject = root; + return reinterpret_cast<NPObject*>(obj); +} + +bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, + const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + PrivateIdentifier *identifier = static_cast<PrivateIdentifier*>(methodName); + if (!identifier->isString) + return false; + + v8::HandleScope handleScope; + // FIXME: should use the plugin's owner frame as the security context + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + // Special case the "eval" method. + if (methodName == NPN_GetStringIdentifier("eval")) { + if (argCount != 1) + return false; + if (args[0].type != NPVariantType_String) + return false; + return NPN_Evaluate(npp, npobj, const_cast<NPString*>(&args[0].value.stringValue), result); + } + + v8::Handle<v8::Value> funcObj = object->v8Object->Get(v8::String::New(identifier->value.string)); + if (funcObj.IsEmpty() || funcObj->IsNull()) { + NULL_TO_NPVARIANT(*result); + return false; + } + if (funcObj->IsUndefined()) { + VOID_TO_NPVARIANT(*result); + return false; + } + + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); // must not be null + + // FIXME: fix variable naming + // Call the function object + v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(funcObj); + // Create list of args to pass to v8 + v8::Handle<v8::Value>* argv = listFromVariantArgs(args, argCount, npobj); + v8::Local<v8::Value> resultObj = proxy->CallFunction(func, object->v8Object, argCount, argv); + delete[] argv; + + // If we had an error, return false. The spec is a little unclear here, but + // says "Returns true if the method was successfully invoked". If we get an + // error return value, was that successfully invoked? + if (resultObj.IsEmpty()) + return false; + + // Convert the result back to an NPVariant + convertV8ObjectToNPVariant(resultObj, npobj, result); + return true; + } + + if (npobj->_class->invoke) + return npobj->_class->invoke(npobj, methodName, args, argCount, result); + + VOID_TO_NPVARIANT(*result); + return true; +} + +// FIXME: Fix it same as NPN_Invoke (HandleScope and such) +bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, + uint32_t argCount, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + VOID_TO_NPVARIANT(*result); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + // Lookup the function object + v8::Handle<v8::Object> funcObj(object->v8Object); + if (!funcObj->IsFunction()) + return false; + + // Call the function object + v8::Local<v8::Value> resultObj; + v8::Handle<v8::Function> func(v8::Function::Cast(*funcObj)); + if (!func->IsNull()) { + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); + + // Create list of args to pass to v8 + v8::Handle<v8::Value>* argv = listFromVariantArgs(args, argCount, npobj); + resultObj = proxy->CallFunction(func, funcObj, argCount, argv); + delete[] argv; + } + + // If we had an error, return false. The spec is a little unclear here, but + // says "Returns true if the method was successfully invoked". If we get an + // error return value, was that successfully invoked? + if (resultObj.IsEmpty()) + return false; + + // Convert the result back to an NPVariant. + convertV8ObjectToNPVariant(resultObj, npobj, result); + return true; + } + + if (npobj->_class->invokeDefault) + return npobj->_class->invokeDefault(npobj, args, argCount, result); + + VOID_TO_NPVARIANT(*result); + return true; +} + +bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *npscript, NPVariant *result) +{ + bool popupsAllowed = WebCore::ChromiumBridge::popupsAllowed(npp); + return NPN_EvaluateHelper(npp, popupsAllowed, npobj, npscript, result); +} + +bool NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npobj, NPString* npscript, NPVariant *result) +{ + VOID_TO_NPVARIANT(*result); + if (!npobj) + return false; + + if (npobj->_class != npScriptObjectClass) + return false; + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); + + v8::Context::Scope scope(context); + + WebCore::String filename; + if (!popupsAllowed) + filename = "npscript"; + + // Convert UTF-8 stream to WebCore::String. + WebCore::String script = WebCore::String::fromUTF8(npscript->UTF8Characters, npscript->UTF8Length); + v8::Local<v8::Value> v8result = proxy->evaluate(WebCore::ScriptSourceCode(script, WebCore::KURL(filename)), 0); + + // If we had an error, return false. + if (v8result.IsEmpty()) + return false; + + convertV8ObjectToNPVariant(v8result, npobj, result); + return true; +} + +bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + v8::Local<v8::Value> v8result = obj->Get(NPIdentifierToV8Identifier(propertyName)); + + convertV8ObjectToNPVariant(v8result, npobj, result); + return true; + } + + if (npobj->_class->hasProperty && npobj->_class->getProperty) { + if (npobj->_class->hasProperty(npobj, propertyName)) + return npobj->_class->getProperty(npobj, propertyName, result); + } + + VOID_TO_NPVARIANT(*result); + return false; +} + +bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + obj->Set(NPIdentifierToV8Identifier(propertyName), + convertNPVariantToV8Object(value, object->rootObject->frame()->script()->windowScriptNPObject())); + return true; + } + + if (npobj->_class->setProperty) + return npobj->_class->setProperty(npobj, propertyName, value); + + return false; +} + +bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) +{ + if (!npobj) + return false; + if (npobj->_class != npScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + // FIXME(mbelshe) - verify that setting to undefined is right. + obj->Set(NPIdentifierToV8Identifier(propertyName), v8::Undefined()); + return true; +} + +bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + return obj->Has(NPIdentifierToV8Identifier(propertyName)); + } + + if (npobj->_class->hasProperty) + return npobj->_class->hasProperty(npobj, propertyName); + return false; +} + +bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + v8::Handle<v8::Value> prop = obj->Get(NPIdentifierToV8Identifier(methodName)); + return prop->IsFunction(); + } + + if (npobj->_class->hasMethod) + return npobj->_class->hasMethod(npobj, methodName); + return false; +} + +void NPN_SetException(NPObject *npobj, const NPUTF8 *message) +{ + if (npobj->_class != npScriptObjectClass) + return; + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(0, npobj); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, message); +} + +bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + + // FIXME(fqian): http://b/issue?id=1210340: Use a v8::Object::Keys() method + // when it exists, instead of evaluating javascript. + + // FIXME(mpcomplete): figure out how to cache this helper function. + // Run a helper function that collects the properties on the object into + // an array. + const char enumeratorCode[] = + "(function (obj) {" + " var props = [];" + " for (var prop in obj) {" + " props[props.length] = prop;" + " }" + " return props;" + "});"; + v8::Handle<v8::String> source = v8::String::New(enumeratorCode); + v8::Handle<v8::Script> script = v8::Script::Compile(source, 0); + v8::Handle<v8::Value> enumeratorObj = script->Run(); + v8::Handle<v8::Function> enumerator = v8::Handle<v8::Function>::Cast(enumeratorObj); + v8::Handle<v8::Value> argv[] = { obj }; + v8::Local<v8::Value> propsObj = enumerator->Call(v8::Handle<v8::Object>::Cast(enumeratorObj), ARRAYSIZE_UNSAFE(argv), argv); + if (propsObj.IsEmpty()) + return false; + + // Convert the results into an array of NPIdentifiers. + v8::Handle<v8::Array> props = v8::Handle<v8::Array>::Cast(propsObj); + *count = props->Length(); + *identifier = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier*) * *count)); + for (uint32_t i = 0; i < *count; ++i) { + v8::Local<v8::Value> name = props->Get(v8::Integer::New(i)); + (*identifier)[i] = getStringIdentifier(v8::Local<v8::String>::Cast(name)); + } + return true; + } + + if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) && npobj->_class->enumerate) + return npobj->_class->enumerate(npobj, identifier, count); + + return false; +} + +bool NPN_Construct(NPP npp, NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!npobj) + return false; + + // FIXME(estade): implement this case. + if (npobj->_class == npScriptObjectClass) { + VOID_TO_NPVARIANT(*result); + return false; + } + + if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) && npobj->_class->construct) + return npobj->_class->construct(npobj, args, argCount, result); + + return false; +} diff --git a/V8Binding/v8/NPV8Object.h b/V8Binding/v8/NPV8Object.h new file mode 100644 index 0000000..bfe7bb7 --- /dev/null +++ b/V8Binding/v8/NPV8Object.h @@ -0,0 +1,36 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef np_v8object_h +#define np_v8object_h + +#include "bindings/npruntime.h" +#include <v8.h> + +namespace WebCore { + class DOMWindow; +} + +extern NPClass* npScriptObjectClass; + +// A V8NPObject is a NPObject which carries additional V8-specific +// information. It is allocated and deallocated by AllocV8NPObject() +// and FreeV8NPObject() methods. +struct V8NPObject { + NPObject object; + v8::Persistent<v8::Object> v8Object; + WebCore::DOMWindow* rootObject; +}; + +struct PrivateIdentifier { + union { + const NPUTF8* string; + int32_t number; + } value; + bool isString; +}; + +NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object>, WebCore::DOMWindow*); + +#endif // np_v8object_h diff --git a/V8Binding/v8/RGBColor.cpp b/V8Binding/v8/RGBColor.cpp new file mode 100644 index 0000000..4a37ea6 --- /dev/null +++ b/V8Binding/v8/RGBColor.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "RGBColor.h" + +namespace WebCore { + +PassRefPtr<CSSPrimitiveValue> RGBColor::red() { + unsigned int value = (m_rgbcolor >> 16) & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +PassRefPtr<CSSPrimitiveValue> RGBColor::green() { + unsigned int value = (m_rgbcolor >> 8) & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +PassRefPtr<CSSPrimitiveValue> RGBColor::blue() { + unsigned int value = m_rgbcolor & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +} // namespace WebCore + diff --git a/V8Binding/v8/RGBColor.h b/V8Binding/v8/RGBColor.h new file mode 100644 index 0000000..afc0500 --- /dev/null +++ b/V8Binding/v8/RGBColor.h @@ -0,0 +1,28 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RGBColor_h +#define RGBColor_h + +#include "config.h" +#include "CSSPrimitiveValue.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +class RGBColor : public RefCounted<RGBColor> { + public: + RGBColor(unsigned rgbcolor) : m_rgbcolor(rgbcolor) { } + + PassRefPtr<CSSPrimitiveValue> red(); + PassRefPtr<CSSPrimitiveValue> green(); + PassRefPtr<CSSPrimitiveValue> blue(); + + private: + unsigned m_rgbcolor; +}; + +} // namespace WebCore + +#endif // RGBColor_h diff --git a/V8Binding/v8/ScriptController.cpp b/V8Binding/v8/ScriptController.cpp new file mode 100644 index 0000000..84ad8b4 --- /dev/null +++ b/V8Binding/v8/ScriptController.cpp @@ -0,0 +1,440 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "ScriptController.h" + +#include "ChromiumBridge.h" +#include "CString.h" +#include "Document.h" +#include "DOMWindow.h" +#include "Event.h" +#include "EventListener.h" +#include "EventNames.h" +#include "Frame.h" +#include "Node.h" +#include "NotImplemented.h" +#include "npruntime_priv.h" +#include "NPV8Object.h" +#include "ScriptSourceCode.h" +#include "Widget.h" + +#include "v8_proxy.h" +#include "v8_binding.h" +#include "V8NPObject.h" + +NPRuntimeFunctions npruntime_functions = { + NPN_GetStringIdentifier, + NPN_GetStringIdentifiers, + NPN_GetIntIdentifier, + NPN_IdentifierIsString, + NPN_UTF8FromIdentifier, + NPN_IntFromIdentifier, + NPN_CreateObject, + NPN_RetainObject, + NPN_ReleaseObject, + NPN_Invoke, + NPN_InvokeDefault, + NPN_Evaluate, + NPN_GetProperty, + NPN_SetProperty, + NPN_RemoveProperty, + NPN_HasProperty, + NPN_HasMethod, + NPN_ReleaseVariantValue, + NPN_SetException +}; + + +namespace WebCore { + +void ScriptController::setFlags(const char* str, int length) +{ + v8::V8::SetFlagsFromString(str, length); +} + +Frame* ScriptController::retrieveActiveFrame() +{ + return V8Proxy::retrieveActiveFrame(); +} + +bool ScriptController::isSafeScript(Frame* target) +{ + return V8Proxy::CanAccessFrame(target, true); +} + +void ScriptController::gcProtectJSWrapper(void* dom_object) +{ + V8Proxy::GCProtect(dom_object); +} + +void ScriptController::gcUnprotectJSWrapper(void* dom_object) +{ + V8Proxy::GCUnprotect(dom_object); +} + +ScriptController::ScriptController(Frame* frame) + : m_frame(frame) + , m_sourceURL(0) + , m_processingTimerCallback(false) + , m_paused(false) + , m_proxy(new V8Proxy(frame)) +#if ENABLE(NETSCAPE_PLUGIN_API) + , m_windowScriptNPObject(0) +#endif +{ +} + +ScriptController::~ScriptController() +{ +} + +void ScriptController::clearScriptObjects() +{ + PluginObjectMap::iterator it = m_pluginObjects.begin(); + for (; it != m_pluginObjects.end(); ++it) { + _NPN_UnregisterObject(it->second); + NPN_ReleaseObject(it->second); + } + m_pluginObjects.clear(); + +#if ENABLE(NETSCAPE_PLUGIN_API) + if (m_windowScriptNPObject) { + // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window + // script object properly. + // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point. + _NPN_DeallocateObject(m_windowScriptNPObject); + m_windowScriptNPObject = 0; + } +#endif +} + +void ScriptController::updateSecurityOrigin() +{ + m_proxy->updateSecurityOrigin(); +} + +void ScriptController::updatePlatformScriptObjects() +{ + notImplemented(); +} + +// Disconnect the proxy from its owner frame; +void ScriptController::disconnectFrame() +{ + m_proxy->disconnectFrame(); +} + +bool ScriptController::processingUserGesture() const +{ + Frame* active_frame = V8Proxy::retrieveActiveFrame(); + // No script is running, must be run by users. + if (!active_frame) + return true; + + V8Proxy* active_proxy = active_frame->script()->proxy(); + + v8::HandleScope handle_scope; + v8::Handle<v8::Context> context = V8Proxy::GetContext(active_frame); + // TODO(fqian): find all cases context can be empty: + // 1) JS is disabled; + // 2) page is NULL; + if (context.IsEmpty()) + return true; + + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> global = context->Global(); + v8::Handle<v8::Value> jsevent = global->Get(v8::String::NewSymbol("event")); + Event* event = V8Proxy::ToNativeEvent(jsevent); + + // Based on code from kjs_bindings.cpp. + // Note: This is more liberal than Firefox's implementation. + if (event) { + const AtomicString& type = event->type(); + bool event_ok = + // mouse events + type == eventNames().clickEvent || + type == eventNames().mousedownEvent || + type == eventNames().mouseupEvent || + type == eventNames().dblclickEvent || + // keyboard events + type == eventNames().keydownEvent || + type == eventNames().keypressEvent || + type == eventNames().keyupEvent || + // other accepted events + type == eventNames().selectEvent || + type == eventNames().changeEvent || + type == eventNames().focusEvent || + type == eventNames().blurEvent || + type == eventNames().submitEvent; + + if (event_ok) + return true; + } else if (active_proxy->inlineCode() && !active_proxy->timerCallback()) + // This is the <a href="javascript:window.open('...')> case -> we let it + // through + return true; + + // This is the <script>window.open(...)</script> case or a timer callback -> + // block it + return false; +} + +void ScriptController::evaluateInNewContext( + const Vector<ScriptSourceCode>& sources) { + m_proxy->evaluateInNewContext(sources); +} + +// Evaluate a script file in the environment of this proxy. +ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) +{ + v8::HandleScope hs; + v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame()); + if (context.IsEmpty()) + return ScriptValue(); + + v8::Context::Scope scope(context); + v8::Local<v8::Value> obj = m_proxy->evaluate(sourceCode, NULL); + + if (obj.IsEmpty() || obj->IsUndefined()) + return ScriptValue(); + + return ScriptValue(obj); +} + +void ScriptController::disposeJSResult(v8::Persistent<v8::Value> result) +{ + result.Dispose(); + result.Clear(); +} + +PassRefPtr<EventListener> ScriptController::createInlineEventListener( + const String& functionName, const String& code, Node* node) +{ + return m_proxy->createInlineEventListener(functionName, code, node); +} + +#if ENABLE(SVG) +PassRefPtr<EventListener> ScriptController::createSVGEventHandler( + const String& functionName, const String& code, Node* node) +{ + return m_proxy->createSVGEventHandler(functionName, code, node); +} +#endif + +void ScriptController::setEventHandlerLineno(int lineno) +{ + m_proxy->setEventHandlerLineno(lineno); +} + +void ScriptController::finishedWithEvent(Event* evt) +{ + m_proxy->finishedWithEvent(evt); +} + +// Create a V8 object with an interceptor of NPObjectPropertyGetter +void ScriptController::BindToWindowObject(Frame* frame, const String& key, NPObject* object) +{ + v8::HandleScope handle_scope; + + v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> value = CreateV8ObjectForNPObject(object, NULL); + + // Attach to the global object + v8::Handle<v8::Object> global = context->Global(); + global->Set(v8String(key), value); +} + +void ScriptController::collectGarbage() +{ + v8::HandleScope hs; + v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame()); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + + m_proxy->evaluate(ScriptSourceCode("if (window.gc) void(gc());"), NULL); +} + +NPRuntimeFunctions* ScriptController::functions() +{ + return &npruntime_functions; +} + + +bool ScriptController::haveInterpreter() const +{ + return m_proxy->ContextInitialized(); +} + +bool ScriptController::isEnabled() const +{ + return m_proxy->isEnabled(); +} + +PassScriptInstance ScriptController::createScriptInstanceForWidget(Widget* widget) +{ + ASSERT(widget != 0); + + if (widget->isFrameView()) + return 0; + + NPObject* npObject = ChromiumBridge::pluginScriptableObject(widget); + if (!npObject) + return 0; + + // Frame Memory Management for NPObjects + // ------------------------------------- + // NPObjects are treated differently than other objects wrapped by JS. + // NPObjects can be created either by the browser (e.g. the main + // window object) or by the plugin (the main plugin object + // for a HTMLEmbedElement). Further, + // unlike most DOM Objects, the frame is especially careful to ensure + // NPObjects terminate at frame teardown because if a plugin leaks a + // reference, it could leak its objects (or the browser's objects). + // + // The Frame maintains a list of plugin objects (m_pluginObjects) + // which it can use to quickly find the wrapped embed object. + // + // Inside the NPRuntime, we've added a few methods for registering + // wrapped NPObjects. The purpose of the registration is because + // javascript garbage collection is non-deterministic, yet we need to + // be able to tear down the plugin objects immediately. When an object + // is registered, javascript can use it. When the object is destroyed, + // or when the object's "owning" object is destroyed, the object will + // be un-registered, and the javascript engine must not use it. + // + // Inside the javascript engine, the engine can keep a reference to the + // NPObject as part of its wrapper. However, before accessing the object + // it must consult the NPN_Registry. + + v8::Local<v8::Object> wrapper = CreateV8ObjectForNPObject(npObject, NULL); + + // Track the plugin object. We've been given a reference to the object. + m_pluginObjects.set(widget, npObject); + + return V8ScriptInstance::create(wrapper); +} + +void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle) +{ + PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle); + if (it == m_pluginObjects.end()) + return; + _NPN_UnregisterObject(it->second); + NPN_ReleaseObject(it->second); + m_pluginObjects.remove(it); +} + +static NPObject* createNoScriptObject() +{ + notImplemented(); + return 0; +} + +static NPObject* createScriptObject(Frame* frame) +{ + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return createNoScriptObject(); + + v8::Context::Scope scope(context); + DOMWindow* window = frame->domWindow(); + v8::Handle<v8::Value> global = V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, window); + ASSERT(global->IsObject()); + return npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(global), window); +} + +NPObject* ScriptController::windowScriptNPObject() +{ + if (m_windowScriptNPObject) + return m_windowScriptNPObject; + + if (isEnabled()) { + // JavaScript is enabled, so there is a JavaScript window object. + // Return an NPObject bound to the window object. + m_windowScriptNPObject = createScriptObject(m_frame); + _NPN_RegisterObject(m_windowScriptNPObject, NULL); + } else { + // JavaScript is not enabled, so we cannot bind the NPObject to the + // JavaScript window object. Instead, we create an NPObject of a + // different class, one which is not bound to a JavaScript object. + m_windowScriptNPObject = createNoScriptObject(); + } + return m_windowScriptNPObject; +} + +NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement* plugin) +{ + // Can't create NPObjects when JavaScript is disabled + if (!isEnabled()) + return createNoScriptObject(); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = V8Proxy::GetContext(m_frame); + if (context.IsEmpty()) + return createNoScriptObject(); + v8::Context::Scope scope(context); + + DOMWindow* window = m_frame->domWindow(); + v8::Handle<v8::Value> v8plugin = V8Proxy::ToV8Object(V8ClassIndex::HTMLEMBEDELEMENT, plugin); + if (!v8plugin->IsObject()) + return createNoScriptObject(); + + return npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(v8plugin), window); +} + + +void ScriptController::clearWindowShell() +{ + // V8 binding expects ScriptController::clearWindowShell only be called + // when a frame is loading a new page. V8Proxy::clearForNavigation + // creates a new context for the new page. + m_proxy->clearForNavigation(); +} + +void ScriptController::attachDebugger(void*) +{ + notImplemented(); +} + +void ScriptController::updateDocument() +{ + m_proxy->updateDocument(); +} + +} // namespace WebCpre diff --git a/V8Binding/v8/ScriptController.h b/V8Binding/v8/ScriptController.h new file mode 100644 index 0000000..e1e9e25 --- /dev/null +++ b/V8Binding/v8/ScriptController.h @@ -0,0 +1,267 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// An interface to abstract implementation differences +// for various Javascript engines. + +#ifndef ScriptController_h +#define ScriptController_h + +#include "HashMap.h" +#include "MessagePort.h" +#include "ScriptInstance.h" +#include "ScriptValue.h" +#include "SecurityOrigin.h" + +#include "bindings/npruntime.h" + +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +#include "v8.h" +#include "v8_proxy.h" + +// JavaScript implementations which expose NPObject will need to implement +// these methods. +typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant); + +typedef NPIdentifier(*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name); +typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names, + int32_t nameCount, + NPIdentifier *identifiers); +typedef NPIdentifier(*NPN_GetIntIdentifierProcPtr) (int32_t intid); +typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier); +typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier); +typedef NPUTF8 * (*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier); + +typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP, + NPClass *aClass); +typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj); +typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj); +typedef bool (*NPN_InvokeProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier methodName, + const NPVariant *args, + unsigned argCount, + NPVariant *result); +typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp, + NPObject *obj, + const NPVariant *args, + unsigned argCount, + NPVariant *result); +typedef bool (*NPN_EvaluateProcPtr) (NPP npp, + NPObject *obj, + NPString *script, + NPVariant *result); +typedef bool (*NPN_GetPropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName, + NPVariant *result); +typedef bool (*NPN_SetPropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName, + const NPVariant *value); +typedef bool (*NPN_HasPropertyProcPtr) (NPP, + NPObject *npobj, + NPIdentifier propertyName); +typedef bool (*NPN_HasMethodProcPtr) (NPP npp, + NPObject *npobj, + NPIdentifier methodName); +typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName); +typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj, + const NPUTF8 *message); + +typedef struct _NPRuntimeFunctions { + NPN_GetStringIdentifierProcPtr getStringIdentifier; + NPN_GetStringIdentifiersProcPtr getStringIdentifiers; + NPN_GetIntIdentifierProcPtr getIntIdentifier; + NPN_IdentifierIsStringProcPtr identifierIsString; + NPN_UTF8FromIdentifierProcPtr utf8FromIdentifier; + NPN_IntFromIdentifierProcPtr intFromIdentifier; + NPN_CreateObjectProcPtr createObject; + NPN_RetainObjectProcPtr retainObject; + NPN_ReleaseObjectProcPtr releaseObject; + NPN_InvokeProcPtr invoke; + NPN_InvokeDefaultProcPtr invokeDefault; + NPN_EvaluateProcPtr evaluate; + NPN_GetPropertyProcPtr getProperty; + NPN_SetPropertyProcPtr setProperty; + NPN_RemovePropertyProcPtr removeProperty; + NPN_HasPropertyProcPtr hasProperty; + NPN_HasMethodProcPtr hasMethod; + NPN_ReleaseVariantValueProcPtr releaseVariantValue; + NPN_SetExceptionProcPtr setException; +} NPRuntimeFunctions; + +namespace WebCore { +class Document; +class EventListener; +class Event; +class Frame; +class HTMLPlugInElement; +class Node; +class ScriptSourceCode; +class String; +class Widget; + +typedef v8::Local<v8::Object> JSInstance; +typedef v8::Local<v8::Object> JSInstanceHandle; +typedef v8::Persistent<v8::Object> JSPersistentInstance; +typedef v8::Local<v8::Value> JSException; +typedef v8::Persistent<v8::Value> JSResult; + +class ScriptController { +public: + ScriptController(Frame*); + ~ScriptController(); + + // TODO(eseidel): V8Proxy should either be folded into ScriptController + // or this accessor should be made JSProxy* + V8Proxy* proxy() { return m_proxy.get(); } + + // Evaluate a script file in the environment of this proxy. + // If succeeded, 'succ' is set to true and result is returned + // as a string. + ScriptValue evaluate(const ScriptSourceCode&); + + // Executes JavaScript in a new context associated with the web frame. The + // script gets its own global scope and its own prototypes for intrinsic + // JavaScript objects (String, Array, and so-on). It shares the wrappers for + // all DOM nodes and DOM constructors. + void evaluateInNewContext(const Vector<ScriptSourceCode>& sources); + + // JSC has a WindowShell object, but for V8, the ScriptController + // is the WindowShell. + bool haveWindowShell() const { return true; } + + // Masquerade 'this' as the windowShell. + // This is a bit of a hack, but provides reasonable compatibility + // with what JSC does as well. + ScriptController* windowShell() { return this; } + + void disposeJSResult(JSResult result); + void collectGarbage(); + + PassRefPtr<EventListener> createInlineEventListener(const String& functionName, const String& code, Node*); +#if ENABLE(SVG) + PassRefPtr<EventListener> createSVGEventHandler(const String& functionName, const String& code, Node*); +#endif + + // Creates a property of the global object of a frame. + void BindToWindowObject(Frame*, const String& key, NPObject*); + + NPRuntimeFunctions* functions(); + + PassScriptInstance createScriptInstanceForWidget(Widget*); + + void disconnectFrame(); + + // Check if the javascript engine has been initialized. + bool haveInterpreter() const; + + bool isEnabled() const; + + // TODO(eseidel): void* is a compile hack + void attachDebugger(void*); + + // Create a NPObject wrapper for a JSObject + // NPObject *WrapScriptObject(NPP pluginId, JSObject* objectToWrap, + // JSRootObject* originRootObject, + // JSRootObject* rootObject); + + // --- Static methods assume we are running VM in single thread, --- + // --- and there is only one VM instance. --- + + // Returns the frame of the calling code is in. + // Not necessary the frame of this proxy. + // For example, JS code in frame A calls windowB.open(...). + // Window::open method has the frame pointer of B, but + // the execution context is in frame A, so it needs + // frame A's loader to complete URL. + static Frame* retrieveActiveFrame(); + + // Check whether it is safe to access a frame in another domain. + static bool isSafeScript(Frame* target); + + // Pass command-line flags to the JS engine + static void setFlags(const char* str, int length); + + // Protect and unprotect the JS wrapper from garbage collected. + static void gcProtectJSWrapper(void* object); + static void gcUnprotectJSWrapper(void* object); + + void finishedWithEvent(Event*); + void setEventHandlerLineno(int lineno); + + void setProcessingTimerCallback(bool b) { m_processingTimerCallback = b; } + bool processingUserGesture() const; + + void setPaused(bool b) { m_paused = b; } + bool isPaused() const { return m_paused; } + + const String* sourceURL() const { return m_sourceURL; } // 0 if we are not evaluating any script + + void clearWindowShell(); + void updateDocument(); + + void updateSecurityOrigin(); + void clearScriptObjects(); + void updatePlatformScriptObjects(); + void cleanupScriptObjectsForPlugin(void*); + +#if ENABLE(NETSCAPE_PLUGIN_API) + NPObject* createScriptObjectForPluginElement(HTMLPlugInElement*); + NPObject* windowScriptNPObject(); +#endif + +private: + Frame* m_frame; + const String* m_sourceURL; + + bool m_processingTimerCallback; + bool m_paused; + + OwnPtr<V8Proxy> m_proxy; + typedef HashMap<void*, NPObject*> PluginObjectMap; + + // A mapping between Widgets and their corresponding script object. + // This list is used so that when the plugin dies, we can immediately + // invalidate all sub-objects which are associated with that plugin. + // The frame keeps a NPObject reference for each item on the list. + PluginObjectMap m_pluginObjects; +#if ENABLE(NETSCAPE_PLUGIN_API) + NPObject* m_windowScriptNPObject; +#endif +}; + +} // namespace WebCore + +#endif // ScriptController_h diff --git a/V8Binding/v8/UndetectableHTMLCollection.idl b/V8Binding/v8/UndetectableHTMLCollection.idl new file mode 100644 index 0000000..bcb2aee --- /dev/null +++ b/V8Binding/v8/UndetectableHTMLCollection.idl @@ -0,0 +1,14 @@ +// Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. + +module html { + + // This interface is used for undetectable HTMLCollections. + // An undetectable HTMLCollection behaves like an HTMLCollection + // when used, but the 'typeof' operator returns undefined and + // ToBoolean returns false. + interface UndetectableHTMLCollection : HTMLCollection { + }; + +} diff --git a/V8Binding/v8/V8CanvasPixelArrayCustom.cpp b/V8Binding/v8/V8CanvasPixelArrayCustom.cpp new file mode 100644 index 0000000..d5441a1 --- /dev/null +++ b/V8Binding/v8/V8CanvasPixelArrayCustom.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_proxy.h" + +#include "CanvasPixelArray.h" + +namespace WebCore { + +// Get the specified value from the pixel buffer and return it wrapped as a +// JavaScript Number object to V8. Accesses outside the valid pixel buffer +// range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasPixelArray) { + INC_STATS("DOM.CanvasPixelArray.IndexedPropertyGetter"); + CanvasPixelArray* pixelBuffer = + V8Proxy::ToNativeObject<CanvasPixelArray>( + V8ClassIndex::CANVASPIXELARRAY, + info.Holder()); + + if ((index < 0) || (index >= pixelBuffer->length())) { + return v8::Undefined(); + } + unsigned char result; + if (!pixelBuffer->get(index, result)) { + return v8::Undefined(); + } + return v8::Number::New(result); +} + + +// Set the specified value in the pixel buffer. Accesses outside the valid pixel +// buffer range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasPixelArray) { + INC_STATS("DOM.CanvasPixelArray.IndexedPropertySetter"); + CanvasPixelArray* pixelBuffer = + V8Proxy::ToNativeObject<CanvasPixelArray>( + V8ClassIndex::CANVASPIXELARRAY, + info.Holder()); + + if ((index >= 0) && (index < pixelBuffer->length())) { + pixelBuffer->set(index, value->NumberValue()); + } + return value; +} + + +} // namespace WebCore diff --git a/V8Binding/v8/V8MessagePortCustom.cpp b/V8Binding/v8/V8MessagePortCustom.cpp new file mode 100644 index 0000000..6405b67 --- /dev/null +++ b/V8Binding/v8/V8MessagePortCustom.cpp @@ -0,0 +1,239 @@ +/* +* Copyright (C) 2009 Google Inc. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following disclaimer +* in the documentation and/or other materials provided with the +* distribution. +* * Neither the name of Google Inc. nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "config.h" + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_proxy.h" + +#include "V8Document.h" +#include "V8HTMLDocument.h" +#include "V8ObjectEventListener.h" + +#include "ExceptionCode.h" +#include "MessagePort.h" + +namespace WebCore { + +// FIXME: merge these with XHR's CreateHiddenXHRDependency + +// Use an array to hold dependents. It works like a ref-counted scheme. +// A value can be added more than once to the xhr object. +static void CreateHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) +{ + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::MESSAGEPORT); + v8::Local<v8::Value> cache = object->GetInternalField(V8Custom::kMessagePortRequestCacheIndex); + if (cache->IsNull() || cache->IsUndefined()) { + cache = v8::Array::New(); + object->SetInternalField(V8Custom::kMessagePortRequestCacheIndex, cache); + } + + v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); + cacheArray->Set(v8::Integer::New(cacheArray->Length()), value); +} + +static void RemoveHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) +{ + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::MESSAGEPORT); + v8::Local<v8::Value> cache = object->GetInternalField(V8Custom::kMessagePortRequestCacheIndex); + ASSERT(cache->IsArray()); + v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); + for (int i = cacheArray->Length() - 1; i >= 0; i--) { + v8::Local<v8::Value> cached = cacheArray->Get(v8::Integer::New(i)); + if (cached->StrictEquals(value)) { + cacheArray->Delete(i); + return; + } + } + + // We should only get here if we try to remove an event listener that was + // never added. +} + +ACCESSOR_GETTER(MessagePortOnmessage) +{ + INC_STATS("DOM.MessagePort.onmessage._get"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, info.Holder()); + if (messagePort->onmessage()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(messagePort->onmessage()); + v8::Local<v8::Object> v8Listener = listener->getListenerObject(); + return v8Listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(MessagePortOnmessage) +{ + INC_STATS("DOM.MessagePort.onmessage._set"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, info.Holder()); + if (value->IsNull()) { + if (messagePort->onmessage()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(messagePort->onmessage()); + v8::Local<v8::Object> v8Listener = listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), v8Listener); + } + + // Clear the listener + messagePort->setOnmessage(0); + + } else { + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(value, false); + if (listener) { + messagePort->setOnmessage(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(MessagePortOnclose) +{ + INC_STATS("DOM.MessagePort.onclose._get"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, info.Holder()); + if (messagePort->onclose()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(messagePort->onclose()); + v8::Local<v8::Object> v8Listener = listener->getListenerObject(); + return v8Listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(MessagePortOnclose) +{ + INC_STATS("DOM.MessagePort.onclose._set"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, info.Holder()); + if (value->IsNull()) { + if (messagePort->onclose()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(messagePort->onclose()); + v8::Local<v8::Object> v8Listener = listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), v8Listener); + } + + // Clear the listener + messagePort->setOnclose(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(value, false); + if (listener) { + messagePort->setOnclose(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +CALLBACK_FUNC_DECL(MessagePortStartConversation) +{ + INC_STATS("DOM.MessagePort.StartConversation()"); + if (args.Length() < 1) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); + + RefPtr<MessagePort> port = + messagePort->startConversation(messagePort->scriptExecutionContext(), + ToWebCoreString(args[0])); + v8::Handle<v8::Value> wrapper = + V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port.get()); + return wrapper; +} + +CALLBACK_FUNC_DECL(MessagePortAddEventListener) +{ + INC_STATS("DOM.MessagePort.AddEventListener()"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(args[1], false); + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + messagePort->addEventListener(type, listener, useCapture); + + CreateHiddenDependency(args.Holder(), args[1]); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(MessagePortRemoveEventListener) +{ + INC_STATS("DOM.MessagePort.RemoveEventListener()"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); // probably leaked + + RefPtr<EventListener> listener = + proxy->FindObjectEventListener(args[1], false); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + messagePort->removeEventListener(type, listener.get(), useCapture); + + RemoveHiddenDependency(args.Holder(), args[1]); + } + + return v8::Undefined(); +} + +} // namespace WebCore diff --git a/V8Binding/v8/V8NPObject.cpp b/V8Binding/v8/V8NPObject.cpp new file mode 100644 index 0000000..60e66a9 --- /dev/null +++ b/V8Binding/v8/V8NPObject.cpp @@ -0,0 +1,369 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "v8_custom.h" +#include "v8_helpers.h" +#include "V8NPObject.h" +#include "V8NPUtils.h" +#include "NPV8Object.h" +#include "npruntime_priv.h" +#include "v8_proxy.h" +#include "dom_wrapper_map.h" +#include "HTMLPlugInElement.h" +#include "V8HTMLAppletElement.h" +#include "V8HTMLEmbedElement.h" +#include "V8HTMLObjectElement.h" + +using namespace WebCore; + +enum InvokeFunctionType { + INVOKE_METHOD = 1, + INVOKE_DEFAULT = 2 +}; + +// TODO(mbelshe): need comments. +// Params: holder could be HTMLEmbedElement or NPObject +static v8::Handle<v8::Value> NPObjectInvokeImpl(const v8::Arguments& args, InvokeFunctionType funcId) +{ + NPObject* npobject; + + // These three types are subtypes of HTMLPlugInElement. + if (V8HTMLAppletElement::HasInstance(args.Holder()) || + V8HTMLEmbedElement::HasInstance(args.Holder()) || + V8HTMLObjectElement::HasInstance(args.Holder())) { + // The holder object is a subtype of HTMLPlugInElement. + HTMLPlugInElement* imp = V8Proxy::DOMWrapperToNode<HTMLPlugInElement>(args.Holder()); + ScriptInstance scriptInstance = imp->getInstance(); + if (scriptInstance) + npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, scriptInstance->instance()); + else + npobject = NULL; + } else { + // The holder object is not a subtype of HTMLPlugInElement, it + // must be an NPObject which has three internal fields. + if (args.Holder()->InternalFieldCount() != V8Custom::kNPObjectInternalFieldCount) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPMethod called on non-NPObject"); + return v8::Undefined(); + } + npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, args.Holder()); + } + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return v8::Undefined(); + } + + // wrap up parameters + int argc = args.Length(); + NPVariant* npArgs = new NPVariant[argc]; + + for (int i = 0; i < argc; i++) + convertV8ObjectToNPVariant(args[i], npobject, &npArgs[i]); + + NPVariant result; + VOID_TO_NPVARIANT(result); + + switch (funcId) { + case INVOKE_METHOD: + if (npobject->_class->invoke) { + v8::Handle<v8::String> function_name(v8::String::Cast(*args.Data())); + NPIdentifier ident = getStringIdentifier(function_name); + npobject->_class->invoke(npobject, ident, npArgs, argc, &result); + } + break; + case INVOKE_DEFAULT: + if (npobject->_class->invokeDefault) + npobject->_class->invokeDefault(npobject, npArgs, argc, &result); + break; + default: + break; + } + + for (int i=0; i < argc; i++) + NPN_ReleaseVariantValue(&npArgs[i]); + delete[] npArgs; + + // unwrap return values + v8::Handle<v8::Value> rv = convertNPVariantToV8Object(&result, npobject); + NPN_ReleaseVariantValue(&result); + + return rv; +} + + +v8::Handle<v8::Value> NPObjectMethodHandler(const v8::Arguments& args) +{ + return NPObjectInvokeImpl(args, INVOKE_METHOD); +} + + +v8::Handle<v8::Value> NPObjectInvokeDefaultHandler(const v8::Arguments& args) +{ + return NPObjectInvokeImpl(args, INVOKE_DEFAULT); +} + + +static void WeakTemplateCallback(v8::Persistent<v8::Value> obj, void* param); + +// NPIdentifier is PrivateIdentifier*. +static WeakReferenceMap<PrivateIdentifier, v8::FunctionTemplate> \ + static_template_map(&WeakTemplateCallback); + +static void WeakTemplateCallback(v8::Persistent<v8::Value> obj, void* param) +{ + PrivateIdentifier* iden = static_cast<PrivateIdentifier*>(param); + ASSERT(iden != NULL); + ASSERT(static_template_map.contains(iden)); + + static_template_map.forget(iden); +} + + +static v8::Handle<v8::Value> NPObjectGetProperty(v8::Local<v8::Object> self, + NPIdentifier ident, + v8::Local<v8::Value> key) +{ + NPObject* npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, self); + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return v8::Handle<v8::Value>(); + } + + if (npobject->_class->hasProperty && + npobject->_class->hasProperty(npobject, ident) && + npobject->_class->getProperty) { + + NPVariant result; + VOID_TO_NPVARIANT(result); + if (!npobject->_class->getProperty(npobject, ident, &result)) + return v8::Handle<v8::Value>(); + + v8::Handle<v8::Value> rv = convertNPVariantToV8Object(&result, npobject); + NPN_ReleaseVariantValue(&result); + return rv; + } else if (key->IsString() && npobject->_class->hasMethod && npobject->_class->hasMethod(npobject, ident)) { + PrivateIdentifier* id = static_cast<PrivateIdentifier*>(ident); + v8::Persistent<v8::FunctionTemplate> desc = static_template_map.get(id); + // Cache templates using identifier as the key. + if (desc.IsEmpty()) { + // Create a new template + v8::Local<v8::FunctionTemplate> temp = v8::FunctionTemplate::New(); + temp->SetCallHandler(NPObjectMethodHandler, key); + desc = v8::Persistent<v8::FunctionTemplate>::New(temp); + static_template_map.set(id, desc); + } + + // FunctionTemplate caches function for each context. + v8::Local<v8::Function> func = desc->GetFunction(); + func->SetName(v8::Handle<v8::String>::Cast(key)); + return func; + } + + return v8::Handle<v8::Value>(); +} + +v8::Handle<v8::Value> NPObjectNamedPropertyGetter(v8::Local<v8::String> name, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectGetProperty(info.Holder(), ident, name); +} + +v8::Handle<v8::Value> NPObjectIndexedPropertyGetter(uint32_t index, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectGetProperty(info.Holder(), ident, v8::Number::New(index)); +} + +v8::Handle<v8::Value> NPObjectGetNamedProperty(v8::Local<v8::Object> self, + v8::Local<v8::String> name) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectGetProperty(self, ident, name); +} + +v8::Handle<v8::Value> NPObjectGetIndexedProperty(v8::Local<v8::Object> self, + uint32_t index) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectGetProperty(self, ident, v8::Number::New(index)); +} + +static v8::Handle<v8::Value> NPObjectSetProperty(v8::Local<v8::Object> self, + NPIdentifier ident, + v8::Local<v8::Value> value) +{ + NPObject* npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, self); + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return value; // intercepted, but an exception was thrown + } + + if (npobject->_class->hasProperty && + npobject->_class->hasProperty(npobject, ident) && + npobject->_class->setProperty) { + + NPVariant npvalue; + VOID_TO_NPVARIANT(npvalue); + convertV8ObjectToNPVariant(value, npobject, &npvalue); + bool succ = npobject->_class->setProperty(npobject, ident, &npvalue); + NPN_ReleaseVariantValue(&npvalue); + if (succ) + return value; // intercept the call + } + return v8::Local<v8::Value>(); // do not intercept the call +} + + +v8::Handle<v8::Value> NPObjectNamedPropertySetter(v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectSetProperty(info.Holder(), ident, value); +} + + +v8::Handle<v8::Value> NPObjectIndexedPropertySetter(uint32_t index, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectSetProperty(info.Holder(), ident, value); +} + +v8::Handle<v8::Value> NPObjectSetNamedProperty(v8::Local<v8::Object> self, + v8::Local<v8::String> name, + v8::Local<v8::Value> value) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectSetProperty(self, ident, value); +} + +v8::Handle<v8::Value> NPObjectSetIndexedProperty(v8::Local<v8::Object> self, + uint32_t index, + v8::Local<v8::Value> value) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectSetProperty(self, ident, value); +} + + +static void WeakNPObjectCallback(v8::Persistent<v8::Value> obj, void* param); + +static DOMWrapperMap<NPObject> staticNpobjectMap(&WeakNPObjectCallback); + +static void WeakNPObjectCallback(v8::Persistent<v8::Value> obj, void* param) +{ + NPObject* npobject = static_cast<NPObject*>(param); + ASSERT(staticNpobjectMap.contains(npobject)); + ASSERT(npobject != NULL); + + // Must remove from our map before calling NPN_ReleaseObject(). + // NPN_ReleaseObject can call ForgetV8ObjectForNPObject, which + // uses the table as well. + staticNpobjectMap.forget(npobject); + + if (_NPN_IsAlive(npobject)) + NPN_ReleaseObject(npobject); +} + + +v8::Local<v8::Object> CreateV8ObjectForNPObject(NPObject* object, NPObject* root) +{ + static v8::Persistent<v8::FunctionTemplate> npObjectDesc; + + ASSERT(v8::Context::InContext()); + + // If this is a v8 object, just return it. + if (object->_class == npScriptObjectClass) { + V8NPObject* v8npobject = reinterpret_cast<V8NPObject*>(object); + return v8::Local<v8::Object>::New(v8npobject->v8Object); + } + + // If we've already wrapped this object, just return it. + if (staticNpobjectMap.contains(object)) + return v8::Local<v8::Object>::New(staticNpobjectMap.get(object)); + + // TODO: we should create a Wrapper type as a subclass of JSObject. + // It has two internal fields, field 0 is the wrapped pointer, + // and field 1 is the type. There should be an api function that + // returns unused type id. + // The same Wrapper type can be used by DOM bindings. + if (npObjectDesc.IsEmpty()) { + npObjectDesc = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New()); + npObjectDesc->InstanceTemplate()->SetInternalFieldCount(V8Custom::kNPObjectInternalFieldCount); + npObjectDesc->InstanceTemplate()->SetNamedPropertyHandler(NPObjectNamedPropertyGetter, NPObjectNamedPropertySetter); + npObjectDesc->InstanceTemplate()->SetIndexedPropertyHandler(NPObjectIndexedPropertyGetter, NPObjectIndexedPropertySetter); + npObjectDesc->InstanceTemplate()->SetCallAsFunctionHandler(NPObjectInvokeDefaultHandler); + } + + v8::Handle<v8::Function> func = npObjectDesc->GetFunction(); + v8::Local<v8::Object> value = SafeAllocation::NewInstance(func); + + // If we were unable to allocate the instance we avoid wrapping + // and registering the NP object. + if (value.IsEmpty()) + return value; + + WrapNPObject(value, object); + + // KJS retains the object as part of its wrapper (see Bindings::CInstance) + NPN_RetainObject(object); + + _NPN_RegisterObject(object, root); + + // Maintain a weak pointer for v8 so we can cleanup the object. + v8::Persistent<v8::Object> weakRef = v8::Persistent<v8::Object>::New(value); + staticNpobjectMap.set(object, weakRef); + + return value; +} + +void ForgetV8ObjectForNPObject(NPObject* object) +{ + if (staticNpobjectMap.contains(object)) { + v8::HandleScope scope; + v8::Persistent<v8::Object> handle(staticNpobjectMap.get(object)); + WebCore::V8Proxy::SetDOMWrapper(handle, WebCore::V8ClassIndex::NPOBJECT, NULL); + staticNpobjectMap.forget(object); + NPN_ReleaseObject(object); + } +} diff --git a/V8Binding/v8/V8NPObject.h b/V8Binding/v8/V8NPObject.h new file mode 100644 index 0000000..c236c60 --- /dev/null +++ b/V8Binding/v8/V8NPObject.h @@ -0,0 +1,53 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_npobject_h +#define v8_npobject_h + +#include <v8.h> +#include "third_party/npapi/bindings/npruntime.h" + +// These functions can be replaced by normal JS operation. +// Getters +v8::Handle<v8::Value> NPObjectNamedPropertyGetter(v8::Local<v8::String> name, + const v8::AccessorInfo& info); +v8::Handle<v8::Value> NPObjectIndexedPropertyGetter(uint32_t index, + const v8::AccessorInfo& info); +v8::Handle<v8::Value> NPObjectGetNamedProperty(v8::Local<v8::Object> self, + v8::Local<v8::String> name); +v8::Handle<v8::Value> NPObjectGetIndexedProperty(v8::Local<v8::Object> self, + uint32_t index); + +// Setters +v8::Handle<v8::Value> NPObjectNamedPropertySetter(v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info); +v8::Handle<v8::Value> NPObjectIndexedPropertySetter(uint32_t index, + const v8::AccessorInfo& info); +v8::Handle<v8::Value> NPObjectSetNamedProperty(v8::Local<v8::Object> self, + v8::Local<v8::String> name, + v8::Local<v8::Value> value); +v8::Handle<v8::Value> NPObjectSetIndexedProperty(v8::Local<v8::Object> self, + uint32_t index, + v8::Local<v8::Value> value); + +v8::Handle<v8::Value> NPObjectInvokeDefaultHandler(const v8::Arguments& args); + +// Get a wrapper for a NPObject. +// If the object is already wrapped, the pre-existing wrapper +// will be returned. +// If the object is not wrapped, wrap it, and give V8 a weak +// reference to the wrapper which will cleanup when there are +// no more JS references to the object. +v8::Local<v8::Object> CreateV8ObjectForNPObject(NPObject* object, NPObject *root); + +// Tell V8 to forcibly remove an object. +// This is used at plugin teardown so that the caller can +// aggressively unload the plugin library. After calling this +// function, the persistent handle to the wrapper will be +// gone, and the wrapped NPObject will be removed so that +// it cannot be referred to. +void ForgetV8ObjectForNPObject(NPObject*object); + +#endif // v8_npobject_h diff --git a/V8Binding/v8/V8NPUtils.cpp b/V8Binding/v8/V8NPUtils.cpp new file mode 100644 index 0000000..04e6ede --- /dev/null +++ b/V8Binding/v8/V8NPUtils.cpp @@ -0,0 +1,124 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "V8NPUtils.h" + +#include "DOMWindow.h" +#include "Frame.h" +#include "PlatformString.h" +#undef LOG + +#include "npruntime_priv.h" +#include "NPV8Object.h" +#include "V8NPObject.h" +#include "v8_proxy.h" + +void convertV8ObjectToNPVariant(v8::Local<v8::Value> object, NPObject *owner, NPVariant* result) +{ + VOID_TO_NPVARIANT(*result); + + // It is really the caller's responsibility to deal with the empty handle + // case because there could be different actions to take in different + // contexts. + ASSERT(!object.IsEmpty()); + + if (object.IsEmpty()) + return; + + if (object->IsInt32()) + INT32_TO_NPVARIANT(object->NumberValue(), *result); + else if (object->IsNumber()) + DOUBLE_TO_NPVARIANT(object->NumberValue(), *result); + else if (object->IsBoolean()) + BOOLEAN_TO_NPVARIANT(object->BooleanValue(), *result); + else if (object->IsNull()) + NULL_TO_NPVARIANT(*result); + else if (object->IsUndefined()) + VOID_TO_NPVARIANT(*result); + else if (object->IsString()) { + v8::String::Utf8Value utf8(object); + char* utf8_chars = strdup(*utf8); + STRINGN_TO_NPVARIANT(utf8_chars, utf8.length(), *result); + } else if (object->IsObject()) { + WebCore::DOMWindow* window = WebCore::V8Proxy::retrieveWindow(); + NPObject* npobject = npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(object), window); + if (npobject) + _NPN_RegisterObject(npobject, owner); + OBJECT_TO_NPVARIANT(npobject, *result); + } +} + + +v8::Handle<v8::Value> convertNPVariantToV8Object(const NPVariant* variant, NPObject* npobject) +{ + NPVariantType type = variant->type; + + if (type == NPVariantType_Int32) + return v8::Integer::New(NPVARIANT_TO_INT32(*variant)); + if (type == NPVariantType_Double) + return v8::Number::New(NPVARIANT_TO_DOUBLE(*variant)); + if (type == NPVariantType_Bool) + return NPVARIANT_TO_BOOLEAN(*variant) ? v8::True() : v8::False(); + if (type == NPVariantType_Null) + return v8::Null(); + if (type == NPVariantType_Void) + return v8::Undefined(); + if (type == NPVariantType_String) { + NPString src = NPVARIANT_TO_STRING(*variant); + return v8::String::New(src.UTF8Characters, src.UTF8Length); + } + if (type == NPVariantType_Object) { + NPObject* obj = NPVARIANT_TO_OBJECT(*variant); + if (obj->_class == npScriptObjectClass) + return reinterpret_cast<V8NPObject*>(obj)->v8Object; + return CreateV8ObjectForNPObject(obj, npobject); + } + return v8::Undefined(); +} + +// Helper function to create an NPN String Identifier from a v8 string. +NPIdentifier getStringIdentifier(v8::Handle<v8::String> str) +{ + const int kStackBufSize = 100; + + int bufLen = str->Length() + 1; + if (bufLen <= kStackBufSize) { + // Use local stack buffer to avoid heap allocations for small strings. + // Here we should only use the stack space for stack_buf when it's used, + // not when we use the heap. + char stackBuf[kStackBufSize]; + str->WriteAscii(stackBuf); + return NPN_GetStringIdentifier(stackBuf); + } + + v8::String::AsciiValue ascii(str); + return NPN_GetStringIdentifier(*ascii); +} diff --git a/V8Binding/v8/V8NPUtils.h b/V8Binding/v8/V8NPUtils.h new file mode 100644 index 0000000..08409f2 --- /dev/null +++ b/V8Binding/v8/V8NPUtils.h @@ -0,0 +1,27 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_np_utils_h +#define v8_np_utils_h + +#include <v8.h> +#include "third_party/npapi/bindings/npruntime.h" + +namespace WebCore { + class Frame; +} + +// Convert a V8 Value of any type (string, bool, object, etc) to a NPVariant. +void convertV8ObjectToNPVariant(v8::Local<v8::Value> object, NPObject *owner, NPVariant* result); + +// Convert a NPVariant (string, bool, object, etc) back to a V8 Value. +// The owner object is the NPObject which relates to the object, if the object +// is an Object. The created NPObject will be tied to the lifetime of the +// owner. +v8::Handle<v8::Value> convertNPVariantToV8Object(const NPVariant* value, NPObject* owner); + +// Helper function to create an NPN String Identifier from a v8 string. +NPIdentifier getStringIdentifier(v8::Handle<v8::String> str); + +#endif // v8_np_utils_h diff --git a/V8Binding/v8/V8SVGPODTypeWrapper.h b/V8Binding/v8/V8SVGPODTypeWrapper.h new file mode 100644 index 0000000..79553c2 --- /dev/null +++ b/V8Binding/v8/V8SVGPODTypeWrapper.h @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef V8SVGPODTypeWrapper_h +#define V8SVGPODTypeWrapper_h + +#if ENABLE(SVG) + +#include "config.h" +#include "SVGElement.h" +#include "SVGList.h" +#include <wtf/Assertions.h> +#include <wtf/RefCounted.h> +#include <wtf/HashMap.h> + +namespace WebCore { + +template<typename PODType> +class V8SVGPODTypeWrapper : public RefCounted<V8SVGPODTypeWrapper<PODType> > { +public: + V8SVGPODTypeWrapper() { } + virtual ~V8SVGPODTypeWrapper() { } + virtual operator PODType() = 0; + virtual void commitChange(PODType, SVGElement*) = 0; +}; + +template<typename PODType> +class V8SVGPODTypeWrapperCreatorForList : public V8SVGPODTypeWrapper<PODType> +{ +public: + typedef PODType (SVGPODListItem<PODType>::*GetterMethod)() const; + typedef void (SVGPODListItem<PODType>::*SetterMethod)(PODType); + + V8SVGPODTypeWrapperCreatorForList(SVGPODListItem<PODType>* creator, const QualifiedName& attributeName) + : m_creator(creator) + , m_getter(&SVGPODListItem<PODType>::value) + , m_setter(&SVGPODListItem<PODType>::setValue) + , m_associatedAttributeName(attributeName) + { + ASSERT(m_creator); + ASSERT(m_getter); + ASSERT(m_setter); + } + + virtual ~V8SVGPODTypeWrapperCreatorForList() { } + + // Getter wrapper + virtual operator PODType() { return (m_creator.get()->*m_getter)(); } + + // Setter wrapper + virtual void commitChange(PODType type, SVGElement* context) + { + if (!m_setter) + return; + + (m_creator.get()->*m_setter)(type); + + if (context) + context->svgAttributeChanged(m_associatedAttributeName); + } + +private: + // Update callbacks + RefPtr<SVGPODListItem<PODType> > m_creator; + GetterMethod m_getter; + SetterMethod m_setter; + const QualifiedName& m_associatedAttributeName; +}; + +template<typename PODType> +class V8SVGStaticPODTypeWrapper : public V8SVGPODTypeWrapper<PODType> +{ +public: + V8SVGStaticPODTypeWrapper(PODType type) + : m_podType(type) + { } + + virtual ~V8SVGStaticPODTypeWrapper() { } + + // Getter wrapper + virtual operator PODType() { return m_podType; } + + // Setter wrapper + virtual void commitChange(PODType type, SVGElement*) + { + m_podType = type; + } + +private: + PODType m_podType; +}; + +template<typename PODType, typename ParentTypeArg> +class V8SVGStaticPODTypeWrapperWithPODTypeParent : public V8SVGStaticPODTypeWrapper<PODType> { +public: + typedef V8SVGPODTypeWrapper<ParentTypeArg> ParentType; + + V8SVGStaticPODTypeWrapperWithPODTypeParent(PODType type, ParentType* parent) + : V8SVGStaticPODTypeWrapper<PODType>(type) + , m_parentType(parent) + { + } + + virtual void commitChange(PODType type, SVGElement* context) + { + V8SVGStaticPODTypeWrapper<PODType>::commitChange(type, context); + m_parentType->commitChange(ParentTypeArg(type), context); + } + +private: + RefPtr<ParentType> m_parentType; +}; + +template<typename PODType, typename ParentType> +class V8SVGStaticPODTypeWrapperWithParent : public V8SVGPODTypeWrapper<PODType> { +public: + typedef PODType (ParentType::*GetterMethod)() const; + typedef void (ParentType::*SetterMethod)(const PODType&); + + V8SVGStaticPODTypeWrapperWithParent(ParentType* parent, GetterMethod getter, SetterMethod setter) + : m_parent(parent) + , m_getter(getter) + , m_setter(setter) + { + ASSERT(m_parent); + ASSERT(m_getter); + ASSERT(m_setter); + } + + virtual operator PODType() + { + return (m_parent.get()->*m_getter)(); + } + + virtual void commitChange(PODType type, SVGElement* context) + { + (m_parent.get()->*m_setter)(type); + } + +private: + // Update callbacks + RefPtr<ParentType> m_parent; + GetterMethod m_getter; + SetterMethod m_setter; +}; + +template<typename PODType, typename PODTypeCreator> +class V8SVGDynamicPODTypeWrapper : public V8SVGPODTypeWrapper<PODType> +{ +public: + typedef PODType (PODTypeCreator::*GetterMethod)() const; + typedef void (PODTypeCreator::*SetterMethod)(PODType); + typedef void (*CacheRemovalCallback)(V8SVGPODTypeWrapper<PODType>*); + + V8SVGDynamicPODTypeWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter, CacheRemovalCallback cacheRemovalCallback) + : m_creator(creator) + , m_getter(getter) + , m_setter(setter) + , m_cacheRemovalCallback(cacheRemovalCallback) + { + ASSERT(creator); + ASSERT(getter); + ASSERT(setter); + ASSERT(cacheRemovalCallback); + } + + virtual ~V8SVGDynamicPODTypeWrapper() { + ASSERT(m_cacheRemovalCallback); + + (*m_cacheRemovalCallback)(this); + } + + // Getter wrapper + virtual operator PODType() { return (m_creator.get()->*m_getter)(); } + + // Setter wrapper + virtual void commitChange(PODType type, SVGElement* context) + { + (m_creator.get()->*m_setter)(type); + + if (context) + context->svgAttributeChanged(m_creator->associatedAttributeName()); + } + +private: + // Update callbacks + RefPtr<PODTypeCreator> m_creator; + GetterMethod m_getter; + SetterMethod m_setter; + CacheRemovalCallback m_cacheRemovalCallback; +}; + +// Caching facilities +template<typename PODType, typename PODTypeCreator> +struct PODTypeWrapperCacheInfo { + typedef PODType (PODTypeCreator::*GetterMethod)() const; + typedef void (PODTypeCreator::*SetterMethod)(PODType); + + // Empty value + PODTypeWrapperCacheInfo() + : creator(0) + , getter(0) + , setter(0) + { } + + // Deleted value + explicit PODTypeWrapperCacheInfo(WTF::HashTableDeletedValueType) + : creator(reinterpret_cast<PODTypeCreator*>(-1)) + , getter(0) + , setter(0) + { + } + bool isHashTableDeletedValue() const + { + return creator == reinterpret_cast<PODTypeCreator*>(-1); + } + + PODTypeWrapperCacheInfo(PODTypeCreator* _creator, GetterMethod _getter, SetterMethod _setter) + : creator(_creator) + , getter(_getter) + , setter(_setter) + { + ASSERT(creator); + ASSERT(getter); + } + + bool operator==(const PODTypeWrapperCacheInfo& other) const + { + return creator == other.creator && getter == other.getter && setter == other.setter; + } + + PODTypeCreator* creator; + GetterMethod getter; + SetterMethod setter; +}; + +template<typename PODType, typename PODTypeCreator> +struct PODTypeWrapperCacheInfoHash { + static unsigned hash(const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& info) + { + unsigned creator = reinterpret_cast<unsigned>(info.creator); + unsigned getter = reinterpret_cast<unsigned>(*(void**)&info.getter); + unsigned setter = reinterpret_cast<unsigned>(*(void**)&info.setter); + return (creator * 13) + getter ^ (setter >> 2); + } + + static bool equal(const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& a, const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& b) + { + return a == b; + } + + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +template<typename PODType, typename PODTypeCreator> +struct PODTypeWrapperCacheInfoTraits : WTF::GenericHashTraits<PODTypeWrapperCacheInfo<PODType, PODTypeCreator> > { + typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo; + + static const bool emptyValueIsZero = true; + static const bool needsDestruction = false; + + static const CacheInfo& emptyValue() + { + static CacheInfo key; + return key; + } + + static void constructDeletedValue(CacheInfo& slot) + { + new (&slot) CacheInfo(WTF::HashTableDeletedValue); + } + + static bool isDeletedValue(const CacheInfo& value) + { + return value.isHashTableDeletedValue(); + } +}; + +template<typename PODType, typename PODTypeCreator> +class V8SVGDynamicPODTypeWrapperCache +{ +public: + typedef PODType (PODTypeCreator::*GetterMethod)() const; + typedef void (PODTypeCreator::*SetterMethod)(PODType); + + typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo; + typedef PODTypeWrapperCacheInfoHash<PODType, PODTypeCreator> CacheInfoHash; + typedef PODTypeWrapperCacheInfoTraits<PODType, PODTypeCreator> CacheInfoTraits; + + typedef V8SVGPODTypeWrapper<PODType> WrapperBase; + typedef V8SVGDynamicPODTypeWrapper<PODType, PODTypeCreator> DynamicWrapper; + + typedef HashMap<CacheInfo, DynamicWrapper*, CacheInfoHash, CacheInfoTraits> DynamicWrapperHashMap; + typedef typename DynamicWrapperHashMap::const_iterator DynamicWrapperHashMapIterator; + + static DynamicWrapperHashMap& dynamicWrapperHashMap() + { + static DynamicWrapperHashMap _dynamicWrapperHashMap; + return _dynamicWrapperHashMap; + } + + // Used for readwrite attributes only + static WrapperBase* lookupOrCreateWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter) + { + DynamicWrapperHashMap& map(dynamicWrapperHashMap()); + CacheInfo info(creator, getter, setter); + + if (map.contains(info)) + return map.get(info); + + DynamicWrapper* wrapper = new V8SVGDynamicPODTypeWrapper<PODType, PODTypeCreator>( + creator, getter, setter, forgetWrapper); + map.set(info, wrapper); + return wrapper; + } + + static void forgetWrapper(V8SVGPODTypeWrapper<PODType>* wrapper) + { + DynamicWrapperHashMap& map(dynamicWrapperHashMap()); + + DynamicWrapperHashMapIterator it = map.begin(); + DynamicWrapperHashMapIterator end = map.end(); + + for (; it != end; ++it) { + if (it->second != wrapper) + continue; + + // It's guaranteed that there's just one object we need to take care of. + map.remove(it->first); + break; + } + } +}; + + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // V8SVGPODTypeWrapper_h diff --git a/V8Binding/v8/V8WorkerContextCustom.cpp b/V8Binding/v8/V8WorkerContextCustom.cpp new file mode 100644 index 0000000..e646bb5 --- /dev/null +++ b/V8Binding/v8/V8WorkerContextCustom.cpp @@ -0,0 +1,230 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_proxy.h" +#include "WorkerContextExecutionProxy.h" + +#include "ExceptionCode.h" +#include "MessagePort.h" +#include "NotImplemented.h" +#include "V8Document.h" +#include "V8HTMLDocument.h" +#include "V8WorkerContextEventListener.h" +#include "WorkerContext.h" + +namespace WebCore { + +// TODO(mbelshe) - merge these with XHR's CreateHiddenXHRDependency + +// Use an array to hold dependents. It works like a ref-counted scheme. +// A value can be added more than once to the xhr object. +static void CreateHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKERCONTEXT); + v8::Local<v8::Value> cache = + object->GetInternalField(V8Custom::kWorkerContextRequestCacheIndex); + if (cache->IsNull() || cache->IsUndefined()) { + cache = v8::Array::New(); + object->SetInternalField(V8Custom::kWorkerContextRequestCacheIndex, cache); + } + + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + cache_array->Set(v8::Integer::New(cache_array->Length()), value); +} + +static void RemoveHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKERCONTEXT); + v8::Local<v8::Value> cache = + object->GetInternalField(V8Custom::kWorkerContextRequestCacheIndex); + ASSERT(cache->IsArray()); + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + for (int i = cache_array->Length() - 1; i >= 0; i--) { + v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i)); + if (cached->StrictEquals(value)) { + cache_array->Delete(i); + return; + } + } + + // We should only get here if we try to remove an event listener that was + // never added. +} + +ACCESSOR_GETTER(WorkerContextSelf) { + INC_STATS(L"DOM.WorkerContext.self._get"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, info.Holder()); + return WorkerContextExecutionProxy::WorkerContextToV8Object(imp); +} + +ACCESSOR_GETTER(WorkerContextOnmessage) { + INC_STATS(L"DOM.WorkerContext.onmessage._get"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, info.Holder()); + if (imp->onmessage()) { + V8WorkerContextEventListener* listener = + static_cast<V8WorkerContextEventListener*>(imp->onmessage()); + v8::Local<v8::Object> v8_listener = listener->getListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(WorkerContextOnmessage) { + INC_STATS(L"DOM.WorkerContext.onmessage._set"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, info.Holder()); + V8WorkerContextEventListener* old_listener = + static_cast<V8WorkerContextEventListener*>(imp->onmessage()); + if (value->IsNull()) { + if (imp->onmessage()) { + v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + // Clear the listener + imp->setOnmessage(0); + + } else { + RefPtr<V8EventListener> listener = + imp->script()->proxy()->FindOrCreateEventListener( + v8::Local<v8::Object>::Cast(value), false, false); + if (listener) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = + old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + imp->setOnmessage(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +v8::Handle<v8::Value> SetTimeoutOrInterval(const v8::Arguments& args, + bool singleShot) { + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, args.Holder()); + + int delay = ToInt32(args[1]); + + notImplemented(); + + return v8::Undefined(); +} + +v8::Handle<v8::Value> ClearTimeoutOrInterval(const v8::Arguments& args) { + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, args.Holder()); + + bool ok = false; + int tid = ToInt32(args[0], ok); + if (ok) { + imp->removeTimeout(tid); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(WorkerContextImportScripts) { + INC_STATS(L"DOM.WorkerContext.importScripts()"); + notImplemented(); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(WorkerContextSetTimeout) { + INC_STATS(L"DOM.WorkerContext.setTimeout()"); + return SetTimeoutOrInterval(args, true); +} + +CALLBACK_FUNC_DECL(WorkerContextClearTimeout) { + INC_STATS(L"DOM.WorkerContext.clearTimeout()"); + return ClearTimeoutOrInterval(args); +} + +CALLBACK_FUNC_DECL(WorkerContextSetInterval) { + INC_STATS(L"DOM.WorkerContext.setInterval()"); + return SetTimeoutOrInterval(args, false); +} + +CALLBACK_FUNC_DECL(WorkerContextClearInterval) { + INC_STATS(L"DOM.WorkerContext.clearInterval()"); + return ClearTimeoutOrInterval(args); +} + +CALLBACK_FUNC_DECL(WorkerContextAddEventListener) { + INC_STATS(L"DOM.WorkerContext.addEventListener()"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, args.Holder()); + + RefPtr<V8EventListener> listener = + imp->script()->proxy()->FindOrCreateEventListener( + v8::Local<v8::Object>::Cast(args[1]), false, false); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->addEventListener(type, listener, useCapture); + + CreateHiddenDependency(args.Holder(), args[1]); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(WorkerContextRemoveEventListener) { + INC_STATS(L"DOM.WorkerContext.removeEventListener()"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, args.Holder()); + WorkerContextExecutionProxy* proxy = imp->script()->proxy(); + + RefPtr<V8EventListener> listener = proxy->FindOrCreateEventListener( + v8::Local<v8::Object>::Cast(args[1]), false, true); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->removeEventListener(type, listener.get(), useCapture); + + RemoveHiddenDependency(args.Holder(), args[1]); + } + + return v8::Undefined(); +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/V8Binding/v8/V8WorkerCustom.cpp b/V8Binding/v8/V8WorkerCustom.cpp new file mode 100644 index 0000000..1f7e5fe --- /dev/null +++ b/V8Binding/v8/V8WorkerCustom.cpp @@ -0,0 +1,282 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_proxy.h" + +#include "ExceptionCode.h" +#include "Frame.h" +#include "MessagePort.h" +#include "V8Document.h" +#include "V8HTMLDocument.h" +#include "V8ObjectEventListener.h" +#include "Worker.h" +#include "WorkerContextExecutionProxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(WorkerConstructor) { + INC_STATS(L"DOM.Worker.Constructor"); + + if (!WorkerContextExecutionProxy::isWebWorkersEnabled()) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Worker is not enabled."); + return v8::Undefined(); + } + + if (!args.IsConstructCall()) { + V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, + "DOM object constructor cannot be called as a function."); + return v8::Undefined(); + } + + if (args.Length() == 0) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + v8::TryCatch try_catch; + v8::Handle<v8::String> script_url = args[0]->ToString(); + if (try_catch.HasCaught()) { + v8::ThrowException(try_catch.Exception()); + return v8::Undefined(); + } + if (script_url.IsEmpty()) { + return v8::Undefined(); + } + + // Get the document. + Frame* frame = V8Proxy::retrieveFrame(); + if (!frame) + return v8::Undefined(); + Document* document = frame->document(); + + // Create the worker object. + // Note: it's OK to let this RefPtr go out of scope because we also call + // SetDOMWrapper(), which effectively holds a reference to obj. + ExceptionCode ec = 0; + RefPtr<Worker> obj = Worker::create( + ToWebCoreString(script_url), document, ec); + + // Setup the standard wrapper object internal fields. + v8::Handle<v8::Object> wrapper_object = args.Holder(); + V8Proxy::SetDOMWrapper( + wrapper_object, V8ClassIndex::WORKER, obj.get()); + + obj->ref(); + V8Proxy::SetJSWrapperForActiveDOMObject( + obj.get(), v8::Persistent<v8::Object>::New(wrapper_object)); + + return wrapper_object; +} + +// TODO(mbelshe) - merge these with XHR's CreateHiddenXHRDependency + +// Use an array to hold dependents. It works like a ref-counted scheme. +// A value can be added more than once to the xhr object. +static void CreateHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(object) == + V8ClassIndex::WORKER); + v8::Local<v8::Value> cache = + object->GetInternalField(V8Custom::kWorkerRequestCacheIndex); + if (cache->IsNull() || cache->IsUndefined()) { + cache = v8::Array::New(); + object->SetInternalField(V8Custom::kWorkerRequestCacheIndex, cache); + } + + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + cache_array->Set(v8::Integer::New(cache_array->Length()), value); +} + +static void RemoveHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKER); + v8::Local<v8::Value> cache = + object->GetInternalField(V8Custom::kWorkerRequestCacheIndex); + ASSERT(cache->IsArray()); + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + for (int i = cache_array->Length() - 1; i >= 0; i--) { + v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i)); + if (cached->StrictEquals(value)) { + cache_array->Delete(i); + return; + } + } + + // We should only get here if we try to remove an event listener that was + // never added. +} + +ACCESSOR_GETTER(WorkerOnmessage) { + INC_STATS(L"DOM.Worker.onmessage._get"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, info.Holder()); + if (imp->onmessage()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(imp->onmessage()); + v8::Local<v8::Object> v8_listener = listener->getListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(WorkerOnmessage) { + INC_STATS(L"DOM.Worker.onmessage._set"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, info.Holder()); + V8ObjectEventListener* old_listener = + static_cast<V8ObjectEventListener*>(imp->onmessage()); + if (value->IsNull()) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + // Clear the listener + imp->setOnmessage(0); + + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(value, false); + if (listener) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = + old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + imp->setOnmessage(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(WorkerOnerror) { + INC_STATS(L"DOM.Worker.onerror._get"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, info.Holder()); + if (imp->onerror()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(imp->onerror()); + v8::Local<v8::Object> v8_listener = listener->getListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(WorkerOnerror) { + INC_STATS(L"DOM.Worker.onerror._set"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, info.Holder()); + V8ObjectEventListener* old_listener = + static_cast<V8ObjectEventListener*>(imp->onerror()); + if (value->IsNull()) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = + old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + // Clear the listener + imp->setOnerror(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(value, false); + if (listener) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + imp->setOnerror(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +CALLBACK_FUNC_DECL(WorkerAddEventListener) { + INC_STATS(L"DOM.Worker.addEventListener()"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(args[1], false); + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->addEventListener(type, listener, useCapture); + + CreateHiddenDependency(args.Holder(), args[1]); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(WorkerRemoveEventListener) { + INC_STATS(L"DOM.Worker.removeEventListener()"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); // probably leaked + + RefPtr<EventListener> listener = + proxy->FindObjectEventListener(args[1], false); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->removeEventListener(type, listener.get(), useCapture); + + RemoveHiddenDependency(args.Holder(), args[1]); + } + + return v8::Undefined(); +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/V8Binding/v8/dom_wrapper_map.h b/V8Binding/v8/dom_wrapper_map.h new file mode 100644 index 0000000..e95ff88 --- /dev/null +++ b/V8Binding/v8/dom_wrapper_map.h @@ -0,0 +1,72 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BINDINGS_V8_DOM_WRAPPER_MAP +#define BINDINGS_V8_DOM_WRAPPER_MAP + +#include <v8.h> +#include <wtf/HashMap.h> + +// A table of wrappers with weak pointers. +// This table allows us to avoid track wrapped objects for debugging +// and for ensuring that we don't double wrap the same object. +template<class KeyType, class ValueType> +class WeakReferenceMap { + public: + WeakReferenceMap(v8::WeakReferenceCallback callback) : + weak_reference_callback_(callback) { } +#ifndef NDEBUG + virtual ~WeakReferenceMap() { + if (map_.size() > 0) { + fprintf(stderr, "Leak %d JS wrappers.\n", map_.size()); + // Print out details. + } + } +#endif + + // Get the JS wrapper object of an object. + virtual v8::Persistent<ValueType> get(KeyType* obj) { + ValueType* wrapper = map_.get(obj); + return wrapper ? v8::Persistent<ValueType>(wrapper) + : v8::Persistent<ValueType>(); + } + + virtual void set(KeyType* obj, v8::Persistent<ValueType> wrapper) { + ASSERT(!map_.contains(obj)); + wrapper.MakeWeak(obj, weak_reference_callback_); + map_.set(obj, *wrapper); + } + + virtual void forget(KeyType* obj) { + ASSERT(obj); + ValueType* wrapper = map_.take(obj); + if (wrapper) { + v8::Persistent<ValueType> handle(wrapper); + handle.Dispose(); + handle.Clear(); + } + } + + bool contains(KeyType* obj) { + return map_.contains(obj); + } + + HashMap<KeyType*, ValueType*>& impl() { + return map_; + } + + protected: + HashMap<KeyType*, ValueType*> map_; + v8::WeakReferenceCallback weak_reference_callback_; +}; + + +template <class KeyType> +class DOMWrapperMap : public WeakReferenceMap<KeyType, v8::Object> { + public: + DOMWrapperMap(v8::WeakReferenceCallback callback) : + WeakReferenceMap<KeyType, v8::Object>(callback) { } +}; + +#endif // BINDINGS_V8_DOM_WRAPPER_MAP diff --git a/V8Binding/v8/npruntime.cpp b/V8Binding/v8/npruntime.cpp new file mode 100644 index 0000000..1ecb68c --- /dev/null +++ b/V8Binding/v8/npruntime.cpp @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2009 Google, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <map> +#include <set> +#include <string> +#include <v8.h> + +#include "bindings/npruntime.h" +#include "NPV8Object.h" +#include "npruntime_priv.h" +#include "V8NPObject.h" + +#include <wtf/Assertions.h> + +using namespace v8; + + +// FIXME: Consider removing locks if we're singlethreaded already. +// The static initializer here should work okay, but we want to avoid +// static initialization in general. +// +// Commenting out the locks to avoid dependencies on chrome for now. +// Need a platform abstraction which we can use. +// static Lock StringIdentifierMapLock; + +namespace { + +// We use StringKey here as the key-type to avoid a string copy to +// construct the map key and for faster comparisons than strcmp. +struct StringKey { + StringKey(const char* str) : string(str), length(strlen(str)) {} + const char* string; + const size_t length; +}; + +inline bool operator<(const StringKey& x, const StringKey& y) { + // Shorter strings are less than longer strings, memcmp breaks ties. + if (x.length < y.length) + return true; + else if (x.length > y.length) + return false; + else + return memcmp(x.string, y.string, y.length) < 0; +} + +} // namespace + +typedef std::map<const StringKey, PrivateIdentifier*> StringIdentifierMap; + +static StringIdentifierMap* getStringIdentifierMap() { + static StringIdentifierMap* stringIdentifierMap = 0; + if (!stringIdentifierMap) + stringIdentifierMap = new StringIdentifierMap(); + return stringIdentifierMap; +} + +// FIXME: Consider removing locks if we're singlethreaded already. +// static Lock IntIdentifierMapLock; + +typedef std::map<int, PrivateIdentifier*> IntIdentifierMap; + +static IntIdentifierMap* getIntIdentifierMap() { + static IntIdentifierMap* intIdentifierMap = 0; + if (!intIdentifierMap) + intIdentifierMap = new IntIdentifierMap(); + return intIdentifierMap; +} + +extern "C" { + +NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name) { + ASSERT(name); + + if (name) { + // AutoLock safeLock(StringIdentifierMapLock); + + StringKey key(name); + StringIdentifierMap* identMap = getStringIdentifierMap(); + StringIdentifierMap::iterator iter = identMap->find(key); + if (iter != identMap->end()) + return static_cast<NPIdentifier>(iter->second); + + size_t nameLen = key.length; + + // We never release identifiers, so this dictionary will grow. + PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>( + malloc(sizeof(PrivateIdentifier) + nameLen + 1)); + char* nameStorage = reinterpret_cast<char*>(identifier + 1); + memcpy(nameStorage, name, nameLen + 1); + identifier->isString = true; + identifier->value.string = reinterpret_cast<NPUTF8*>(nameStorage); + key.string = nameStorage; + (*identMap)[key] = identifier; + return (NPIdentifier)identifier; + } + + return 0; +} + +void NPN_GetStringIdentifiers(const NPUTF8** names, int32_t nameCount, + NPIdentifier* identifiers) { + ASSERT(names); + ASSERT(identifiers); + + if (names && identifiers) + for (int i = 0; i < nameCount; i++) + identifiers[i] = NPN_GetStringIdentifier(names[i]); +} + +NPIdentifier NPN_GetIntIdentifier(int32_t intid) { + // AutoLock safeLock(IntIdentifierMapLock); + + IntIdentifierMap* identMap = getIntIdentifierMap(); + IntIdentifierMap::iterator iter = identMap->find(intid); + if (iter != identMap->end()) + return static_cast<NPIdentifier>(iter->second); + + // We never release identifiers, so this dictionary will grow. + PrivateIdentifier* identifier = reinterpret_cast<PrivateIdentifier*>( + malloc(sizeof(PrivateIdentifier))); + identifier->isString = false; + identifier->value.number = intid; + (*identMap)[intid] = identifier; + return (NPIdentifier)identifier; +} + +bool NPN_IdentifierIsString(NPIdentifier identifier) { + PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier); + return i->isString; +} + +NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier) { + PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier); + if (!i->isString || !i->value.string) + return NULL; + + return (NPUTF8 *)strdup(i->value.string); +} + +int32_t NPN_IntFromIdentifier(NPIdentifier identifier) { + PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier); + if (i->isString) + return 0; + return i->value.number; +} + +void NPN_ReleaseVariantValue(NPVariant* variant) { + ASSERT(variant); + + if (variant->type == NPVariantType_Object) { + NPN_ReleaseObject(variant->value.objectValue); + variant->value.objectValue = 0; + } else if (variant->type == NPVariantType_String) { + free((void*)variant->value.stringValue.UTF8Characters); + variant->value.stringValue.UTF8Characters = 0; + variant->value.stringValue.UTF8Length = 0; + } + + variant->type = NPVariantType_Void; +} + +NPObject *NPN_CreateObject(NPP npp, NPClass* aClass) { + ASSERT(aClass); + + if (aClass) { + NPObject* obj; + if (aClass->allocate != NULL) + obj = aClass->allocate(npp, aClass); + else + obj = reinterpret_cast<NPObject*>(malloc(sizeof(NPObject))); + + obj->_class = aClass; + obj->referenceCount = 1; + return obj; + } + + return 0; +} + +NPObject* NPN_RetainObject(NPObject* obj) { + ASSERT(obj); + ASSERT(obj->referenceCount > 0); + + if (obj) + obj->referenceCount++; + + return obj; +} + +// _NPN_DeallocateObject actually deletes the object. Technically, +// callers should use NPN_ReleaseObject. Webkit exposes this function +// to kill objects which plugins may not have properly released. +void _NPN_DeallocateObject(NPObject *obj) { + ASSERT(obj); + ASSERT(obj->referenceCount >= 0); + + if (obj) { + // NPObjects that remain in pure C++ may never have wrappers. + // Hence, if it's not already alive, don't unregister it. + // If it is alive, unregister it as the *last* thing we do + // so that it can do as much cleanup as possible on its own. + if (_NPN_IsAlive(obj)) + _NPN_UnregisterObject(obj); + + obj->referenceCount = -1; + if (obj->_class->deallocate) + obj->_class->deallocate(obj); + else + free(obj); + } +} + +void NPN_ReleaseObject(NPObject* obj) { + ASSERT(obj); + ASSERT(obj->referenceCount >= 1); + + if (obj && obj->referenceCount >= 1) { + if (--obj->referenceCount == 0) + _NPN_DeallocateObject(obj); + } +} + +void _NPN_InitializeVariantWithStringCopy(NPVariant* variant, + const NPString* value) { + variant->type = NPVariantType_String; + variant->value.stringValue.UTF8Length = value->UTF8Length; + variant->value.stringValue.UTF8Characters = + reinterpret_cast<NPUTF8*>(malloc(sizeof(NPUTF8) * value->UTF8Length)); + memcpy((void*)variant->value.stringValue.UTF8Characters, + value->UTF8Characters, + sizeof(NPUTF8) * value->UTF8Length); +} + + +// NPN_Registry +// +// The registry is designed for quick lookup of NPObjects. +// JS needs to be able to quickly lookup a given NPObject to determine +// if it is alive or not. +// The browser needs to be able to quickly lookup all NPObjects which are +// "owned" by an object. +// +// The g_live_objects is a hash table of all live objects to their owner +// objects. Presence in this table is used primarily to determine if +// objects are live or not. +// +// The g_root_objects is a hash table of root objects to a set of +// objects that should be deactivated in sync with the root. A +// root is defined as a top-level owner object. This is used on +// Frame teardown to deactivate all objects associated +// with a particular plugin. + +typedef std::set<NPObject*> NPObjectSet; +typedef std::map<NPObject*, NPObject*> NPObjectMap; +typedef std::map<NPObject*, NPObjectSet*> NPRootObjectMap; + +// A map of live NPObjects with pointers to their Roots. +NPObjectMap g_live_objects; + +// A map of the root objects and the list of NPObjects +// associated with that object. +NPRootObjectMap g_root_objects; + +void _NPN_RegisterObject(NPObject* obj, NPObject* owner) { + ASSERT(obj); + + // Check if already registered. + if (g_live_objects.find(obj) != g_live_objects.end()) { + return; + } + + if (!owner) { + // Registering a new owner object. + ASSERT(g_root_objects.find(obj) == g_root_objects.end()); + g_root_objects[obj] = new NPObjectSet(); + } else { + // Always associate this object with it's top-most parent. + // Since we always flatten, we only have to look up one level. + NPObjectMap::iterator owner_entry = g_live_objects.find(owner); + NPObject* parent = NULL; + if (g_live_objects.end() != owner_entry) + parent = owner_entry->second; + + if (parent) { + owner = parent; + } + ASSERT(g_root_objects.find(obj) == g_root_objects.end()); + if (g_root_objects.find(owner) != g_root_objects.end()) + (g_root_objects[owner])->insert(obj); + } + + ASSERT(g_live_objects.find(obj) == g_live_objects.end()); + g_live_objects[obj] = owner; +} + +void _NPN_UnregisterObject(NPObject* obj) { + ASSERT(obj); + ASSERT(g_live_objects.find(obj) != g_live_objects.end()); + + NPObject* owner = NULL; + if (g_live_objects.find(obj) != g_live_objects.end()) + owner = g_live_objects.find(obj)->second; + + if (owner == NULL) { + // Unregistering a owner object; also unregister it's descendants. + ASSERT(g_root_objects.find(obj) != g_root_objects.end()); + NPObjectSet* set = g_root_objects[obj]; + while (set->size() > 0) { +#ifndef NDEBUG + size_t size = set->size(); +#endif + NPObject* sub_object = *(set->begin()); + // The sub-object should not be a owner! + ASSERT(g_root_objects.find(sub_object) == g_root_objects.end()); + + // First, unregister the object. + set->erase(sub_object); + g_live_objects.erase(sub_object); + + // Remove the JS references to the object. + ForgetV8ObjectForNPObject(sub_object); + + ASSERT(set->size() < size); + } + delete set; + g_root_objects.erase(obj); + } else { + NPRootObjectMap::iterator owner_entry = g_root_objects.find(owner); + if (owner_entry != g_root_objects.end()) { + NPObjectSet* list = owner_entry->second; + ASSERT(list->find(obj) != list->end()); + list->erase(obj); + } + } + ForgetV8ObjectForNPObject(obj); + + g_live_objects.erase(obj); +} + +bool _NPN_IsAlive(NPObject* obj) { + return g_live_objects.find(obj) != g_live_objects.end(); +} + +} // extern "C" diff --git a/V8Binding/v8/npruntime_impl.h b/V8Binding/v8/npruntime_impl.h new file mode 100644 index 0000000..9a9b612 --- /dev/null +++ b/V8Binding/v8/npruntime_impl.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef npruntime_impl_h +#define npruntime_impl_h + +#include "bindings/npruntime.h" + +// This file exists to support WebCore, which expects to be able to call upon +// portions of the NPRuntime implementation. + +// A simple mapping for now. FIXME We should probably just adopt the +// underscore prefix as our naming convention too. +#define _NPN_ReleaseObject NPN_ReleaseObject + +#endif diff --git a/V8Binding/v8/npruntime_internal.h b/V8Binding/v8/npruntime_internal.h new file mode 100644 index 0000000..75bf2b0 --- /dev/null +++ b/V8Binding/v8/npruntime_internal.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Collabora, Ltd. 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.1 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * This is a internal include header for npapi.h + * + * Some of the #defines which are in X11 headers conflict with type and enum + * names in JavaScriptCore and WebCore + * This header #undefs those defines to fix the conflicts + * If you need to include npapi.h or npruntime.h when building on X11, + * include this file instead of the actual npapi.h or npruntime.h + */ + +#include "npapi.h" +#include "npruntime.h" +#include "npfunctions.h" + +#ifdef XP_UNIX + #include <X11/Xresource.h> + + #undef None + #undef Above + #undef Below + #undef Auto + #undef Complex + #undef Status +#endif diff --git a/V8Binding/v8/npruntime_priv.h b/V8Binding/v8/npruntime_priv.h new file mode 100644 index 0000000..0aa952c --- /dev/null +++ b/V8Binding/v8/npruntime_priv.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NP_RUNTIME_PRIV_H_ +#define NP_RUNTIME_PRIV_H_ + + +#include "third_party/npapi/bindings/npruntime.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + _NPN_InitializeVariantWithStringCopy() will copy string data. The string data + will be deallocated by calls to NPReleaseVariantValue(). +*/ +void _NPN_InitializeVariantWithStringCopy(NPVariant*, const NPString*); +void _NPN_DeallocateObject(NPObject *obj); + +// The following routines allow the browser to aggressively cleanup NPObjects +// on a per plugin basis. All NPObjects used through the NPRuntime API should +// be "registered" while they are alive. After an object has been +// deleted, it is possible for Javascript to have a reference to that object +// which has not yet been garbage collected. Javascript access to NPObjects +// will reference this registry to determine if the object is accessible or +// not. + +// Windows introduces an additional complication for objects created by the +// plugin. Plugins load inside of a DLL. Each DLL has it's own heap. If +// the browser unloads the plugin DLL, all objects created within the DLL's +// heap instantly become invalid. Normally, when WebKit drops the reference +// on the top-level plugin object, it tells the plugin manager that the +// plugin can be destroyed, which can unload the DLL. So, we must eliminate +// all pointers to any object ever created by the plugin. + +// We generally associate NPObjects with an owner. The owner of an NPObject +// is an NPObject which, when destroyed, also destroys all objects it owns. +// For example, if an NPAPI plugin creates 10 sub-NPObjects, all 11 objects +// (the NPAPI plugin + its 10 sub-objects) should become inaccessible +// simultaneously. + +// The ownership hierarchy is flat, and not a tree. Imagine the following +// object creation: +// PluginObject +// | +// +-- Creates -----> Object1 +// | +// +-- Creates -----> Object2 +// +// PluginObject will be the "owner" for both Object1 and Object2. + +// Register an NPObject with the runtime. If the owner is NULL, the +// object is treated as an owning object. If owner is not NULL, +// this object will be registered as owned by owner's top-level owner. +void _NPN_RegisterObject(NPObject* obj, NPObject* owner); + +// Unregister an NPObject with the runtime. If obj is an owning +// object, this call will also unregister all of the owned objects. +void _NPN_UnregisterObject(NPObject* obj); + +// Check to see if an object is registered with the runtime. +// Return true if registered, false otherwise. +bool _NPN_IsAlive(NPObject* obj); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif diff --git a/V8Binding/v8/v8_binding.cpp b/V8Binding/v8/v8_binding.cpp new file mode 100644 index 0000000..3a36fc5 --- /dev/null +++ b/V8Binding/v8/v8_binding.cpp @@ -0,0 +1,120 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "v8_binding.h" + +#include "AtomicString.h" +#include "CString.h" +#include "MathExtras.h" +#include "PlatformString.h" +#include "StringBuffer.h" + +#include <v8.h> + +namespace WebCore { + +// WebCoreStringResource is a helper class for v8ExternalString. It is used +// to manage the life-cycle of the underlying buffer of the external string. +class WebCoreStringResource: public v8::String::ExternalStringResource { + public: + explicit WebCoreStringResource(const String& str) + : impl_(str.impl()) { } + + virtual ~WebCoreStringResource() {} + + const uint16_t* data() const { + return reinterpret_cast<const uint16_t*>(impl_.characters()); + } + + size_t length() const { return impl_.length(); } + + String webcore_string() { return impl_; } + + private: + // A shallow copy of the string. + // Keeps the string buffer alive until the V8 engine garbage collects it. + String impl_; +}; + +String v8StringToWebCoreString(v8::Handle<v8::String> v8_str) { + if (v8_str->IsExternal()) { + WebCoreStringResource* str_resource = static_cast<WebCoreStringResource*>( + v8_str->GetExternalStringResource()); + return str_resource->webcore_string(); + } + + int length = v8_str->Length(); + if (length == 0) { + // Avoid trying to morph empty strings, as they do not have enough room to + // contain the external reference. + return ""; + } + + // Copy the characters from the v8::String into a WebCore::String and allocate + // an external resource which will be attached to the v8::String. + String result; + const int kStringSizeToCopy = 256; + if (length < kStringSizeToCopy) { + uint16_t buffer[kStringSizeToCopy]; + v8_str->Write(buffer, 0, length); + result = StringImpl::create(reinterpret_cast<UChar*>(buffer), length); + } else { + StringBuffer buf(length); + v8_str->Write(reinterpret_cast<uint16_t*>(buf.characters()), 0, length); + result = String::adopt(buf); + } + +// +// TODO(mbelshe): Disable string morphing because it causes mystery +// perf regressions on intl1 and intl2 page cyclers. It works fine +// on machines other than the buildbots. +// +// WebCoreStringResource* resource = new WebCoreStringResource(result); +// if (!v8_str->MakeExternal(resource)) { +// // In case of a failure delete the external resource as it was not used. +// delete resource; +// } + return result; +} + + +String v8ValueToWebCoreString(v8::Handle<v8::Value> obj) { + v8::Handle<v8::String> v8_str; + if (obj->IsString()) { + v8_str = v8::Handle<v8::String>::Cast(obj); + } else { + v8::TryCatch block; + v8_str = obj->ToString(); + if (v8_str.IsEmpty()) + return ""; + } + return v8StringToWebCoreString(v8_str); +} + + +AtomicString v8StringToAtomicWebCoreString(v8::Handle<v8::String> v8_str) { + String str = v8StringToWebCoreString(v8_str); + return AtomicString(str); +} + + +AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> v8_str) { + String str = v8ValueToWebCoreString(v8_str); + return AtomicString(str); +} + + +v8::Handle<v8::String> v8String(const String& str) { + if (!str.length()) + return v8::String::Empty(); + return v8::String::NewExternal(new WebCoreStringResource(str)); +} + +v8::Local<v8::String> v8ExternalString(const String& str) { + if (!str.length()) + return v8::String::Empty(); + return v8::String::NewExternal(new WebCoreStringResource(str)); +} + +} // namespace WebCore diff --git a/V8Binding/v8/v8_binding.h b/V8Binding/v8/v8_binding.h new file mode 100644 index 0000000..8300dd7 --- /dev/null +++ b/V8Binding/v8/v8_binding.h @@ -0,0 +1,130 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BINDING_H__ +#define V8_BINDING_H__ + +#include "config.h" + +#include "MathExtras.h" +#include "PlatformString.h" + +#include <v8.h> + +namespace WebCore { + +// The string returned by this function is still owned by the argument +// and will be deallocated when the argument is deallocated. +inline const uint16_t* FromWebCoreString(const String& str) { + return reinterpret_cast<const uint16_t*>(str.characters()); +} + +// Convert v8 types to a WebCore::String. If the V8 string is not already +// an external string then it is transformed into an external string at this +// point to avoid repeated conversions. +String v8StringToWebCoreString(v8::Handle<v8::String> obj); +String v8ValueToWebCoreString(v8::Handle<v8::Value> obj); + +// TODO(mbelshe): drop this in favor of the type specific +// v8ValueToWebCoreString when we rework the code generation. +inline String ToWebCoreString(v8::Handle<v8::Value> obj) { + return v8ValueToWebCoreString(obj); +} + +// Convert v8 types to a WebCore::AtomicString. +AtomicString v8StringToAtomicWebCoreString(v8::Handle<v8::String> obj); +AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> obj); + +inline String valueToStringWithNullCheck(v8::Handle<v8::Value> value) { + if (value->IsNull()) return String(); + return ToWebCoreString(value); +} + +inline String valueToStringWithNullOrUndefinedCheck( + v8::Handle<v8::Value> value) { + if (value->IsNull() || value->IsUndefined()) return String(); + return ToWebCoreString(value); +} + +// Convert a value to a 32-bit integer. The conversion fails if the +// value cannot be converted to an integer or converts to nan or to an +// infinity. +// FIXME: Rename to toInt32() once V8 bindings migration is complete. +inline int ToInt32(v8::Handle<v8::Value> value, bool& ok) { + ok = true; + + // Fast case. The value is already a 32-bit integer. + if (value->IsInt32()) { + return value->Int32Value(); + } + + // Can the value be converted to a number? + v8::Local<v8::Number> number_object = value->ToNumber(); + if (number_object.IsEmpty()) { + ok = false; + return 0; + } + + // Does the value convert to nan or to an infinity? + double number_value = number_object->Value(); + if (isnan(number_value) || isinf(number_value)) { + ok = false; + return 0; + } + + // Can the value be converted to a 32-bit integer? + v8::Local<v8::Int32> int_value = value->ToInt32(); + if (int_value.IsEmpty()) { + ok = false; + return 0; + } + + // Return the result of the int32 conversion. + return int_value->Value(); +} + +// Convert a value to a 32-bit integer assuming the conversion cannot fail. +// FIXME: Rename to toInt32() once V8 bindings migration is complete. +inline int ToInt32(v8::Handle<v8::Value> value) { + bool ok; + return ToInt32(value, ok); +} + +inline String ToString(const String& string) { + return string; +} + +// Convert a string to a V8 string. +v8::Handle<v8::String> v8String(const String& str); + +inline v8::Handle<v8::String> v8UndetectableString(const String& str) { + return v8::String::NewUndetectable(FromWebCoreString(str), str.length()); +} + +// Return a V8 external string that shares the underlying buffer with the given +// WebCore string. The reference counting mechanism is used to keep the +// underlying buffer alive while the string is still live in the V8 engine. +v8::Local<v8::String> v8ExternalString(const String& str); + +inline v8::Handle<v8::Value> v8StringOrNull(const String& str) { + return str.isNull() + ? v8::Handle<v8::Value>(v8::Null()) + : v8::Handle<v8::Value>(v8String(str)); +} + +inline v8::Handle<v8::Value> v8StringOrUndefined(const String& str) { + return str.isNull() + ? v8::Handle<v8::Value>(v8::Undefined()) + : v8::Handle<v8::Value>(v8String(str)); +} + +inline v8::Handle<v8::Value> v8StringOrFalse(const String& str) { + return str.isNull() + ? v8::Handle<v8::Value>(v8::False()) + : v8::Handle<v8::Value>(v8String(str)); +} + +} // namespace WebCore + +#endif // V8_BINDING_H__ diff --git a/V8Binding/v8/v8_custom.cpp b/V8Binding/v8/v8_custom.cpp new file mode 100644 index 0000000..4b2e545 --- /dev/null +++ b/V8Binding/v8/v8_custom.cpp @@ -0,0 +1,1282 @@ +/* + * 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" +#include "V8XPathNSResolver.h" +#include "V8XPathResult.h" + +#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; +} + + +// Element --------------------------------------------------------------------- + +CALLBACK_FUNC_DECL(ElementSetAttribute) { + INC_STATS("DOM.Element.setAttribute()"); + Element* imp = V8Proxy::DOMWrapperToNode<Element>(args.Holder()); + ExceptionCode ec = 0; + String name = ToWebCoreString(args[0]); + String value = ToWebCoreString(args[1]); + + if (!AllowSettingSrcToJavascriptURL(imp, name, value)) { + return v8::Undefined(); + } + + imp->setAttribute(name, value, ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ElementSetAttributeNode) { + INC_STATS("DOM.Element.setAttributeNode()"); + if (!V8Attr::HasInstance(args[0])) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); + } + + Attr* newAttr = V8Proxy::DOMWrapperToNode<Attr>(args[0]); + Element* imp = V8Proxy::DOMWrapperToNode<Element>(args.Holder()); + ExceptionCode ec = 0; + + if (!AllowSettingSrcToJavascriptURL(imp, newAttr->name(), newAttr->value())) { + return v8::Undefined(); + } + + RefPtr<Attr> result = imp->setAttributeNode(newAttr, ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return V8Proxy::NodeToV8Object(result.get()); +} + +CALLBACK_FUNC_DECL(ElementSetAttributeNS) { + INC_STATS("DOM.Element.setAttributeNS()"); + Element* imp = V8Proxy::DOMWrapperToNode<Element>(args.Holder()); + ExceptionCode ec = 0; + String namespaceURI = valueToStringWithNullCheck(args[0]); + String qualifiedName = ToWebCoreString(args[1]); + String value = ToWebCoreString(args[2]); + + if (!AllowSettingSrcToJavascriptURL(imp, qualifiedName, value)) { + return v8::Undefined(); + } + + imp->setAttributeNS(namespaceURI, qualifiedName, value, ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ElementSetAttributeNodeNS) { + INC_STATS("DOM.Element.setAttributeNodeNS()"); + if (!V8Attr::HasInstance(args[0])) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); + } + + Attr* newAttr = V8Proxy::DOMWrapperToNode<Attr>(args[0]); + Element* imp = V8Proxy::DOMWrapperToNode<Element>(args.Holder()); + ExceptionCode ec = 0; + + if (!AllowSettingSrcToJavascriptURL(imp, newAttr->name(), newAttr->value())) { + return v8::Undefined(); + } + + RefPtr<Attr> result = imp->setAttributeNodeNS(newAttr, ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return V8Proxy::NodeToV8Object(result.get()); +} + + + +// Attr ------------------------------------------------------------------------ + +ACCESSOR_SETTER(AttrValue) { + Attr* imp = + V8Proxy::DOMWrapperToNode<Attr>(info.Holder()); + String v = valueToStringWithNullCheck(value); + Element* ownerElement = imp->ownerElement(); + + if (ownerElement && + !AllowSettingSrcToJavascriptURL(ownerElement, imp->name(), v)) + return; + + ExceptionCode ec = 0; + imp->setValue(v, ec); + V8Proxy::SetDOMException(ec); +} + + +// HTMLFrameElement ------------------------------------------------------------ + +ACCESSOR_SETTER(HTMLFrameElementSrc) { + HTMLFrameElement* imp = + V8Proxy::DOMWrapperToNode<HTMLFrameElement>(info.Holder()); + String v = valueToStringWithNullCheck(value); + + if (!AllowSettingFrameSrcToJavascriptUrl(imp, v)) return; + + imp->setSrc(v); +} + +ACCESSOR_SETTER(HTMLFrameElementLocation) { + HTMLFrameElement* imp = + V8Proxy::DOMWrapperToNode<HTMLFrameElement>(info.Holder()); + String v = valueToStringWithNullCheck(value); + + if (!AllowSettingFrameSrcToJavascriptUrl(imp, v)) return; + + imp->setLocation(v); +} + + +// HTMLIFrameElement ----------------------------------------------------------- + +ACCESSOR_SETTER(HTMLIFrameElementSrc) { + HTMLIFrameElement* imp = + V8Proxy::DOMWrapperToNode<HTMLIFrameElement>(info.Holder()); + String v = valueToStringWithNullCheck(value); + + if (!AllowSettingFrameSrcToJavascriptUrl(imp, v)) return; + + imp->setSrc(v); +} + + +// 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); +} + + +ACCESSOR_SETTER(ElementEventHandler) { + Node* node = V8Proxy::DOMWrapperToNode<Node>(info.Holder()); + + // Name starts with 'on', remove them. + String key = ToWebCoreString(name); + ASSERT(key.startsWith("on")); + String event_type = key.substring(2); + + // Set handler if the value is a function. Otherwise, clear the + // event handler. + if (value->IsFunction()) { + V8Proxy* proxy = V8Proxy::retrieve(node->document()->frame()); + // the document might be created using createDocument, + // which does not have a frame, use the active frame + if (!proxy) + proxy = V8Proxy::retrieve(V8Proxy::retrieveActiveFrame()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateV8EventListener(value, true); + if (listener) { + node->setInlineEventListenerForType(event_type, listener); + } + } else { + node->removeInlineEventListenerForType(event_type); + } +} + + +ACCESSOR_GETTER(ElementEventHandler) { + Node* node = V8Proxy::DOMWrapperToNode<Node>(info.Holder()); + + // Name starts with 'on', remove them. + String key = ToWebCoreString(name); + ASSERT(key.startsWith("on")); + String event_type = key.substring(2); + + EventListener* listener = node->inlineEventListenerForType(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 diff --git a/V8Binding/v8/v8_custom.h b/V8Binding/v8/v8_custom.h new file mode 100644 index 0000000..a891e2e --- /dev/null +++ b/V8Binding/v8/v8_custom.h @@ -0,0 +1,545 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CUSTOM_H__ +#define V8_CUSTOM_H__ + +#include <v8.h> +#include "v8_index.h" + +struct NPObject; + +#define CALLBACK_FUNC_DECL(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##Callback(const v8::Arguments& args) + +#define ACCESSOR_GETTER(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##AccessorGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info) + +#define ACCESSOR_SETTER(NAME) \ +void V8Custom::v8##NAME##AccessorSetter(v8::Local<v8::String> name, \ + v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info) + +#define INDEXED_PROPERTY_GETTER(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##IndexedPropertyGetter(\ + uint32_t index, const v8::AccessorInfo& info) + +#define INDEXED_PROPERTY_SETTER(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##IndexedPropertySetter(\ + uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info) + +#define INDEXED_PROPERTY_DELETER(NAME) \ +v8::Handle<v8::Boolean> V8Custom::v8##NAME##IndexedPropertyDeleter(\ + uint32_t index, const v8::AccessorInfo& info) + +#define NAMED_PROPERTY_GETTER(NAME) \ + v8::Handle<v8::Value> V8Custom::v8##NAME##NamedPropertyGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info) + +#define NAMED_PROPERTY_SETTER(NAME) \ + v8::Handle<v8::Value> V8Custom::v8##NAME##NamedPropertySetter(\ + v8::Local<v8::String> name, v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info) + +#define NAMED_PROPERTY_DELETER(NAME) \ + v8::Handle<v8::Boolean> V8Custom::v8##NAME##NamedPropertyDeleter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info) + +#define NAMED_ACCESS_CHECK(NAME) \ + bool V8Custom::v8##NAME##NamedSecurityCheck(v8::Local<v8::Object> host, \ + v8::Local<v8::Value> key, \ + v8::AccessType type, \ + v8::Local<v8::Value> data) + +#define INDEXED_ACCESS_CHECK(NAME) \ + bool V8Custom::v8##NAME##IndexedSecurityCheck(v8::Local<v8::Object> host, \ + uint32_t index, \ + v8::AccessType type, \ + v8::Local<v8::Value> data) + +namespace WebCore { + +class Frame; +class V8Proxy; +class String; +class HTMLCollection; +class DOMWindow; + +class V8Custom { + public: + + // Constants. + static const int kDOMWrapperTypeIndex = 0; + static const int kDOMWrapperObjectIndex = 1; + static const int kDefaultWrapperInternalFieldCount = 2; + + static const int kNPObjectInternalFieldCount = + kDefaultWrapperInternalFieldCount + 0; + + static const int kDocumentImplementationIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kDocumentMinimumInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; + + static const int kHTMLDocumentMarkerIndex = + kDocumentMinimumInternalFieldCount + 0; + static const int kHTMLDocumentShadowIndex = + kDocumentMinimumInternalFieldCount + 1; + static const int kHTMLDocumentInternalFieldCount = + kDocumentMinimumInternalFieldCount + 2; + + static const int kXMLHttpRequestCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kXMLHttpRequestInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; + + static const int kMessageChannelPort1Index = + kDefaultWrapperInternalFieldCount + 0; + static const int kMessageChannelPort2Index = + kDefaultWrapperInternalFieldCount + 1; + static const int kMessageChannelInternalFieldCount = + kDefaultWrapperInternalFieldCount + 2; + + static const int kMessagePortRequestCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kMessagePortEntangledPortIndex = + kDefaultWrapperInternalFieldCount + 1; + static const int kMessagePortInternalFieldCount = + kDefaultWrapperInternalFieldCount + 2; + +#if ENABLE(WORKERS) + static const int kWorkerRequestCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kWorkerInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; + + static const int kWorkerContextRequestCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kWorkerContextInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; +#endif + + static const int kDOMWindowHistoryIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kDOMWindowNavigatorIndex = + kDefaultWrapperInternalFieldCount + 1; + static const int kDOMWindowLocationIndex = + kDefaultWrapperInternalFieldCount + 2; + static const int kDOMWindowInternalFieldCount = + kDefaultWrapperInternalFieldCount + 3; + + static const int kStyleSheetOwnerNodeIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kStyleSheetInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; + +#define DECLARE_PROPERTY_ACCESSOR_GETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##AccessorGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info); + +#define DECLARE_PROPERTY_ACCESSOR_SETTER(NAME) \ +static void v8##NAME##AccessorSetter(v8::Local<v8::String> name, \ + v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info); + +#define DECLARE_PROPERTY_ACCESSOR(NAME) \ + DECLARE_PROPERTY_ACCESSOR_GETTER(NAME) \ + DECLARE_PROPERTY_ACCESSOR_SETTER(NAME) + + +#define DECLARE_NAMED_PROPERTY_GETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##NamedPropertyGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info); + +#define DECLARE_NAMED_PROPERTY_SETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##NamedPropertySetter(\ + v8::Local<v8::String> name, \ + v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info); + +#define DECLARE_NAMED_PROPERTY_DELETER(NAME) \ +static v8::Handle<v8::Boolean> v8##NAME##NamedPropertyDeleter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info); + +#define USE_NAMED_PROPERTY_GETTER(NAME) \ + V8Custom::v8##NAME##NamedPropertyGetter + +#define USE_NAMED_PROPERTY_SETTER(NAME) \ + V8Custom::v8##NAME##NamedPropertySetter + +#define USE_NAMED_PROPERTY_DELETER(NAME) \ + V8Custom::v8##NAME##NamedPropertyDeleter + +#define DECLARE_INDEXED_PROPERTY_GETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##IndexedPropertyGetter(\ + uint32_t index, const v8::AccessorInfo& info); + +#define DECLARE_INDEXED_PROPERTY_SETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##IndexedPropertySetter(\ + uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info); + +#define DECLARE_INDEXED_PROPERTY_DELETER(NAME) \ +static v8::Handle<v8::Boolean> v8##NAME##IndexedPropertyDeleter(\ + uint32_t index, const v8::AccessorInfo& info); + +#define USE_INDEXED_PROPERTY_GETTER(NAME) \ + V8Custom::v8##NAME##IndexedPropertyGetter + +#define USE_INDEXED_PROPERTY_SETTER(NAME) \ + V8Custom::v8##NAME##IndexedPropertySetter + +#define USE_INDEXED_PROPERTY_DELETER(NAME) \ + V8Custom::v8##NAME##IndexedPropertyDeleter + +#define DECLARE_CALLBACK(NAME) \ +static v8::Handle<v8::Value> v8##NAME##Callback(const v8::Arguments& args); + +#define USE_CALLBACK(NAME) \ + V8Custom::v8##NAME##Callback + +#define DECLARE_NAMED_ACCESS_CHECK(NAME) \ +static bool v8##NAME##NamedSecurityCheck(v8::Local<v8::Object> host, \ + v8::Local<v8::Value> key, \ + v8::AccessType type, \ + v8::Local<v8::Value> data); + +#define DECLARE_INDEXED_ACCESS_CHECK(NAME) \ +static bool v8##NAME##IndexedSecurityCheck(v8::Local<v8::Object> host, \ + uint32_t index, \ + v8::AccessType type, \ + v8::Local<v8::Value> data); + +DECLARE_PROPERTY_ACCESSOR(CanvasRenderingContext2DStrokeStyle) +DECLARE_PROPERTY_ACCESSOR(CanvasRenderingContext2DFillStyle) +// Customized getter&setter of DOMWindow.location +DECLARE_PROPERTY_ACCESSOR_SETTER(DOMWindowLocation) +// Customized setter of DOMWindow.opener +DECLARE_PROPERTY_ACCESSOR_SETTER(DOMWindowOpener) + +DECLARE_PROPERTY_ACCESSOR(DocumentLocation) +DECLARE_PROPERTY_ACCESSOR(DocumentImplementation) +DECLARE_PROPERTY_ACCESSOR_GETTER(EventSrcElement) +DECLARE_PROPERTY_ACCESSOR(EventReturnValue) +DECLARE_PROPERTY_ACCESSOR_GETTER(EventDataTransfer) +DECLARE_PROPERTY_ACCESSOR_GETTER(EventClipboardData) + +// Getter/Setter for window event handlers +DECLARE_PROPERTY_ACCESSOR(DOMWindowEventHandler) +// Getter/Setter for Element event handlers +DECLARE_PROPERTY_ACCESSOR(ElementEventHandler) + +// HTMLCanvasElement +DECLARE_CALLBACK(HTMLCanvasElementGetContext) + +// Customized setter of src and location on HTMLFrameElement +DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLFrameElementSrc) +DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLFrameElementLocation) +// Customized setter of src on HTMLIFrameElement +DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLIFrameElementSrc) +// Customized setter of Attr.value +DECLARE_PROPERTY_ACCESSOR_SETTER(AttrValue) + +// Customized setter of HTMLOptionsCollection length +DECLARE_PROPERTY_ACCESSOR(HTMLOptionsCollectionLength) + +DECLARE_CALLBACK(HTMLInputElementSetSelectionRange) + +// Customized accessors for HTMLInputElement +DECLARE_PROPERTY_ACCESSOR(HTMLInputElementSelectionStart) +DECLARE_PROPERTY_ACCESSOR(HTMLInputElementSelectionEnd) + +DECLARE_NAMED_ACCESS_CHECK(Location) +DECLARE_INDEXED_ACCESS_CHECK(History) + +DECLARE_NAMED_ACCESS_CHECK(History) +DECLARE_INDEXED_ACCESS_CHECK(Location) + +// HTMLCollection customized functions. +DECLARE_CALLBACK(HTMLCollectionItem) +DECLARE_CALLBACK(HTMLCollectionNamedItem) +// HTMLCollections are callable as functions. +DECLARE_CALLBACK(HTMLCollectionCallAsFunction) + +// HTMLSelectElement customized functions. +DECLARE_CALLBACK(HTMLSelectElementRemove) + +// HTMLOptionsCollection customized functions. +DECLARE_CALLBACK(HTMLOptionsCollectionRemove) +DECLARE_CALLBACK(HTMLOptionsCollectionAdd) + +// HTMLDocument customized functions +DECLARE_CALLBACK(HTMLDocumentWrite) +DECLARE_CALLBACK(HTMLDocumentWriteln) +DECLARE_CALLBACK(HTMLDocumentOpen) +DECLARE_PROPERTY_ACCESSOR(HTMLDocumentAll) +DECLARE_NAMED_PROPERTY_GETTER(HTMLDocument) +DECLARE_NAMED_PROPERTY_DELETER(HTMLDocument) + +// Document customized functions +DECLARE_CALLBACK(DocumentEvaluate) +DECLARE_CALLBACK(DocumentGetCSSCanvasContext) + +// Window customized functions +DECLARE_CALLBACK(DOMWindowAddEventListener) +DECLARE_CALLBACK(DOMWindowRemoveEventListener) +DECLARE_CALLBACK(DOMWindowPostMessage) +DECLARE_CALLBACK(DOMWindowSetTimeout) +DECLARE_CALLBACK(DOMWindowSetInterval) +DECLARE_CALLBACK(DOMWindowAtob) +DECLARE_CALLBACK(DOMWindowBtoa) +DECLARE_CALLBACK(DOMWindowNOP) +DECLARE_CALLBACK(DOMWindowToString) +DECLARE_CALLBACK(DOMWindowShowModalDialog) +DECLARE_CALLBACK(DOMWindowOpen) +DECLARE_CALLBACK(DOMWindowClearTimeout) +DECLARE_CALLBACK(DOMWindowClearInterval) + +DECLARE_CALLBACK(DOMParserConstructor) +DECLARE_CALLBACK(MessageChannelConstructor) +DECLARE_CALLBACK(WebKitCSSMatrixConstructor) +DECLARE_CALLBACK(WebKitPointConstructor) +DECLARE_CALLBACK(XMLHttpRequestConstructor) +DECLARE_CALLBACK(XMLSerializerConstructor) +DECLARE_CALLBACK(XPathEvaluatorConstructor) +DECLARE_CALLBACK(XSLTProcessorConstructor) + +// Implementation of custom XSLTProcessor methods. +DECLARE_CALLBACK(XSLTProcessorImportStylesheet) +DECLARE_CALLBACK(XSLTProcessorTransformToFragment) +DECLARE_CALLBACK(XSLTProcessorTransformToDocument) +DECLARE_CALLBACK(XSLTProcessorSetParameter) +DECLARE_CALLBACK(XSLTProcessorGetParameter) +DECLARE_CALLBACK(XSLTProcessorRemoveParameter) + +// CSSPrimitiveValue customized functions +DECLARE_CALLBACK(CSSPrimitiveValueGetRGBColorValue) + +// Canvas 2D customized functions +DECLARE_CALLBACK(CanvasRenderingContext2DSetStrokeColor) +DECLARE_CALLBACK(CanvasRenderingContext2DSetFillColor) +DECLARE_CALLBACK(CanvasRenderingContext2DStrokeRect) +DECLARE_CALLBACK(CanvasRenderingContext2DSetShadow) +DECLARE_CALLBACK(CanvasRenderingContext2DDrawImage) +DECLARE_CALLBACK(CanvasRenderingContext2DDrawImageFromRect) +DECLARE_CALLBACK(CanvasRenderingContext2DCreatePattern) +DECLARE_CALLBACK(CanvasRenderingContext2DFillText) +DECLARE_CALLBACK(CanvasRenderingContext2DStrokeText) +DECLARE_CALLBACK(CanvasRenderingContext2DPutImageData) + +// Implementation of Clipboard attributes and methods. +DECLARE_PROPERTY_ACCESSOR_GETTER(ClipboardTypes) +DECLARE_CALLBACK(ClipboardClearData) +DECLARE_CALLBACK(ClipboardGetData) +DECLARE_CALLBACK(ClipboardSetData) +DECLARE_CALLBACK(ClipboardSetDragImage); + +// Implementation of Element methods. +DECLARE_CALLBACK(ElementQuerySelector) +DECLARE_CALLBACK(ElementQuerySelectorAll) +DECLARE_CALLBACK(ElementSetAttribute) +DECLARE_CALLBACK(ElementSetAttributeNode) +DECLARE_CALLBACK(ElementSetAttributeNS) +DECLARE_CALLBACK(ElementSetAttributeNodeNS) + +// Implementation of custom Location methods. +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationProtocol) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationHost) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationHostname) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationPort) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationPathname) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationSearch) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationHash) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationHref) +DECLARE_PROPERTY_ACCESSOR_GETTER(LocationAssign) +DECLARE_PROPERTY_ACCESSOR_GETTER(LocationReplace) +DECLARE_PROPERTY_ACCESSOR_GETTER(LocationReload) +DECLARE_CALLBACK(LocationAssign) +DECLARE_CALLBACK(LocationReplace) +DECLARE_CALLBACK(LocationReload) +DECLARE_CALLBACK(LocationToString) +DECLARE_CALLBACK(LocationValueOf) + +// Implementation of EventTarget::addEventListener +// and EventTarget::removeEventListener +DECLARE_CALLBACK(NodeAddEventListener) +DECLARE_CALLBACK(NodeRemoveEventListener) + +// Custom implementation is Navigator properties. +// We actually only need this because WebKit has +// navigator.appVersion as custom. Our version just +// passes through. +DECLARE_PROPERTY_ACCESSOR(NavigatorAppVersion) + +// Custom implementation of XMLHttpRequest properties +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnabort) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnerror) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnload) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnloadstart) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnprogress) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnreadystatechange) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestResponseText) +DECLARE_CALLBACK(XMLHttpRequestAddEventListener) +DECLARE_CALLBACK(XMLHttpRequestRemoveEventListener) +DECLARE_CALLBACK(XMLHttpRequestOpen) +DECLARE_CALLBACK(XMLHttpRequestSend) +DECLARE_CALLBACK(XMLHttpRequestSetRequestHeader) +DECLARE_CALLBACK(XMLHttpRequestGetResponseHeader) +DECLARE_CALLBACK(XMLHttpRequestOverrideMimeType) +DECLARE_CALLBACK(XMLHttpRequestDispatchEvent) + +// Custom implementation of XMLHttpRequestUpload properties +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnabort) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnerror) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnload) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnloadstart) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnprogress) +DECLARE_CALLBACK(XMLHttpRequestUploadAddEventListener) +DECLARE_CALLBACK(XMLHttpRequestUploadRemoveEventListener) +DECLARE_CALLBACK(XMLHttpRequestUploadDispatchEvent) + +// Custom implementation of TreeWalker functions +DECLARE_CALLBACK(TreeWalkerParentNode) +DECLARE_CALLBACK(TreeWalkerFirstChild) +DECLARE_CALLBACK(TreeWalkerLastChild) +DECLARE_CALLBACK(TreeWalkerNextNode) +DECLARE_CALLBACK(TreeWalkerPreviousNode) +DECLARE_CALLBACK(TreeWalkerNextSibling) +DECLARE_CALLBACK(TreeWalkerPreviousSibling) + +// Custom implementation of InspectorController functions +DECLARE_CALLBACK(InspectorControllerDebuggerEnabled) +DECLARE_CALLBACK(InspectorControllerPauseOnExceptions) +DECLARE_CALLBACK(InspectorControllerProfilerEnabled) +#if ENABLE(DATABASE) +DECLARE_CALLBACK(InspectorControllerDatabaseTableNames) +#endif +DECLARE_CALLBACK(InspectorControllerWrapCallback) + +// Custom implementation of NodeIterator functions +DECLARE_CALLBACK(NodeIteratorNextNode) +DECLARE_CALLBACK(NodeIteratorPreviousNode) + +// Custom implementation of NodeFilter function +DECLARE_CALLBACK(NodeFilterAcceptNode) + +// Custom implementation of HTMLFormElement +DECLARE_CALLBACK(HTMLFormElementSubmit) + +DECLARE_INDEXED_PROPERTY_GETTER(DOMStringList) +DECLARE_CALLBACK(DOMStringListItem) + +DECLARE_NAMED_PROPERTY_GETTER(DOMWindow) +DECLARE_INDEXED_PROPERTY_GETTER(DOMWindow) +DECLARE_NAMED_ACCESS_CHECK(DOMWindow) +DECLARE_INDEXED_ACCESS_CHECK(DOMWindow) + +DECLARE_NAMED_PROPERTY_GETTER(HTMLFrameSetElement) +DECLARE_NAMED_PROPERTY_GETTER(HTMLFormElement) +DECLARE_NAMED_PROPERTY_GETTER(NodeList) +DECLARE_NAMED_PROPERTY_GETTER(NamedNodeMap) +DECLARE_NAMED_PROPERTY_GETTER(CSSStyleDeclaration) +DECLARE_NAMED_PROPERTY_SETTER(CSSStyleDeclaration) +DECLARE_NAMED_PROPERTY_GETTER(HTMLPlugInElement) +DECLARE_NAMED_PROPERTY_SETTER(HTMLPlugInElement) +DECLARE_INDEXED_PROPERTY_GETTER(HTMLPlugInElement) +DECLARE_INDEXED_PROPERTY_SETTER(HTMLPlugInElement) + +// Plugin object can be called as function. +DECLARE_CALLBACK(HTMLPlugInElement) + +DECLARE_NAMED_PROPERTY_GETTER(StyleSheetList) +DECLARE_INDEXED_PROPERTY_GETTER(NamedNodeMap) +DECLARE_INDEXED_PROPERTY_GETTER(HTMLFormElement) +DECLARE_INDEXED_PROPERTY_GETTER(HTMLOptionsCollection) +DECLARE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection) +DECLARE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection) +DECLARE_NAMED_PROPERTY_GETTER(HTMLCollection) + +// Canvas and supporting classes +DECLARE_INDEXED_PROPERTY_GETTER(CanvasPixelArray) +DECLARE_INDEXED_PROPERTY_SETTER(CanvasPixelArray) + +// MessagePort +DECLARE_PROPERTY_ACCESSOR(MessagePortOnmessage) +DECLARE_PROPERTY_ACCESSOR(MessagePortOnclose) +DECLARE_CALLBACK(MessagePortStartConversation) +DECLARE_CALLBACK(MessagePortAddEventListener) +DECLARE_CALLBACK(MessagePortRemoveEventListener) + +// Database +DECLARE_CALLBACK(DatabaseChangeVersion) +DECLARE_CALLBACK(DatabaseTransaction) +DECLARE_CALLBACK(SQLTransactionExecuteSql) +DECLARE_CALLBACK(SQLResultSetRowListItem) + +// SVG custom properties and callbacks +#if ENABLE(SVG) +DECLARE_PROPERTY_ACCESSOR_GETTER(SVGLengthValue) +DECLARE_CALLBACK(SVGLengthConvertToSpecifiedUnits) +DECLARE_CALLBACK(SVGMatrixInverse) +DECLARE_CALLBACK(SVGMatrixRotateFromVector) +DECLARE_CALLBACK(SVGElementInstanceAddEventListener) +DECLARE_CALLBACK(SVGElementInstanceRemoveEventListener) +#endif + +// Worker +#if ENABLE(WORKERS) +DECLARE_PROPERTY_ACCESSOR(WorkerOnmessage) +DECLARE_PROPERTY_ACCESSOR(WorkerOnerror) +DECLARE_CALLBACK(WorkerConstructor) +DECLARE_CALLBACK(WorkerAddEventListener) +DECLARE_CALLBACK(WorkerRemoveEventListener) + +DECLARE_PROPERTY_ACCESSOR_GETTER(WorkerContextSelf) +DECLARE_PROPERTY_ACCESSOR(WorkerContextOnmessage) +DECLARE_CALLBACK(WorkerContextImportScripts) +DECLARE_CALLBACK(WorkerContextSetTimeout) +DECLARE_CALLBACK(WorkerContextClearTimeout) +DECLARE_CALLBACK(WorkerContextSetInterval) +DECLARE_CALLBACK(WorkerContextClearInterval) +DECLARE_CALLBACK(WorkerContextAddEventListener) +DECLARE_CALLBACK(WorkerContextRemoveEventListener) +#endif + +#undef DECLARE_INDEXED_ACCESS_CHECK +#undef DECLARE_NAMED_ACCESS_CHECK + +#undef DECLARE_PROPERTY_ACCESSOR_SETTER +#undef DECLARE_PROPERTY_ACCESSOR_GETTER +#undef DECLARE_PROPERTY_ACCESSOR + +#undef DECLARE_NAMED_PROPERTY_GETTER +#undef DECLARE_NAMED_PROPERTY_SETTER +#undef DECLARE_NAMED_PROPERTY_DELETER + +#undef DECLARE_INDEXED_PROPERTY_GETTER +#undef DECLARE_INDEXED_PROPERTY_SETTER +#undef DECLARE_INDEXED_PROPERTY_DELETER + +#undef DECLARE_CALLBACK + + // Returns the NPObject corresponding to an HTMLElement object. + static NPObject* GetHTMLPlugInElementNPObject(v8::Handle<v8::Object> object); + + // Returns the owner frame pointer of a DOM wrapper object. It only works for + // these DOM objects requiring cross-domain access check. + static Frame* GetTargetFrame(v8::Local<v8::Object> host, + v8::Local<v8::Value> data); + + // Special case for downcasting SVG path segments +#if ENABLE(SVG) + static V8ClassIndex::V8WrapperType DowncastSVGPathSeg(void* path_seg); +#endif + + private: + static v8::Handle<v8::Value> WindowSetTimeoutImpl(const v8::Arguments& args, + bool single_shot); + static void ClearTimeoutImpl(const v8::Arguments& args); + static void WindowSetLocation(DOMWindow*, const String&); +}; + +} // namespace WebCore + +#endif // V8_CUSTOM_H__ diff --git a/V8Binding/v8/v8_helpers.cpp b/V8Binding/v8/v8_helpers.cpp new file mode 100644 index 0000000..7a72ab5 --- /dev/null +++ b/V8Binding/v8/v8_helpers.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#define max max +#define min min +#include "v8_helpers.h" +#include "v8_proxy.h" +#include "v8_index.h" +#include "NPV8Object.h" + +#include "DOMWindow.h" + +using WebCore::V8Custom; + +void WrapNPObject(v8::Handle<v8::Object> obj, NPObject* npobj) +{ + WebCore::V8Proxy::SetDOMWrapper(obj, WebCore::V8ClassIndex::NPOBJECT, npobj); +} + +v8::Local<v8::Context> getV8Context(NPP npp, NPObject* npobj) +{ + V8NPObject* object = reinterpret_cast<V8NPObject*>(npobj); + return WebCore::V8Proxy::GetContext(object->rootObject->frame()); +} + +WebCore::V8Proxy* GetV8Proxy(NPObject* npobj) +{ + V8NPObject* object = reinterpret_cast<V8NPObject*>(npobj); + WebCore::Frame* frame = object->rootObject->frame(); + return WebCore::V8Proxy::retrieve(frame); +} diff --git a/V8Binding/v8/v8_helpers.h b/V8Binding/v8/v8_helpers.h new file mode 100644 index 0000000..eebdd1e --- /dev/null +++ b/V8Binding/v8/v8_helpers.h @@ -0,0 +1,24 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_HELPERS_H__ +#define V8_HELPERS_H__ + +#include "third_party/npapi/bindings/npruntime.h" +#include <v8.h> + +namespace WebCore { + class V8Proxy; +} + +// Associates an NPObject with a V8 object. +void WrapNPObject(v8::Handle<v8::Object> obj, NPObject *npobj); + +// Retrieves the V8 Context from the NP context pr obj (at most 1 may be NULL). +v8::Local<v8::Context> getV8Context(NPP npp, NPObject* npobj); + +// Get V8Proxy object from an NPObject. +WebCore::V8Proxy* GetV8Proxy(NPObject* npobj); + +#endif // V8_HELPERS_H__ diff --git a/V8Binding/v8/v8_index.cpp b/V8Binding/v8/v8_index.cpp new file mode 100644 index 0000000..60757b6 --- /dev/null +++ b/V8Binding/v8/v8_index.cpp @@ -0,0 +1,403 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "v8_index.h" + +// TODO: Can we use a macro to include necessary headers by using +// WRAPPER_TYPES? +#include "V8Attr.h" +#include "V8BarInfo.h" +#include "V8CanvasRenderingContext2D.h" +#include "V8CanvasGradient.h" +#include "V8CanvasPattern.h" +#include "V8CanvasPixelArray.h" +#include "V8CDATASection.h" +#include "V8CharacterData.h" +#include "V8ClientRect.h" +#include "V8ClientRectList.h" +#include "V8Clipboard.h" +#include "V8Comment.h" +#include "V8Console.h" +#include "V8Counter.h" +#include "V8CSSStyleDeclaration.h" +#include "V8CSSRule.h" +#include "V8CSSStyleRule.h" +#include "V8CSSCharsetRule.h" +#include "V8CSSImportRule.h" +#include "V8CSSMediaRule.h" +#include "V8CSSFontFaceRule.h" +#include "V8CSSPageRule.h" +#include "V8CSSRuleList.h" +#include "V8CSSPrimitiveValue.h" +#include "V8CSSValue.h" +#include "V8CSSValueList.h" +#include "V8CSSStyleSheet.h" +#include "V8CSSVariablesDeclaration.h" +#include "V8CSSVariablesRule.h" +#include "V8Database.h" +#include "V8Document.h" +#include "V8DocumentFragment.h" +#include "V8DocumentType.h" +#include "V8Element.h" +#include "V8Entity.h" +#include "V8EntityReference.h" +#include "V8File.h" +#include "V8FileList.h" +#include "V8History.h" +#include "V8HTMLCanvasElement.h" +#include "V8UndetectableHTMLCollection.h" +#include "V8HTMLCollection.h" +#include "V8HTMLDocument.h" +#include "V8HTMLElement.h" +#include "V8HTMLOptionsCollection.h" +#include "V8HTMLAnchorElement.h" +#include "V8HTMLAppletElement.h" +#include "V8HTMLAreaElement.h" +#include "V8HTMLBaseElement.h" +#include "V8HTMLBaseFontElement.h" +#include "V8HTMLBlockquoteElement.h" +#include "V8HTMLBodyElement.h" +#include "V8HTMLBRElement.h" +#include "V8HTMLButtonElement.h" +#include "V8HTMLCanvasElement.h" +#include "V8HTMLModElement.h" +#include "V8HTMLDirectoryElement.h" +#include "V8HTMLDivElement.h" +#include "V8HTMLDListElement.h" +#include "V8HTMLEmbedElement.h" +#include "V8HTMLFieldSetElement.h" +#include "V8HTMLFormElement.h" +#include "V8HTMLFontElement.h" +#include "V8HTMLFrameElement.h" +#include "V8HTMLFrameSetElement.h" +#include "V8HTMLHeadingElement.h" +#include "V8HTMLHeadElement.h" +#include "V8HTMLHRElement.h" +#include "V8HTMLHtmlElement.h" +#include "V8HTMLIFrameElement.h" +#include "V8HTMLImageElement.h" +#include "V8HTMLInputElement.h" +#include "V8HTMLIsIndexElement.h" +#include "V8HTMLLabelElement.h" +#include "V8HTMLLegendElement.h" +#include "V8HTMLLIElement.h" +#include "V8HTMLLinkElement.h" +#include "V8HTMLMapElement.h" +#include "V8HTMLMarqueeElement.h" +#include "V8HTMLMenuElement.h" +#include "V8HTMLMetaElement.h" +#include "V8HTMLObjectElement.h" +#include "V8HTMLOListElement.h" +#include "V8HTMLOptGroupElement.h" +#include "V8HTMLOptionElement.h" +#include "V8HTMLParagraphElement.h" +#include "V8HTMLParamElement.h" +#include "V8HTMLPreElement.h" +#include "V8HTMLQuoteElement.h" +#include "V8HTMLScriptElement.h" +#include "V8HTMLSelectElement.h" +#include "V8HTMLStyleElement.h" +#include "V8HTMLTableCaptionElement.h" +#include "V8HTMLTableColElement.h" +#include "V8HTMLTableElement.h" +#include "V8HTMLTableSectionElement.h" +#include "V8HTMLTableCellElement.h" +#include "V8HTMLTableRowElement.h" +#include "V8HTMLTextAreaElement.h" +#include "V8HTMLTitleElement.h" +#include "V8HTMLUListElement.h" +#include "V8ImageData.h" +#include "V8InspectorController.h" +#include "V8MediaList.h" +#include "V8MessageChannel.h" +#include "V8MessageEvent.h" +#include "V8MessagePort.h" +#include "V8NamedNodeMap.h" +#include "V8Node.h" +#include "V8NodeList.h" +#include "V8NodeFilter.h" +#include "V8Notation.h" +#include "V8ProcessingInstruction.h" +#include "V8ProgressEvent.h" +#include "V8StyleSheet.h" +#include "V8Text.h" +#include "V8TextEvent.h" +#include "V8DOMCoreException.h" +#include "V8DOMParser.h" +#include "V8DOMStringList.h" +#include "V8DOMWindow.h" +#include "V8Event.h" +#include "V8EventException.h" +#include "V8KeyboardEvent.h" +#include "V8MouseEvent.h" +#include "V8WebKitAnimationEvent.h" +#include "V8WebKitCSSKeyframeRule.h" +#include "V8WebKitCSSKeyframesRule.h" +#include "V8WebKitCSSMatrix.h" +#include "V8WebKitCSSTransformValue.h" +#include "V8WebKitPoint.h" +#include "V8WebKitTransitionEvent.h" +#include "V8WheelEvent.h" +#include "V8UIEvent.h" +#include "V8MutationEvent.h" +#include "V8OverflowEvent.h" +#include "V8Location.h" +#include "V8Screen.h" +#include "V8DOMSelection.h" +#include "V8Navigator.h" +#include "V8MimeType.h" +#include "V8MimeTypeArray.h" +#include "V8Plugin.h" +#include "V8PluginArray.h" +#include "V8Range.h" +#include "V8RangeException.h" +#include "V8Rect.h" +#include "V8SQLError.h" +#include "V8SQLResultSet.h" +#include "V8SQLResultSetRowList.h" +#include "V8SQLTransaction.h" +#include "V8NodeIterator.h" +#include "V8TextMetrics.h" +#include "V8TreeWalker.h" +#include "V8StyleSheetList.h" +#include "V8DOMImplementation.h" +#include "V8XPathResult.h" +#include "V8XPathException.h" +#include "V8XPathExpression.h" +#include "V8XPathNSResolver.h" +#include "V8XMLHttpRequest.h" +#include "V8XMLHttpRequestException.h" +#include "V8XMLHttpRequestProgressEvent.h" +#include "V8XMLHttpRequestUpload.h" +#include "V8XMLSerializer.h" +#include "V8XPathEvaluator.h" +#include "V8XSLTProcessor.h" +#include "V8RGBColor.h" + +#if ENABLE(SVG_ANIMATION) +#include "V8SVGAnimateColorElement.h" +#include "V8SVGAnimateElement.h" +#include "V8SVGAnimateTransformElement.h" +#include "V8SVGAnimationElement.h" +#include "V8SVGSetElement.h" +#endif + +#if ENABLE(SVG_FILTERS) +#include "V8SVGComponentTransferFunctionElement.h" +#include "V8SVGFEBlendElement.h" +#include "V8SVGFEColorMatrixElement.h" +#include "V8SVGFEComponentTransferElement.h" +#include "V8SVGFECompositeElement.h" +#include "V8SVGFEDiffuseLightingElement.h" +#include "V8SVGFEDisplacementMapElement.h" +#include "V8SVGFEDistantLightElement.h" +#include "V8SVGFEFloodElement.h" +#include "V8SVGFEFuncAElement.h" +#include "V8SVGFEFuncBElement.h" +#include "V8SVGFEFuncGElement.h" +#include "V8SVGFEFuncRElement.h" +#include "V8SVGFEGaussianBlurElement.h" +#include "V8SVGFEImageElement.h" +#include "V8SVGFEMergeElement.h" +#include "V8SVGFEMergeNodeElement.h" +#include "V8SVGFEOffsetElement.h" +#include "V8SVGFEPointLightElement.h" +#include "V8SVGFESpecularLightingElement.h" +#include "V8SVGFESpotLightElement.h" +#include "V8SVGFETileElement.h" +#include "V8SVGFETurbulenceElement.h" +#include "V8SVGFilterElement.h" +#endif + +#if ENABLE(SVG_FONTS) +#include "V8SVGDefinitionSrcElement.h" +#include "V8SVGFontFaceElement.h" +#include "V8SVGFontFaceFormatElement.h" +#include "V8SVGFontFaceNameElement.h" +#include "V8SVGFontFaceSrcElement.h" +#include "V8SVGFontFaceUriElement.h" +#endif + +#if ENABLE(SVG_FOREIGN_OBJECT) +#include "V8SVGForeignObjectElement.h" +#endif + +#if ENABLE(SVG_USE) +#include "V8SVGUseElement.h" +#endif + +#if ENABLE(SVG) +#include "V8SVGAElement.h" +#include "V8SVGAltGlyphElement.h" +#include "V8SVGCircleElement.h" +#include "V8SVGClipPathElement.h" +#include "V8SVGCursorElement.h" +#include "V8SVGDefsElement.h" +#include "V8SVGDescElement.h" +#include "V8SVGElement.h" +#include "V8SVGEllipseElement.h" +#include "V8SVGException.h" +#include "V8SVGGElement.h" +#include "V8SVGGlyphElement.h" +#include "V8SVGGradientElement.h" +#include "V8SVGImageElement.h" +#include "V8SVGLinearGradientElement.h" +#include "V8SVGLineElement.h" +#include "V8SVGMarkerElement.h" +#include "V8SVGMaskElement.h" +#include "V8SVGMetadataElement.h" +#include "V8SVGPathElement.h" +#include "V8SVGPatternElement.h" +#include "V8SVGPolygonElement.h" +#include "V8SVGPolylineElement.h" +#include "V8SVGRadialGradientElement.h" +#include "V8SVGRectElement.h" +#include "V8SVGScriptElement.h" +#include "V8SVGStopElement.h" +#include "V8SVGStyleElement.h" +#include "V8SVGSVGElement.h" +#include "V8SVGSwitchElement.h" +#include "V8SVGSymbolElement.h" +#include "V8SVGTextContentElement.h" +#include "V8SVGTextElement.h" +#include "V8SVGTextPathElement.h" +#include "V8SVGTextPositioningElement.h" +#include "V8SVGTitleElement.h" +#include "V8SVGTRefElement.h" +#include "V8SVGTSpanElement.h" +#include "V8SVGViewElement.h" +#include "V8SVGAngle.h" +#include "V8SVGAnimatedAngle.h" +#include "V8SVGAnimatedBoolean.h" +#include "V8SVGAnimatedEnumeration.h" +#include "V8SVGAnimatedInteger.h" +#include "V8SVGAnimatedLength.h" +#include "V8SVGAnimatedLengthList.h" +#include "V8SVGAnimatedNumber.h" +#include "V8SVGAnimatedNumberList.h" +#include "V8SVGAnimatedPoints.h" +#include "V8SVGAnimatedPreserveAspectRatio.h" +#include "V8SVGAnimatedRect.h" +#include "V8SVGAnimatedString.h" +#include "V8SVGAnimatedTransformList.h" +#include "V8SVGColor.h" +#include "V8SVGDocument.h" +#include "V8SVGElementInstance.h" +#include "V8SVGElementInstanceList.h" +#include "V8SVGLength.h" +#include "V8SVGLengthList.h" +#include "V8SVGMatrix.h" +#include "V8SVGNumber.h" +#include "V8SVGNumberList.h" +#include "V8SVGPaint.h" +#include "V8SVGPathSeg.h" +#include "V8SVGPathSegArcAbs.h" +#include "V8SVGPathSegArcRel.h" +#include "V8SVGPathSegClosePath.h" +#include "V8SVGPathSegCurvetoCubicAbs.h" +#include "V8SVGPathSegCurvetoCubicRel.h" +#include "V8SVGPathSegCurvetoCubicSmoothAbs.h" +#include "V8SVGPathSegCurvetoCubicSmoothRel.h" +#include "V8SVGPathSegCurvetoQuadraticAbs.h" +#include "V8SVGPathSegCurvetoQuadraticRel.h" +#include "V8SVGPathSegCurvetoQuadraticSmoothAbs.h" +#include "V8SVGPathSegCurvetoQuadraticSmoothRel.h" +#include "V8SVGPathSegLinetoAbs.h" +#include "V8SVGPathSegLinetoHorizontalAbs.h" +#include "V8SVGPathSegLinetoHorizontalRel.h" +#include "V8SVGPathSegLinetoRel.h" +#include "V8SVGPathSegLinetoVerticalAbs.h" +#include "V8SVGPathSegLinetoVerticalRel.h" +#include "V8SVGPathSegList.h" +#include "V8SVGPathSegMovetoAbs.h" +#include "V8SVGPathSegMovetoRel.h" +#include "V8SVGPoint.h" +#include "V8SVGPointList.h" +#include "V8SVGPreserveAspectRatio.h" +#include "V8SVGRect.h" +#include "V8SVGRenderingIntent.h" +#include "V8SVGStringList.h" +#include "V8SVGTransform.h" +#include "V8SVGTransformList.h" +#include "V8SVGUnitTypes.h" +#include "V8SVGURIReference.h" +#include "V8SVGZoomEvent.h" +#endif + +#if ENABLE(VIDEO) +#include "V8HTMLAudioElement.h" +#include "V8HTMLMediaElement.h" +#include "V8HTMLSourceElement.h" +#include "V8HTMLVideoElement.h" +#include "V8MediaError.h" +#include "V8TimeRanges.h" +#endif + +#if ENABLE(WORKERS) +#include "V8Worker.h" +#include "V8WorkerContext.h" +#include "V8WorkerLocation.h" +#include "V8WorkerNavigator.h" +#endif + +namespace WebCore { + +FunctionTemplateFactory V8ClassIndex::GetFactory(V8WrapperType type) { + switch (type) { +#define MAKE_CASE(type, name)\ + case V8ClassIndex::type: return V8##name::GetTemplate; + WRAPPER_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: return NULL; + } +} + + +#define MAKE_CACHE(type, name)\ + static v8::Persistent<v8::FunctionTemplate> name##_cache_; + ALL_WRAPPER_TYPES(MAKE_CACHE) +#undef MAKE_CACHE + + +v8::Persistent<v8::FunctionTemplate>* V8ClassIndex::GetCache( + V8WrapperType type) { + switch (type) { +#define MAKE_CASE(type, name)\ + case V8ClassIndex::type: return &name##_cache_; + ALL_WRAPPER_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: + ASSERT(false); + return NULL; + } +} + +} // namespace WebCore diff --git a/V8Binding/v8/v8_index.h b/V8Binding/v8/v8_index.h new file mode 100644 index 0000000..f567e5d --- /dev/null +++ b/V8Binding/v8/v8_index.h @@ -0,0 +1,488 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_INDEX_H__ +#define V8_INDEX_H__ + +#include <v8.h> +#include "PlatformString.h" // for WebCore::String + +namespace WebCore { + +typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); + +#if ENABLE(VIDEO) +#define VIDEO_HTMLELEMENT_TYPES(V) \ + V(HTMLAUDIOELEMENT, HTMLAudioElement) \ + V(HTMLMEDIAELEMENT, HTMLMediaElement) \ + V(HTMLSOURCEELEMENT, HTMLSourceElement) \ + V(HTMLVIDEOELEMENT, HTMLVideoElement) +#define VIDEO_NONNODE_TYPES(V) \ + V(MEDIAERROR, MediaError) \ + V(TIMERANGES, TimeRanges) +#else +#define VIDEO_HTMLELEMENT_TYPES(V) +#define VIDEO_NONNODE_TYPES(V) +#endif + +#if ENABLE(WORKERS) +#define WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) \ + V(WORKER, Worker) + +#define WORKER_NONNODE_WRAPPER_TYPES(V) \ + V(WORKERCONTEXT, WorkerContext) \ + V(WORKERLOCATION, WorkerLocation) \ + V(WORKERNAVIGATOR, WorkerNavigator) +#else +#define WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) +#define WORKER_NONNODE_WRAPPER_TYPES(V) +#endif + +#define DOM_NODE_TYPES(V) \ + V(ATTR, Attr) \ + V(CHARACTERDATA, CharacterData) \ + V(CDATASECTION, CDATASection) \ + V(COMMENT, Comment) \ + V(DOCUMENT, Document) \ + V(DOCUMENTFRAGMENT, DocumentFragment) \ + V(DOCUMENTTYPE, DocumentType) \ + V(ELEMENT, Element) \ + V(ENTITY, Entity) \ + V(ENTITYREFERENCE, EntityReference) \ + V(HTMLDOCUMENT, HTMLDocument) \ + V(NODE, Node) \ + V(NOTATION, Notation) \ + V(PROCESSINGINSTRUCTION, ProcessingInstruction) \ + V(TEXT, Text) \ + \ + V(HTMLANCHORELEMENT, HTMLAnchorElement) \ + V(HTMLAPPLETELEMENT, HTMLAppletElement) \ + V(HTMLAREAELEMENT, HTMLAreaElement) \ + V(HTMLBASEELEMENT, HTMLBaseElement) \ + V(HTMLBASEFONTELEMENT, HTMLBaseFontElement) \ + V(HTMLBLOCKQUOTEELEMENT, HTMLBlockquoteElement) \ + V(HTMLBODYELEMENT, HTMLBodyElement) \ + V(HTMLBRELEMENT, HTMLBRElement) \ + V(HTMLBUTTONELEMENT, HTMLButtonElement) \ + V(HTMLCANVASELEMENT, HTMLCanvasElement) \ + V(HTMLDIRECTORYELEMENT, HTMLDirectoryElement) \ + V(HTMLDIVELEMENT, HTMLDivElement) \ + V(HTMLDLISTELEMENT, HTMLDListElement) \ + V(HTMLEMBEDELEMENT, HTMLEmbedElement) \ + V(HTMLFIELDSETELEMENT, HTMLFieldSetElement) \ + V(HTMLFONTELEMENT, HTMLFontElement) \ + V(HTMLFORMELEMENT, HTMLFormElement) \ + V(HTMLFRAMEELEMENT, HTMLFrameElement) \ + V(HTMLFRAMESETELEMENT, HTMLFrameSetElement) \ + V(HTMLHEADINGELEMENT, HTMLHeadingElement) \ + V(HTMLHEADELEMENT, HTMLHeadElement) \ + V(HTMLHRELEMENT, HTMLHRElement) \ + V(HTMLHTMLELEMENT, HTMLHtmlElement) \ + V(HTMLIFRAMEELEMENT, HTMLIFrameElement) \ + V(HTMLIMAGEELEMENT, HTMLImageElement) \ + V(HTMLINPUTELEMENT, HTMLInputElement) \ + V(HTMLISINDEXELEMENT, HTMLIsIndexElement) \ + V(HTMLLABELELEMENT, HTMLLabelElement) \ + V(HTMLLEGENDELEMENT, HTMLLegendElement) \ + V(HTMLLIELEMENT, HTMLLIElement) \ + V(HTMLLINKELEMENT, HTMLLinkElement) \ + V(HTMLMAPELEMENT, HTMLMapElement) \ + V(HTMLMARQUEEELEMENT, HTMLMarqueeElement) \ + V(HTMLMENUELEMENT, HTMLMenuElement) \ + V(HTMLMETAELEMENT, HTMLMetaElement) \ + V(HTMLMODELEMENT, HTMLModElement) \ + V(HTMLOBJECTELEMENT, HTMLObjectElement) \ + V(HTMLOLISTELEMENT, HTMLOListElement) \ + V(HTMLOPTGROUPELEMENT, HTMLOptGroupElement) \ + V(HTMLOPTIONELEMENT, HTMLOptionElement) \ + V(HTMLPARAGRAPHELEMENT, HTMLParagraphElement) \ + V(HTMLPARAMELEMENT, HTMLParamElement) \ + V(HTMLPREELEMENT, HTMLPreElement) \ + V(HTMLQUOTEELEMENT, HTMLQuoteElement) \ + V(HTMLSCRIPTELEMENT, HTMLScriptElement) \ + V(HTMLSELECTELEMENT, HTMLSelectElement) \ + V(HTMLSTYLEELEMENT, HTMLStyleElement) \ + V(HTMLTABLECAPTIONELEMENT, HTMLTableCaptionElement) \ + V(HTMLTABLECOLELEMENT, HTMLTableColElement) \ + V(HTMLTABLEELEMENT, HTMLTableElement) \ + V(HTMLTABLESECTIONELEMENT, HTMLTableSectionElement) \ + V(HTMLTABLECELLELEMENT, HTMLTableCellElement) \ + V(HTMLTABLEROWELEMENT, HTMLTableRowElement) \ + V(HTMLTEXTAREAELEMENT, HTMLTextAreaElement) \ + V(HTMLTITLEELEMENT, HTMLTitleElement) \ + V(HTMLULISTELEMENT, HTMLUListElement) \ + V(HTMLELEMENT, HTMLElement) \ + VIDEO_HTMLELEMENT_TYPES(V) + +#if ENABLE(SVG_ANIMATION) +#define SVG_ANIMATION_ELEMENT_TYPES(V) \ + V(SVGANIMATECOLORELEMENT, SVGAnimateColorElement) \ + V(SVGANIMATEELEMENT, SVGAnimateElement) \ + V(SVGANIMATETRANSFORMELEMENT, SVGAnimateTransformElement) \ + V(SVGANIMATIONELEMENT, SVGAnimationElement) \ + V(SVGSETELEMENT, SVGSetElement) +#else +#define SVG_ANIMATION_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG_FILTERS) +#define SVG_FILTERS_ELEMENT_TYPES(V) \ + V(SVGCOMPONENTTRANSFERFUNCTIONELEMENT, SVGComponentTransferFunctionElement)\ + V(SVGFEBLENDELEMENT, SVGFEBlendElement) \ + V(SVGFECOLORMATRIXELEMENT, SVGFEColorMatrixElement) \ + V(SVGFECOMPONENTTRANSFERELEMENT, SVGFEComponentTransferElement) \ + V(SVGFECOMPOSITEELEMENT, SVGFECompositeElement) \ + V(SVGFEDIFFUSELIGHTINGELEMENT, SVGFEDiffuseLightingElement) \ + V(SVGFEDISPLACEMENTMAPELEMENT, SVGFEDisplacementMapElement) \ + V(SVGFEDISTANTLIGHTELEMENT, SVGFEDistantLightElement) \ + V(SVGFEFLOODELEMENT, SVGFEFloodElement) \ + V(SVGFEFUNCAELEMENT, SVGFEFuncAElement) \ + V(SVGFEFUNCBELEMENT, SVGFEFuncBElement) \ + V(SVGFEFUNCGELEMENT, SVGFEFuncGElement) \ + V(SVGFEFUNCRELEMENT, SVGFEFuncRElement) \ + V(SVGFEGAUSSIANBLURELEMENT, SVGFEGaussianBlurElement) \ + V(SVGFEIMAGEELEMENT, SVGFEImageElement) \ + V(SVGFEMERGEELEMENT, SVGFEMergeElement) \ + V(SVGFEMERGENODEELEMENT, SVGFEMergeNodeElement) \ + V(SVGFEOFFSETELEMENT, SVGFEOffsetElement) \ + V(SVGFEPOINTLIGHTELEMENT, SVGFEPointLightElement) \ + V(SVGFESPECULARLIGHTINGELEMENT, SVGFESpecularLightingElement) \ + V(SVGFESPOTLIGHTELEMENT, SVGFESpotLightElement) \ + V(SVGFETILEELEMENT, SVGFETileElement) \ + V(SVGFETURBULENCEELEMENT, SVGFETurbulenceElement) \ + V(SVGFILTERELEMENT, SVGFilterElement) +#else +#define SVG_FILTERS_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG_FONTS) +#define SVG_FONTS_ELEMENT_TYPES(V) \ + V(SVGDEFINITIONSRCELEMENT, SVGDefinitionSrcElement) \ + V(SVGFONTFACEELEMENT, SVGFontFaceElement) \ + V(SVGFONTFACEFORMATELEMENT, SVGFontFaceFormatElement) \ + V(SVGFONTFACENAMEELEMENT, SVGFontFaceNameElement) \ + V(SVGFONTFACESRCELEMENT, SVGFontFaceSrcElement) \ + V(SVGFONTFACEURIELEMENT, SVGFontFaceUriElement) +#else +#define SVG_FONTS_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG_FOREIGN_OBJECT) +#define SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V) \ + V(SVGFOREIGNOBJECTELEMENT, SVGForeignObjectElement) +#else +#define SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG_USE) +#define SVG_USE_ELEMENT_TYPES(V) \ + V(SVGUSEELEMENT, SVGUseElement) +#else +#define SVG_USE_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG) +#define SVG_NODE_TYPES(V) \ + SVG_ANIMATION_ELEMENT_TYPES(V) \ + SVG_FILTERS_ELEMENT_TYPES(V) \ + SVG_FONTS_ELEMENT_TYPES(V) \ + SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V) \ + SVG_USE_ELEMENT_TYPES(V) \ + V(SVGAELEMENT, SVGAElement) \ + V(SVGALTGLYPHELEMENT, SVGAltGlyphElement) \ + V(SVGCIRCLEELEMENT, SVGCircleElement) \ + V(SVGCLIPPATHELEMENT, SVGClipPathElement) \ + V(SVGCURSORELEMENT, SVGCursorElement) \ + V(SVGDEFSELEMENT, SVGDefsElement) \ + V(SVGDESCELEMENT, SVGDescElement) \ + V(SVGELLIPSEELEMENT, SVGEllipseElement) \ + V(SVGGELEMENT, SVGGElement) \ + V(SVGGLYPHELEMENT, SVGGlyphElement) \ + V(SVGGRADIENTELEMENT, SVGGradientElement) \ + V(SVGIMAGEELEMENT, SVGImageElement) \ + V(SVGLINEARGRADIENTELEMENT, SVGLinearGradientElement) \ + V(SVGLINEELEMENT, SVGLineElement) \ + V(SVGMARKERELEMENT, SVGMarkerElement) \ + V(SVGMASKELEMENT, SVGMaskElement) \ + V(SVGMETADATAELEMENT, SVGMetadataElement) \ + V(SVGPATHELEMENT, SVGPathElement) \ + V(SVGPATTERNELEMENT, SVGPatternElement) \ + V(SVGPOLYGONELEMENT, SVGPolygonElement) \ + V(SVGPOLYLINEELEMENT, SVGPolylineElement) \ + V(SVGRADIALGRADIENTELEMENT, SVGRadialGradientElement) \ + V(SVGRECTELEMENT, SVGRectElement) \ + V(SVGSCRIPTELEMENT, SVGScriptElement) \ + V(SVGSTOPELEMENT, SVGStopElement) \ + V(SVGSTYLEELEMENT, SVGStyleElement) \ + V(SVGSVGELEMENT, SVGSVGElement) \ + V(SVGSWITCHELEMENT, SVGSwitchElement) \ + V(SVGSYMBOLELEMENT, SVGSymbolElement) \ + V(SVGTEXTCONTENTELEMENT, SVGTextContentElement) \ + V(SVGTEXTELEMENT, SVGTextElement) \ + V(SVGTEXTPATHELEMENT, SVGTextPathElement) \ + V(SVGTEXTPOSITIONINGELEMENT, SVGTextPositioningElement) \ + V(SVGTITLEELEMENT, SVGTitleElement) \ + V(SVGTREFELEMENT, SVGTRefElement) \ + V(SVGTSPANELEMENT, SVGTSpanElement) \ + V(SVGVIEWELEMENT, SVGViewElement) \ + V(SVGELEMENT, SVGElement) \ + \ + V(SVGDOCUMENT, SVGDocument) +#endif // SVG + + +// ACTIVE_DOM_OBJECT_TYPES are DOM_OBJECT_TYPES that need special treatement +// during GC. +#define ACTIVE_DOM_OBJECT_TYPES(V) \ + V(MESSAGEPORT, MessagePort) \ + V(XMLHTTPREQUEST, XMLHttpRequest) \ + WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) + +// NOTE: DOM_OBJECT_TYPES is split into two halves because +// Visual Studio's Intellinonsense crashes when macros get +// too large. 10-29-08 +// DOM_OBJECT_TYPES are non-node DOM types. +#define DOM_OBJECT_TYPES_1(V) \ + V(BARINFO, BarInfo) \ + V(CANVASGRADIENT, CanvasGradient) \ + V(CANVASPATTERN, CanvasPattern) \ + V(CANVASRENDERINGCONTEXT2D, CanvasRenderingContext2D) \ + V(CLIENTRECT, ClientRect) \ + V(CLIENTRECTLIST, ClientRectList) \ + V(CLIPBOARD, Clipboard) \ + V(CONSOLE, Console) \ + V(COUNTER, Counter) \ + V(CSSCHARSETRULE, CSSCharsetRule) \ + V(CSSFONTFACERULE, CSSFontFaceRule) \ + V(CSSIMPORTRULE, CSSImportRule) \ + V(CSSMEDIARULE, CSSMediaRule) \ + V(CSSPAGERULE, CSSPageRule) \ + V(CSSPRIMITIVEVALUE, CSSPrimitiveValue) \ + V(CSSRULE, CSSRule) \ + V(CSSRULELIST, CSSRuleList) \ + V(CSSSTYLEDECLARATION, CSSStyleDeclaration) \ + V(CSSSTYLERULE, CSSStyleRule) \ + V(CSSSTYLESHEET, CSSStyleSheet) \ + V(CSSVALUE, CSSValue) \ + V(CSSVALUELIST, CSSValueList) \ + V(CSSVARIABLESDECLARATION, CSSVariablesDeclaration) \ + V(CSSVARIABLESRULE, CSSVariablesRule) \ + V(DOMCOREEXCEPTION, DOMCoreException) \ + V(DOMIMPLEMENTATION, DOMImplementation) \ + V(DOMPARSER, DOMParser) \ + V(DOMSELECTION, DOMSelection) \ + V(DOMSTRINGLIST, DOMStringList) \ + V(DOMWINDOW, DOMWindow) \ + V(EVENT, Event) \ + V(EVENTEXCEPTION, EventException) \ + V(FILE, File) \ + V(FILELIST, FileList) \ + V(HISTORY, History) \ + V(UNDETECTABLEHTMLCOLLECTION, UndetectableHTMLCollection) \ + V(HTMLCOLLECTION, HTMLCollection) \ + V(HTMLOPTIONSCOLLECTION, HTMLOptionsCollection) \ + V(IMAGEDATA, ImageData) \ + V(CANVASPIXELARRAY, CanvasPixelArray) \ + V(INSPECTORCONTROLLER, InspectorController) \ + V(KEYBOARDEVENT, KeyboardEvent) \ + V(LOCATION, Location) \ + V(MEDIALIST, MediaList) + +#define DOM_OBJECT_TYPES_2(V) \ + V(MESSAGECHANNEL, MessageChannel) \ + V(MESSAGEEVENT, MessageEvent) \ + V(MIMETYPE, MimeType) \ + V(MIMETYPEARRAY, MimeTypeArray) \ + V(MOUSEEVENT, MouseEvent) \ + V(MUTATIONEVENT, MutationEvent) \ + V(NAMEDNODEMAP, NamedNodeMap) \ + V(NAVIGATOR, Navigator) \ + V(NODEFILTER, NodeFilter) \ + V(NODEITERATOR, NodeIterator) \ + V(NODELIST, NodeList) \ + V(OVERFLOWEVENT, OverflowEvent) \ + V(PLUGIN, Plugin) \ + V(PLUGINARRAY, PluginArray) \ + V(PROGRESSEVENT, ProgressEvent) \ + V(RANGE, Range) \ + V(RANGEEXCEPTION, RangeException) \ + V(RECT, Rect) \ + V(RGBCOLOR, RGBColor) \ + V(SCREEN, Screen) \ + V(STYLESHEET, StyleSheet) \ + V(STYLESHEETLIST, StyleSheetList) \ + V(TEXTEVENT, TextEvent) \ + V(TEXTMETRICS, TextMetrics) \ + V(TREEWALKER, TreeWalker) \ + V(UIEVENT, UIEvent) \ + V(WEBKITANIMATIONEVENT, WebKitAnimationEvent) \ + V(WEBKITCSSKEYFRAMERULE, WebKitCSSKeyframeRule) \ + V(WEBKITCSSKEYFRAMESRULE, WebKitCSSKeyframesRule) \ + V(WEBKITCSSMATRIX, WebKitCSSMatrix) \ + V(WEBKITPOINT, WebKitPoint) \ + V(WEBKITCSSTRANSFORMVALUE, WebKitCSSTransformValue) \ + V(WEBKITTRANSITIONEVENT, WebKitTransitionEvent) \ + V(WHEELEVENT, WheelEvent) \ + V(XMLHTTPREQUESTUPLOAD, XMLHttpRequestUpload) \ + V(XMLHTTPREQUESTEXCEPTION, XMLHttpRequestException) \ + V(XMLHTTPREQUESTPROGRESSEVENT, XMLHttpRequestProgressEvent) \ + V(XMLSERIALIZER, XMLSerializer) \ + V(XPATHEVALUATOR, XPathEvaluator) \ + V(XPATHEXCEPTION, XPathException) \ + V(XPATHEXPRESSION, XPathExpression) \ + V(XPATHNSRESOLVER, XPathNSResolver) \ + V(XPATHRESULT, XPathResult) \ + V(XSLTPROCESSOR, XSLTProcessor) \ + ACTIVE_DOM_OBJECT_TYPES(V) \ + VIDEO_NONNODE_TYPES(V) \ + WORKER_NONNODE_WRAPPER_TYPES(V) + +#define DOM_OBJECT_DATABASE_TYPES(V) \ + V(DATABASE, Database) \ + V(SQLERROR, SQLError) \ + V(SQLRESULTSET, SQLResultSet) \ + V(SQLRESULTSETROWLIST, SQLResultSetRowList) \ + V(SQLTRANSACTION, SQLTransaction) + +#define DOM_OBJECT_TYPES(V) \ + DOM_OBJECT_TYPES_1(V) \ + DOM_OBJECT_TYPES_2(V) \ + DOM_OBJECT_DATABASE_TYPES(V) + +#if ENABLE(SVG) +// SVG_OBJECT_TYPES are svg non-node, non-pod types. +#define SVG_OBJECT_TYPES(V) \ + V(SVGANGLE, SVGAngle) \ + V(SVGANIMATEDANGLE, SVGAnimatedAngle) \ + V(SVGANIMATEDBOOLEAN, SVGAnimatedBoolean) \ + V(SVGANIMATEDENUMERATION, SVGAnimatedEnumeration) \ + V(SVGANIMATEDINTEGER, SVGAnimatedInteger) \ + V(SVGANIMATEDLENGTH, SVGAnimatedLength) \ + V(SVGANIMATEDLENGTHLIST, SVGAnimatedLengthList) \ + V(SVGANIMATEDNUMBER, SVGAnimatedNumber) \ + V(SVGANIMATEDNUMBERLIST, SVGAnimatedNumberList) \ + V(SVGANIMATEDPRESERVEASPECTRATIO, SVGAnimatedPreserveAspectRatio) \ + V(SVGANIMATEDRECT, SVGAnimatedRect) \ + V(SVGANIMATEDSTRING, SVGAnimatedString) \ + V(SVGANIMATEDTRANSFORMLIST, SVGAnimatedTransformList) \ + V(SVGCOLOR, SVGColor) \ + V(SVGELEMENTINSTANCE, SVGElementInstance) \ + V(SVGELEMENTINSTANCELIST, SVGElementInstanceList) \ + V(SVGEXCEPTION, SVGException) \ + V(SVGLENGTHLIST, SVGLengthList) \ + V(SVGNUMBERLIST, SVGNumberList) \ + V(SVGPAINT, SVGPaint) \ + V(SVGPATHSEG, SVGPathSeg) \ + V(SVGPATHSEGARCABS, SVGPathSegArcAbs) \ + V(SVGPATHSEGARCREL, SVGPathSegArcRel) \ + V(SVGPATHSEGCLOSEPATH, SVGPathSegClosePath) \ + V(SVGPATHSEGCURVETOCUBICABS, SVGPathSegCurvetoCubicAbs) \ + V(SVGPATHSEGCURVETOCUBICREL, SVGPathSegCurvetoCubicRel) \ + V(SVGPATHSEGCURVETOCUBICSMOOTHABS, SVGPathSegCurvetoCubicSmoothAbs) \ + V(SVGPATHSEGCURVETOCUBICSMOOTHREL, SVGPathSegCurvetoCubicSmoothRel) \ + V(SVGPATHSEGCURVETOQUADRATICABS, SVGPathSegCurvetoQuadraticAbs) \ + V(SVGPATHSEGCURVETOQUADRATICREL, SVGPathSegCurvetoQuadraticRel) \ + V(SVGPATHSEGCURVETOQUADRATICSMOOTHABS, SVGPathSegCurvetoQuadraticSmoothAbs)\ + V(SVGPATHSEGCURVETOQUADRATICSMOOTHREL, SVGPathSegCurvetoQuadraticSmoothRel)\ + V(SVGPATHSEGLINETOABS, SVGPathSegLinetoAbs) \ + V(SVGPATHSEGLINETOHORIZONTALABS, SVGPathSegLinetoHorizontalAbs) \ + V(SVGPATHSEGLINETOHORIZONTALREL, SVGPathSegLinetoHorizontalRel) \ + V(SVGPATHSEGLINETOREL, SVGPathSegLinetoRel) \ + V(SVGPATHSEGLINETOVERTICALABS, SVGPathSegLinetoVerticalAbs) \ + V(SVGPATHSEGLINETOVERTICALREL, SVGPathSegLinetoVerticalRel) \ + V(SVGPATHSEGLIST, SVGPathSegList) \ + V(SVGPATHSEGMOVETOABS, SVGPathSegMovetoAbs) \ + V(SVGPATHSEGMOVETOREL, SVGPathSegMovetoRel) \ + V(SVGPOINTLIST, SVGPointList) \ + V(SVGPRESERVEASPECTRATIO, SVGPreserveAspectRatio) \ + V(SVGRENDERINGINTENT, SVGRenderingIntent) \ + V(SVGSTRINGLIST, SVGStringList) \ + V(SVGTRANSFORMLIST, SVGTransformList) \ + V(SVGUNITTYPES, SVGUnitTypes) \ + V(SVGZOOMEVENT, SVGZoomEvent) + +// SVG POD types should list all types whose IDL has PODType declaration. +#define SVG_POD_TYPES(V) \ + V(SVGLENGTH, SVGLength) \ + V(SVGTRANSFORM, SVGTransform) \ + V(SVGMATRIX, SVGMatrix) \ + V(SVGNUMBER, SVGNumber) \ + V(SVGPOINT, SVGPoint) \ + V(SVGRECT, SVGRect) + +// POD types can have different implementation names, see CodeGenerateV8.pm. +#define SVG_POD_NATIVE_TYPES(V) \ + V(SVGLENGTH, SVGLength) \ + V(SVGTRANSFORM, SVGTransform) \ + V(SVGMATRIX, TransformationMatrix) \ + V(SVGNUMBER, float) \ + V(SVGPOINT, FloatPoint) \ + V(SVGRECT, FloatRect) + +// Shouldn't generate code for these two types. +#define SVG_NO_WRAPPER_TYPES(V) \ + V(SVGURIREFERENCE, SVGURIReference) \ + V(SVGANIMATEDPOINTS, SVGAnimatedPoints) + +// SVG_NONNODE_TYPES are SVG non-node object types, pod typs and +// numerical types. +#define SVG_NONNODE_TYPES(V) \ + SVG_OBJECT_TYPES(V) \ + SVG_POD_TYPES(V) +#endif // SVG + +// EVENTTARGET, EVENTLISTENER, and NPOBJECT do not have V8 wrappers. +#define DOM_NO_WRAPPER_TYPES(V) \ + V(EVENTTARGET, EventTarget) \ + V(EVENTLISTENER, EventListener) \ + V(NPOBJECT, NPObject) + +#if ENABLE(SVG) +#define WRAPPER_TYPES(V) \ + DOM_NODE_TYPES(V) \ + DOM_OBJECT_TYPES(V) \ + SVG_NODE_TYPES(V) \ + SVG_NONNODE_TYPES(V) +#define NO_WRAPPER_TYPES(V) \ + DOM_NO_WRAPPER_TYPES(V) \ + SVG_NO_WRAPPER_TYPES(V) +#else // SVG +#define WRAPPER_TYPES(V) \ + DOM_NODE_TYPES(V) \ + DOM_OBJECT_TYPES(V) +#define NO_WRAPPER_TYPES(V) \ + DOM_NO_WRAPPER_TYPES(V) +#endif // SVG + +#define ALL_WRAPPER_TYPES(V) \ + WRAPPER_TYPES(V) \ + NO_WRAPPER_TYPES(V) + +class V8ClassIndex { + public: + // Type must start at non-negative numbers. See ToInt, FromInt. + enum V8WrapperType { + INVALID_CLASS_INDEX = 0, +#define DEFINE_ENUM(name, type) name, + ALL_WRAPPER_TYPES(DEFINE_ENUM) +#undef DEFINE_ENUM + CLASSINDEX_END, + WRAPPER_TYPE_COUNT = CLASSINDEX_END + }; + + static int ToInt(V8WrapperType type) { return static_cast<int>(type); } + + static V8WrapperType FromInt(int v) { + ASSERT(INVALID_CLASS_INDEX <= v && v < CLASSINDEX_END); + return static_cast<V8WrapperType>(v); + } + + static FunctionTemplateFactory GetFactory(V8WrapperType type); + // Returns a field to be used as cache for the template for the given type + static v8::Persistent<v8::FunctionTemplate>* GetCache(V8WrapperType type); +}; + +} + +#endif // V8_INDEX_H__ diff --git a/V8Binding/v8/v8_npobject.h b/V8Binding/v8/v8_npobject.h new file mode 100644 index 0000000..c2d8550 --- /dev/null +++ b/V8Binding/v8/v8_npobject.h @@ -0,0 +1,7 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a temporary file until V8HTMLPlugInElementCustom.cpp in WebKit +// includes the new name of this file. +#include "V8NPObject.h" diff --git a/V8Binding/v8/v8_proxy.cpp b/V8Binding/v8/v8_proxy.cpp new file mode 100644 index 0000000..deb47fd --- /dev/null +++ b/V8Binding/v8/v8_proxy.cpp @@ -0,0 +1,3346 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include <algorithm> +#include <utility> + +#include <v8.h> +#include <v8-debug.h> + +#include "v8_proxy.h" +#include "v8_index.h" +#include "v8_binding.h" +#include "v8_custom.h" +#include "V8Collection.h" +#include "V8DOMWindow.h" + +#include "ChromiumBridge.h" +#include "DOMObjectsInclude.h" + +#include "ScriptController.h" +#include "V8DOMMap.h" + +namespace WebCore { + +V8EventListenerList::V8EventListenerList(const char* name) +{ + ASSERT(strlen(name) <= kMaxKeyNameLength); + v8::HandleScope handleScope; + + // Write the name into a temporary buffer, leaving 1 space at the beginning + // for a prefix we'll vary between the inline and non-inline keys. + char keyBuffer[kMaxKeyNameLength + 2] = { 0 }; + strncpy(keyBuffer + 1, name, kMaxKeyNameLength); + keyBuffer[0] = '1'; + m_inlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); + keyBuffer[0] = '2'; + m_nonInlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); +} + +V8EventListenerList::~V8EventListenerList() +{ + m_inlineKey.Dispose(); + m_nonInlineKey.Dispose(); +} + +V8EventListenerList::iterator V8EventListenerList::begin() +{ + return m_list.begin(); +} + +V8EventListenerList::iterator V8EventListenerList::end() +{ + return m_list.end(); +} + +v8::Handle<v8::String> V8EventListenerList::getKey(bool isInline) +{ + if (isInline) + return m_inlineKey; + else + return m_nonInlineKey; +} + +// See comment in .h file for this function, and update accordingly if +// implementation details change here. +void V8EventListenerList::add(V8EventListener* listener) +{ + m_list.append(listener); + + v8::HandleScope handleScope; + v8::Local<v8::Object> object = listener->getListenerObject(); + v8::Local<v8::Value> value = v8::External::Wrap(listener); + object->SetHiddenValue(getKey(listener->isInline()), value); +} + +void V8EventListenerList::remove(V8EventListener* listener) +{ + v8::HandleScope handleScope; + for (size_t i = 0; i < m_list.size(); i++) { + V8EventListener* element = m_list.at(i); + if (element->isInline() == listener->isInline() && element == listener) { + v8::Local<v8::Object> object = listener->getListenerObject(); + object->DeleteHiddenValue(getKey(listener->isInline())); + m_list.remove(i); + break; + } + } +} + +void V8EventListenerList::clear() +{ + v8::HandleScope handleScope; + for (size_t i = 0; i < m_list.size(); i++) { + V8EventListener* element = m_list.at(i); + v8::Local<v8::Object> object = element->getListenerObject(); + object->DeleteHiddenValue(getKey(element->isInline())); + } + m_list.clear(); +} + +V8EventListener* V8EventListenerList::find(v8::Local<v8::Object> object, bool isInline) +{ + v8::Local<v8::Value> value = object->GetHiddenValue(getKey(isInline)); + if (value.IsEmpty()) + return 0; + return reinterpret_cast<V8EventListener*>(v8::External::Unwrap(value)); +} + + +// Static utility context. +v8::Persistent<v8::Context> V8Proxy::m_utilityContext; + +// Static list of registered extensions +V8ExtensionList V8Proxy::m_extensions; + + +#ifndef NDEBUG +// Keeps track of global handles created (not JS wrappers +// of DOM objects). Often these global handles are source +// of leaks. +// +// If you want to let a C++ object hold a persistent handle +// to a JS object, you should register the handle here to +// keep track of leaks. +// +// When creating a persistent handle, call: +// +// #ifndef NDEBUG +// V8Proxy::RegisterGlobalHandle(type, host, handle); +// #endif +// +// When releasing the handle, call: +// +// #ifndef NDEBUG +// V8Proxy::UnregisterGlobalHandle(type, host, handle); +// #endif +// +typedef HashMap<v8::Value*, GlobalHandleInfo*> GlobalHandleMap; + +static GlobalHandleMap& global_handle_map() +{ + static GlobalHandleMap static_global_handle_map; + return static_global_handle_map; +} + + +// The USE_VAR(x) template is used to silence C++ compiler warnings +// issued for unused variables (typically parameters or values that +// we want to watch in the debugger). +template <typename T> +static inline void USE_VAR(T) { } + +// The function is the place to set the break point to inspect +// live global handles. Leaks are often come from leaked global handles. +static void EnumerateGlobalHandles() +{ + for (GlobalHandleMap::iterator it = global_handle_map().begin(), + end = global_handle_map().end(); it != end; ++it) { + GlobalHandleInfo* info = it->second; + USE_VAR(info); + v8::Value* handle = it->first; + USE_VAR(handle); + } +} + +void V8Proxy::RegisterGlobalHandle(GlobalHandleType type, void* host, + v8::Persistent<v8::Value> handle) +{ + ASSERT(!global_handle_map().contains(*handle)); + global_handle_map().set(*handle, new GlobalHandleInfo(host, type)); +} + + +void V8Proxy::UnregisterGlobalHandle(void* host, v8::Persistent<v8::Value> handle) +{ + ASSERT(global_handle_map().contains(*handle)); + GlobalHandleInfo* info = global_handle_map().take(*handle); + ASSERT(info->host_ == host); + delete info; +} +#endif // ifndef NDEBUG + +void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst, + v8::Handle<v8::ObjectTemplate> proto, + const BatchedAttribute* attrs, + size_t num_attrs) +{ + for (size_t i = 0; i < num_attrs; ++i) { + const BatchedAttribute* a = &attrs[i]; + (a->on_proto ? proto : inst)->SetAccessor( + v8::String::New(a->name), + a->getter, + a->setter, + a->data == V8ClassIndex::INVALID_CLASS_INDEX + ? v8::Handle<v8::Value>() + : v8::Integer::New(V8ClassIndex::ToInt(a->data)), + a->settings, + a->attribute); + } +} + +void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc, + v8::Handle<v8::ObjectTemplate> proto, + const BatchedConstant* consts, + size_t num_consts) +{ + for (size_t i = 0; i < num_consts; ++i) { + const BatchedConstant* c = &consts[i]; + desc->Set(v8::String::New(c->name), + v8::Integer::New(c->value), + v8::ReadOnly); + proto->Set(v8::String::New(c->name), + v8::Integer::New(c->value), + v8::ReadOnly); + } +} + +typedef HashMap<Node*, v8::Object*> DOMNodeMap; +typedef HashMap<void*, v8::Object*> DOMObjectMap; + +#ifndef NDEBUG +static void EnumerateDOMObjectMap(DOMObjectMap& wrapper_map) +{ + for (DOMObjectMap::iterator it = wrapper_map.begin(), end = wrapper_map.end(); + it != end; ++it) { + v8::Persistent<v8::Object> wrapper(it->second); + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + void* obj = it->first; + USE_VAR(type); + USE_VAR(obj); + } +} + + +static void EnumerateDOMNodeMap(DOMNodeMap& node_map) +{ + for (DOMNodeMap::iterator it = node_map.begin(), end = node_map.end(); + it != end; ++it) { + Node* node = it->first; + USE_VAR(node); + ASSERT(v8::Persistent<v8::Object>(it->second).IsWeak()); + } +} +#endif // NDEBUG + +#if ENABLE(SVG) +v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( + SVGElementInstance* instance) +{ + if (!instance) + return v8::Null(); + + v8::Handle<v8::Object> existing_instance = getDOMSVGElementInstanceMap().get(instance); + if (!existing_instance.IsEmpty()) + return existing_instance; + + instance->ref(); + + // Instantiate the V8 object and remember it + v8::Handle<v8::Object> result = + InstantiateV8Object(V8ClassIndex::SVGELEMENTINSTANCE, + V8ClassIndex::SVGELEMENTINSTANCE, + instance); + if (!result.IsEmpty()) { + // Only update the DOM SVG element map if the result is non-empty. + getDOMSVGElementInstanceMap().set(instance, + v8::Persistent<v8::Object>::New(result)); + } + return result; +} + +// Map of SVG objects with contexts to their contexts +static HashMap<void*, SVGElement*>& svg_object_to_context_map() +{ + static HashMap<void*, SVGElement*> static_svg_object_to_context_map; + return static_svg_object_to_context_map; +} + +v8::Handle<v8::Value> V8Proxy::SVGObjectWithContextToV8Object( + V8ClassIndex::V8WrapperType type, void* object) +{ + if (!object) + return v8::Null(); + + v8::Persistent<v8::Object> result = + getDOMSVGObjectWithContextMap().get(object); + if (!result.IsEmpty()) return result; + + // Special case: SVGPathSegs need to be downcast to their real type + if (type == V8ClassIndex::SVGPATHSEG) + type = V8Custom::DowncastSVGPathSeg(object); + + v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, object); + if (!v8obj.IsEmpty()) { + result = v8::Persistent<v8::Object>::New(v8obj); + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(object)->ref(); break; +SVG_OBJECT_TYPES(MAKE_CASE) +#undef MAKE_CASE +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: \ + static_cast<V8SVGPODTypeWrapper<NAME>*>(object)->ref(); break; +SVG_POD_NATIVE_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: + ASSERT(false); + } + getDOMSVGObjectWithContextMap().set(object, result); + } + + return result; +} + +void V8Proxy::SetSVGContext(void* obj, SVGElement* context) +{ + SVGElement* old_context = svg_object_to_context_map().get(obj); + + if (old_context == context) + return; + + if (old_context) + old_context->deref(); + + if (context) + context->ref(); + + svg_object_to_context_map().set(obj, context); +} + +SVGElement* V8Proxy::GetSVGContext(void* obj) +{ + return svg_object_to_context_map().get(obj); +} + +#endif + +// A map from a DOM node to its JS wrapper, the wrapper +// is kept as a strong reference to survive GCs. +static DOMObjectMap& gc_protected_map() { + static DOMObjectMap static_gc_protected_map; + return static_gc_protected_map; +} + +// static +void V8Proxy::GCProtect(void* dom_object) +{ + if (!dom_object) + return; + if (gc_protected_map().contains(dom_object)) + return; + if (!getDOMObjectMap().contains(dom_object)) + return; + + // Create a new (strong) persistent handle for the object. + v8::Persistent<v8::Object> wrapper = getDOMObjectMap().get(dom_object); + if (wrapper.IsEmpty()) return; + + gc_protected_map().set(dom_object, *v8::Persistent<v8::Object>::New(wrapper)); +} + + +// static +void V8Proxy::GCUnprotect(void* dom_object) +{ + if (!dom_object) + return; + if (!gc_protected_map().contains(dom_object)) + return; + + // Dispose the strong reference. + v8::Persistent<v8::Object> wrapper(gc_protected_map().take(dom_object)); + wrapper.Dispose(); +} + + +// Create object groups for DOM tree nodes. +static void GCPrologue() +{ + v8::HandleScope scope; + +#ifndef NDEBUG + EnumerateDOMObjectMap(getDOMObjectMap().impl()); +#endif + + // Run through all objects with possible pending activity making their + // wrappers non weak if there is pending activity. + DOMObjectMap active_map = getActiveDOMObjectMap().impl(); + for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end(); + it != end; ++it) { + void* obj = it->first; + v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>(it->second); + ASSERT(wrapper.IsWeak()); + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: { \ + NAME* impl = static_cast<NAME*>(obj); \ + if (impl->hasPendingActivity()) \ + wrapper.ClearWeak(); \ + break; \ + } +ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + default: + ASSERT(false); +#undef MAKE_CASE + } + + // Additional handling of message port ensuring that entangled ports also + // have their wrappers entangled. This should ideally be handled when the + // ports are actually entangled in MessagePort::entangle, but to avoid + // forking MessagePort.* this is postponed to GC time. Having this postponed + // has the drawback that the wrappers are "entangled/unentangled" for each + // GC even though their entnaglement most likely is still the same. + if (type == V8ClassIndex::MESSAGEPORT) { + // Get the port and its entangled port. + MessagePort* port1 = static_cast<MessagePort*>(obj); + MessagePort* port2 = port1->entangledPort(); + if (port2 != NULL) { + // As ports are always entangled in pairs only perform the entanglement + // once for each pair (see ASSERT in MessagePort::unentangle()). + if (port1 < port2) { + v8::Handle<v8::Value> port1_wrapper = + V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1); + v8::Handle<v8::Value> port2_wrapper = + V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port2); + ASSERT(port1_wrapper->IsObject()); + v8::Handle<v8::Object>::Cast(port1_wrapper)->SetInternalField( + V8Custom::kMessagePortEntangledPortIndex, port2_wrapper); + ASSERT(port2_wrapper->IsObject()); + v8::Handle<v8::Object>::Cast(port2_wrapper)->SetInternalField( + V8Custom::kMessagePortEntangledPortIndex, port1_wrapper); + } + } else { + // Remove the wrapper entanglement when a port is not entangled. + if (V8Proxy::DOMObjectHasJSWrapper(port1)) { + v8::Handle<v8::Value> wrapper = + V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1); + ASSERT(wrapper->IsObject()); + v8::Handle<v8::Object>::Cast(wrapper)->SetInternalField( + V8Custom::kMessagePortEntangledPortIndex, v8::Undefined()); + } + } + } + } + + // Create object groups. + typedef std::pair<uintptr_t, Node*> GrouperPair; + typedef Vector<GrouperPair> GrouperList; + + DOMNodeMap node_map = getDOMNodeMap().impl(); + GrouperList grouper; + grouper.reserveCapacity(node_map.size()); + + for (DOMNodeMap::iterator it = node_map.begin(), end = node_map.end(); + it != end; ++it) { + Node* node = it->first; + + // If the node is in document, put it in the ownerDocument's object group. + // + // If an image element was created by JavaScript "new Image", + // it is not in a document. However, if the load event has not + // been fired (still onloading), it is treated as in the document. + // + // Otherwise, the node is put in an object group identified by the root + // elment of the tree to which it belongs. + uintptr_t group_id; + if (node->inDocument() || + (node->hasTagName(HTMLNames::imgTag) && + !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())) { + group_id = reinterpret_cast<uintptr_t>(node->document()); + } else { + Node* root = node; + while (root->parent()) + root = root->parent(); + + // If the node is alone in its DOM tree (doesn't have a parent or any + // children) then the group will be filtered out later anyway. + if (root == node && !node->hasChildNodes()) + continue; + + group_id = reinterpret_cast<uintptr_t>(root); + } + grouper.append(GrouperPair(group_id, node)); + } + + // Group by sorting by the group id. This will use the std::pair operator<, + // which will really sort by both the group id and the Node*. However the + // Node* is only involved to sort within a group id, so it will be fine. + std::sort(grouper.begin(), grouper.end()); + + // TODO(deanm): Should probably work in iterators here, but indexes were + // easier for my simple mind. + for (size_t i = 0; i < grouper.size(); ) { + // Seek to the next key (or the end of the list). + size_t next_key_index = grouper.size(); + for (size_t j = i; j < grouper.size(); ++j) { + if (grouper[i].first != grouper[j].first) { + next_key_index = j; + break; + } + } + + ASSERT(next_key_index > i); + + // We only care about a group if it has more than one object. If it only + // has one object, it has nothing else that needs to be kept alive. + if (next_key_index - i <= 1) { + i = next_key_index; + continue; + } + + Vector<v8::Persistent<v8::Value> > group; + group.reserveCapacity(next_key_index - i); + for (; i < next_key_index; ++i) { + v8::Persistent<v8::Value> wrapper = + getDOMNodeMap().get(grouper[i].second); + if (!wrapper.IsEmpty()) + group.append(wrapper); + } + + if (group.size() > 1) + v8::V8::AddObjectGroup(&group[0], group.size()); + + ASSERT(i == next_key_index); + } +} + + +static void GCEpilogue() +{ + v8::HandleScope scope; + + // Run through all objects with pending activity making their wrappers weak + // again. + DOMObjectMap active_map = getActiveDOMObjectMap().impl(); + for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end(); + it != end; ++it) { + void* obj = it->first; + v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>(it->second); + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: { \ + NAME* impl = static_cast<NAME*>(obj); \ + if (impl->hasPendingActivity()) { \ + ASSERT(!wrapper.IsWeak()); \ + wrapper.MakeWeak(impl, &weakActiveDOMObjectCallback); \ + } \ + break; \ + } +ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + default: + ASSERT(false); +#undef MAKE_CASE + } + } + +#ifndef NDEBUG + // Check all survivals are weak. + EnumerateDOMObjectMap(getDOMObjectMap().impl()); + EnumerateDOMNodeMap(getDOMNodeMap().impl()); + EnumerateDOMObjectMap(gc_protected_map()); + EnumerateGlobalHandles(); +#undef USE_VAR +#endif +} + + +typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap; + +bool AllowAllocation::m_current = false; + + +// JavaScriptConsoleMessages encapsulate everything needed to +// log messages originating from JavaScript to the Chrome console. +class JavaScriptConsoleMessage { + public: + JavaScriptConsoleMessage(const String& str, + const String& sourceID, + unsigned lineNumber) + : m_string(str) + , m_sourceID(sourceID) + , m_lineNumber(lineNumber) { } + + void AddToPage(Page* page) const; + + private: + const String m_string; + const String m_sourceID; + const unsigned m_lineNumber; +}; + +void JavaScriptConsoleMessage::AddToPage(Page* page) const +{ + ASSERT(page); + Console* console = page->mainFrame()->domWindow()->console(); + console->addMessage(JSMessageSource, ErrorMessageLevel, m_string, m_lineNumber, m_sourceID); +} + +// The ConsoleMessageManager handles all console messages that stem +// from JavaScript. It keeps a list of messages that have been delayed but +// it makes sure to add all messages to the console in the right order. +class ConsoleMessageManager { + public: + // Add a message to the console. May end up calling JavaScript code + // indirectly through the inspector so only call this function when + // it is safe to do allocations. + static void AddMessage(Page* page, const JavaScriptConsoleMessage& message); + + // Add a message to the console but delay the reporting until it + // is safe to do so: Either when we leave JavaScript execution or + // when adding other console messages. The primary purpose of this + // method is to avoid calling into V8 to handle console messages + // when the VM is in a state that does not support GCs or allocations. + // Delayed messages are always reported in the page corresponding + // to the active context. + static void AddDelayedMessage(const JavaScriptConsoleMessage& message); + + // Process any delayed messages. May end up calling JavaScript code + // indirectly through the inspector so only call this function when + // it is safe to do allocations. + static void ProcessDelayedMessages(); + + private: + // All delayed messages are stored in this vector. If the vector + // is NULL, there are no delayed messages. + static Vector<JavaScriptConsoleMessage>* m_delayed; +}; + + +Vector<JavaScriptConsoleMessage>* ConsoleMessageManager::m_delayed = NULL; + + +void ConsoleMessageManager::AddMessage( + Page* page, + const JavaScriptConsoleMessage& message) +{ + // Process any delayed messages to make sure that messages + // appear in the right order in the console. + ProcessDelayedMessages(); + message.AddToPage(page); +} + + +void ConsoleMessageManager::AddDelayedMessage(const JavaScriptConsoleMessage& message) +{ + if (!m_delayed) + // Allocate a vector for the delayed messages. Will be + // deallocated when the delayed messages are processed + // in ProcessDelayedMessages(). + m_delayed = new Vector<JavaScriptConsoleMessage>(); + m_delayed->append(message); +} + + +void ConsoleMessageManager::ProcessDelayedMessages() +{ + // If we have a delayed vector it cannot be empty. + if (!m_delayed) + return; + ASSERT(!m_delayed->isEmpty()); + + // Add the delayed messages to the page of the active + // context. If that for some bizarre reason does not + // exist, we clear the list of delayed messages to avoid + // posting messages. We still deallocate the vector. + Frame* frame = V8Proxy::retrieveActiveFrame(); + Page* page = NULL; + if (frame) + page = frame->page(); + if (!page) + m_delayed->clear(); + + // Iterate through all the delayed messages and add them + // to the console. + const int size = m_delayed->size(); + for (int i = 0; i < size; i++) { + m_delayed->at(i).AddToPage(page); + } + + // Deallocate the delayed vector. + delete m_delayed; + m_delayed = NULL; +} + + +// Convenience class for ensuring that delayed messages in the +// ConsoleMessageManager are processed quickly. +class ConsoleMessageScope { + public: + ConsoleMessageScope() { ConsoleMessageManager::ProcessDelayedMessages(); } + ~ConsoleMessageScope() { ConsoleMessageManager::ProcessDelayedMessages(); } +}; + +void log_info(Frame* frame, const String& msg, const String& url) +{ + Page* page = frame->page(); + if (!page) + return; + JavaScriptConsoleMessage message(msg, url, 0); + ConsoleMessageManager::AddMessage(page, message); +} + +static void HandleConsoleMessage(v8::Handle<v8::Message> message, + v8::Handle<v8::Value> data) +{ + // Use the frame where JavaScript is called from. + Frame* frame = V8Proxy::retrieveActiveFrame(); + if (!frame) + return; + + Page* page = frame->page(); + if (!page) + return; + + v8::Handle<v8::String> errorMessageString = message->Get(); + ASSERT(!errorMessageString.IsEmpty()); + String errorMessage = ToWebCoreString(errorMessageString); + + v8::Handle<v8::Value> resourceName = message->GetScriptResourceName(); + bool useURL = (resourceName.IsEmpty() || !resourceName->IsString()); + String resourceNameString = (useURL) + ? frame->document()->url() + : ToWebCoreString(resourceName); + JavaScriptConsoleMessage consoleMessage(errorMessage, + resourceNameString, + message->GetLineNumber()); + ConsoleMessageManager::AddMessage(page, consoleMessage); +} + + +enum DelayReporting { + REPORT_LATER, + REPORT_NOW +}; + + +static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) +{ + ASSERT(target); + Document* targetDocument = target->document(); + if (!targetDocument) + return; + + Frame* source = V8Proxy::retrieveActiveFrame(); + if (!source || !source->document()) + return; // Ignore error if the source document is gone. + + Document* sourceDocument = source->document(); + + // FIXME: This error message should contain more specifics of why the same + // origin check has failed. + String str = String::format("Unsafe JavaScript attempt to access frame " + "with URL %s from frame with URL %s. " + "Domains, protocols and ports must match.\n", + targetDocument->url().string().utf8().data(), + sourceDocument->url().string().utf8().data()); + + // Build a console message with fake source ID and line number. + const String kSourceID = ""; + const int kLineNumber = 1; + JavaScriptConsoleMessage message(str, kSourceID, kLineNumber); + + if (delay == REPORT_NOW) { + // NOTE(tc): Apple prints the message in the target page, but it seems like + // it should be in the source page. Even for delayed messages, we put it in + // the source page; see ConsoleMessageManager::ProcessDelayedMessages(). + ConsoleMessageManager::AddMessage(source->page(), message); + + } else { + ASSERT(delay == REPORT_LATER); + // We cannot safely report the message eagerly, because this may cause + // allocations and GCs internally in V8 and we cannot handle that at this + // point. Therefore we delay the reporting. + ConsoleMessageManager::AddDelayedMessage(message); + } +} + +static void ReportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, + v8::AccessType type, + v8::Local<v8::Value> data) +{ + Frame* target = V8Custom::GetTargetFrame(host, data); + if (target) + ReportUnsafeAccessTo(target, REPORT_LATER); +} + +static void HandleFatalErrorInV8() +{ + // TODO: We temporarily deal with V8 internal error situations + // such as out-of-memory by crashing the renderer. + CRASH(); +} + +static void ReportFatalErrorInV8(const char* location, const char* message) +{ + // V8 is shutdown, we cannot use V8 api. + // The only thing we can do is to disable JavaScript. + // TODO: clean up V8Proxy and disable JavaScript. + printf("V8 error: %s (%s)\n", message, location); + HandleFatalErrorInV8(); +} + +V8Proxy::~V8Proxy() +{ + clearForClose(); + DestroyGlobal(); +} + +void V8Proxy::DestroyGlobal() +{ + if (!m_global.IsEmpty()) { +#ifndef NDEBUG + UnregisterGlobalHandle(this, m_global); +#endif + m_global.Dispose(); + m_global.Clear(); + } +} + + +bool V8Proxy::DOMObjectHasJSWrapper(void* obj) { + return getDOMObjectMap().contains(obj) || + getActiveDOMObjectMap().contains(obj); +} + + +// The caller must have increased obj's ref count. +void V8Proxy::SetJSWrapperForDOMObject(void* obj, v8::Persistent<v8::Object> wrapper) +{ + ASSERT(MaybeDOMWrapper(wrapper)); +#ifndef NDEBUG + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: +ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + ASSERT(false); +#undef MAKE_CASE + default: break; + } +#endif + getDOMObjectMap().set(obj, wrapper); +} + +// The caller must have increased obj's ref count. +void V8Proxy::SetJSWrapperForActiveDOMObject(void* obj, v8::Persistent<v8::Object> wrapper) +{ + ASSERT(MaybeDOMWrapper(wrapper)); +#ifndef NDEBUG + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: break; +ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + default: ASSERT(false); +#undef MAKE_CASE + } +#endif + getActiveDOMObjectMap().set(obj, wrapper); +} + +// The caller must have increased node's ref count. +void V8Proxy::SetJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper) +{ + ASSERT(MaybeDOMWrapper(wrapper)); + getDOMNodeMap().set(node, wrapper); +} + +PassRefPtr<EventListener> V8Proxy::createInlineEventListener( + const String& functionName, + const String& code, Node* node) +{ + return V8LazyEventListener::create(m_frame, code, functionName); +} + +#if ENABLE(SVG) +PassRefPtr<EventListener> V8Proxy::createSVGEventHandler(const String& functionName, + const String& code, Node* node) +{ + return V8LazyEventListener::create(m_frame, code, functionName); +} +#endif + + +// Event listeners + +static V8EventListener* FindEventListenerInList(V8EventListenerList& list, + v8::Local<v8::Value> listener, + bool isInline) +{ + ASSERT(v8::Context::InContext()); + + if (!listener->IsObject()) + return 0; + + return list.find(listener->ToObject(), isInline); +} + +// Find an existing wrapper for a JS event listener in the map. +PassRefPtr<V8EventListener> V8Proxy::FindV8EventListener(v8::Local<v8::Value> listener, + bool isInline) +{ + return FindEventListenerInList(m_event_listeners, listener, isInline); +} + +PassRefPtr<V8EventListener> V8Proxy::FindOrCreateV8EventListener(v8::Local<v8::Value> obj, bool isInline) +{ + ASSERT(v8::Context::InContext()); + + if (!obj->IsObject()) + return 0; + + V8EventListener* wrapper = + FindEventListenerInList(m_event_listeners, obj, isInline); + if (wrapper) + return wrapper; + + // Create a new one, and add to cache. + RefPtr<V8EventListener> new_listener = + V8EventListener::create(m_frame, v8::Local<v8::Object>::Cast(obj), isInline); + m_event_listeners.add(new_listener.get()); + + return new_listener; +} + + +// Object event listeners (such as XmlHttpRequest and MessagePort) are +// different from listeners on DOM nodes. An object event listener wrapper +// only holds a weak reference to the JS function. A strong reference can +// create a cycle. +// +// The lifetime of these objects is bounded by the life time of its JS +// wrapper. So we can create a hidden reference from the JS wrapper to +// to its JS function. +// +// (map) +// XHR <---------- JS_wrapper +// | (hidden) : ^ +// V V : (may reachable by closure) +// V8_listener --------> JS_function +// (weak) <-- may create a cycle if it is strong +// +// The persistent reference is made weak in the constructor +// of V8ObjectEventListener. + +PassRefPtr<V8EventListener> V8Proxy::FindObjectEventListener( + v8::Local<v8::Value> listener, bool isInline) +{ + return FindEventListenerInList(m_xhr_listeners, listener, isInline); +} + + +PassRefPtr<V8EventListener> V8Proxy::FindOrCreateObjectEventListener( + v8::Local<v8::Value> obj, bool isInline) +{ + ASSERT(v8::Context::InContext()); + + if (!obj->IsObject()) + return 0; + + V8EventListener* wrapper = + FindEventListenerInList(m_xhr_listeners, obj, isInline); + if (wrapper) + return wrapper; + + // Create a new one, and add to cache. + RefPtr<V8EventListener> new_listener = + V8ObjectEventListener::create(m_frame, v8::Local<v8::Object>::Cast(obj), isInline); + m_xhr_listeners.add(new_listener.get()); + + return new_listener.release(); +} + + +static void RemoveEventListenerFromList(V8EventListenerList& list, + V8EventListener* listener) +{ + list.remove(listener); +} + + +void V8Proxy::RemoveV8EventListener(V8EventListener* listener) +{ + RemoveEventListenerFromList(m_event_listeners, listener); +} + + +void V8Proxy::RemoveObjectEventListener(V8ObjectEventListener* listener) +{ + RemoveEventListenerFromList(m_xhr_listeners, listener); +} + + +static void DisconnectEventListenersInList(V8EventListenerList& list) +{ + V8EventListenerList::iterator p = list.begin(); + while (p != list.end()) { + (*p)->disconnectFrame(); + ++p; + } + list.clear(); +} + + +void V8Proxy::DisconnectEventListeners() +{ + DisconnectEventListenersInList(m_event_listeners); + DisconnectEventListenersInList(m_xhr_listeners); +} + + +v8::Handle<v8::Script> V8Proxy::CompileScript(v8::Handle<v8::String> code, + const String& fileName, + int baseLine) +{ + const uint16_t* fileNameString = FromWebCoreString(fileName); + v8::Handle<v8::String> name = + v8::String::New(fileNameString, fileName.length()); + v8::Handle<v8::Integer> line = v8::Integer::New(baseLine); + v8::ScriptOrigin origin(name, line); + v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin); + return script; +} + +bool V8Proxy::HandleOutOfMemory() +{ + v8::Local<v8::Context> context = v8::Context::GetCurrent(); + + if (!context->HasOutOfMemoryException()) + return false; + + // Warning, error, disable JS for this frame? + Frame* frame = V8Proxy::retrieveFrame(context); + + V8Proxy* proxy = V8Proxy::retrieve(frame); + // Clean m_context, and event handlers. + proxy->clearForClose(); + // Destroy the global object. + proxy->DestroyGlobal(); + + ChromiumBridge::notifyJSOutOfMemory(frame); + + // Disable JS. + Settings* settings = frame->settings(); + ASSERT(settings); + settings->setJavaScriptEnabled(false); + + return true; +} + +void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources) +{ + InitContextIfNeeded(); + + v8::HandleScope handleScope; + + // Set up the DOM window as the prototype of the new global object. + v8::Handle<v8::Context> windowContext = m_context; + v8::Handle<v8::Object> windowGlobal = windowContext->Global(); + v8::Handle<v8::Value> windowWrapper = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, windowGlobal); + + ASSERT(V8Proxy::DOMWrapperToNative<DOMWindow>(windowWrapper) == + m_frame->domWindow()); + + v8::Persistent<v8::Context> context = + createNewContext(v8::Handle<v8::Object>()); + v8::Context::Scope context_scope(context); + v8::Handle<v8::Object> global = context->Global(); + + v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__"); + global->Set(implicitProtoString, windowWrapper); + + // Give the code running in the new context a way to get access to the + // original context. + global->Set(v8::String::New("contentWindow"), windowGlobal); + + // Run code in the new context. + for (size_t i = 0; i < sources.size(); ++i) + evaluate(sources[i], 0); + + // Using the default security token means that the canAccess is always + // called, which is slow. + // TODO(aa): Use tokens where possible. This will mean keeping track of all + // created contexts so that they can all be updated when the document domain + // changes. + context->UseDefaultSecurityToken(); + context.Dispose(); +} + +v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* n) +{ + ASSERT(v8::Context::InContext()); + + // Compile the script. + v8::Local<v8::String> code = v8ExternalString(source.source()); + ChromiumBridge::traceEventBegin("v8.compile", n, ""); + + // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at + // 1, whereas v8 starts at 0. + v8::Handle<v8::Script> script = CompileScript(code, source.url(), + source.startLine() - 1); + ChromiumBridge::traceEventEnd("v8.compile", n, ""); + + ChromiumBridge::traceEventBegin("v8.run", n, ""); + v8::Local<v8::Value> result; + { + // Isolate exceptions that occur when executing the code. These + // exceptions should not interfere with javascript code we might + // evaluate from C++ when returning from here + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + + // Set inlineCode to true for <a href="javascript:doSomething()"> + // and false for <script>doSomething</script>. We make a rough guess at + // this based on whether the script source has a URL. + result = RunScript(script, source.url().string().isNull()); + } + ChromiumBridge::traceEventEnd("v8.run", n, ""); + return result; +} + +v8::Local<v8::Value> V8Proxy::RunScript(v8::Handle<v8::Script> script, + bool inline_code) +{ + if (script.IsEmpty()) + return v8::Local<v8::Value>(); + + // Compute the source string and prevent against infinite recursion. + if (m_recursion >= kMaxRecursionDepth) { + v8::Local<v8::String> code = + v8ExternalString("throw RangeError('Recursion too deep')"); + // TODO(kasperl): Ideally, we should be able to re-use the origin of the + // script passed to us as the argument instead of using an empty string + // and 0 baseLine. + script = CompileScript(code, "", 0); + } + + if (HandleOutOfMemory()) + ASSERT(script.IsEmpty()); + + if (script.IsEmpty()) + return v8::Local<v8::Value>(); + + // Save the previous value of the inlineCode flag and update the flag for + // the duration of the script invocation. + bool previous_inline_code = inlineCode(); + setInlineCode(inline_code); + + // Run the script and keep track of the current recursion depth. + v8::Local<v8::Value> result; + { ConsoleMessageScope scope; + m_recursion++; + + // Evaluating the JavaScript could cause the frame to be deallocated, + // so we start the keep alive timer here. + // Frame::keepAlive method adds the ref count of the frame and sets a + // timer to decrease the ref count. It assumes that the current JavaScript + // execution finishs before firing the timer. + // See issue 1218756 and 914430. + m_frame->keepAlive(); + + result = script->Run(); + m_recursion--; + } + + if (HandleOutOfMemory()) + ASSERT(result.IsEmpty()); + + // Handle V8 internal error situation (Out-of-memory). + if (result.IsEmpty()) + return v8::Local<v8::Value>(); + + // Restore inlineCode flag. + setInlineCode(previous_inline_code); + + if (v8::V8::IsDead()) + HandleFatalErrorInV8(); + + return result; +} + + +v8::Local<v8::Value> V8Proxy::CallFunction(v8::Handle<v8::Function> function, + v8::Handle<v8::Object> receiver, + int argc, + v8::Handle<v8::Value> args[]) +{ + // For now, we don't put any artificial limitations on the depth + // of recursion that stems from calling functions. This is in + // contrast to the script evaluations. + v8::Local<v8::Value> result; + { + ConsoleMessageScope scope; + + // Evaluating the JavaScript could cause the frame to be deallocated, + // so we start the keep alive timer here. + // Frame::keepAlive method adds the ref count of the frame and sets a + // timer to decrease the ref count. It assumes that the current JavaScript + // execution finishs before firing the timer. + // See issue 1218756 and 914430. + m_frame->keepAlive(); + + result = function->Call(receiver, argc, args); + } + + if (v8::V8::IsDead()) + HandleFatalErrorInV8(); + + return result; +} + + +v8::Local<v8::Function> V8Proxy::GetConstructor(V8ClassIndex::V8WrapperType t){ + // A DOM constructor is a function instance created from a DOM constructor + // template. There is one instance per context. A DOM constructor is + // different from a normal function in two ways: + // 1) it cannot be called as constructor (aka, used to create a DOM object) + // 2) its __proto__ points to Object.prototype rather than + // Function.prototype. + // The reason for 2) is that, in Safari, a DOM constructor is a normal JS + // object, but not a function. Hotmail relies on the fact that, in Safari, + // HTMLElement.__proto__ == Object.prototype. + // + // m_object_prototype is a cache of the original Object.prototype. + + ASSERT(ContextInitialized()); + // Enter the context of the proxy to make sure that the + // function is constructed in the context corresponding to + // this proxy. + v8::Context::Scope scope(m_context); + v8::Handle<v8::FunctionTemplate> templ = GetTemplate(t); + // Getting the function might fail if we're running out of + // stack or memory. + v8::TryCatch try_catch; + v8::Local<v8::Function> value = templ->GetFunction(); + if (value.IsEmpty()) + return v8::Local<v8::Function>(); + // Hotmail fix, see comments above. + value->Set(v8::String::New("__proto__"), m_object_prototype); + return value; +} + + +v8::Local<v8::Object> V8Proxy::CreateWrapperFromCache(V8ClassIndex::V8WrapperType type) { + int class_index = V8ClassIndex::ToInt(type); + v8::Local<v8::Value> cached_object = + m_wrapper_boilerplates->Get(v8::Integer::New(class_index)); + if (cached_object->IsObject()) { + v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(cached_object); + return object->Clone(); + } + + // Not in cache. + InitContextIfNeeded(); + v8::Context::Scope scope(m_context); + v8::Local<v8::Function> function = GetConstructor(type); + v8::Local<v8::Object> instance = SafeAllocation::NewInstance(function); + if (!instance.IsEmpty()) { + m_wrapper_boilerplates->Set(v8::Integer::New(class_index), instance); + return instance->Clone(); + } + return v8::Local<v8::Object>(); +} + + +// Get the string 'toString'. +static v8::Persistent<v8::String> GetToStringName() { + static v8::Persistent<v8::String> value; + if (value.IsEmpty()) + value = v8::Persistent<v8::String>::New(v8::String::New("toString")); + return value; +} + + +static v8::Handle<v8::Value> ConstructorToString(const v8::Arguments& args) { + // The DOM constructors' toString functions grab the current toString + // for Functions by taking the toString function of itself and then + // calling it with the constructor as its receiver. This means that + // changes to the Function prototype chain or toString function are + // reflected when printing DOM constructors. The only wart is that + // changes to a DOM constructor's toString's toString will cause the + // toString of the DOM constructor itself to change. This is extremely + // obscure and unlikely to be a problem. + v8::Handle<v8::Value> val = args.Callee()->Get(GetToStringName()); + if (!val->IsFunction()) return v8::String::New(""); + return v8::Handle<v8::Function>::Cast(val)->Call(args.This(), 0, NULL); +} + + +v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( + V8ClassIndex::V8WrapperType type) +{ + v8::Persistent<v8::FunctionTemplate>* cache_cell = + V8ClassIndex::GetCache(type); + if (!(*cache_cell).IsEmpty()) + return *cache_cell; + + // not found + FunctionTemplateFactory factory = V8ClassIndex::GetFactory(type); + v8::Persistent<v8::FunctionTemplate> desc = factory(); + // DOM constructors are functions and should print themselves as such. + // However, we will later replace their prototypes with Object + // prototypes so we need to explicitly override toString on the + // instance itself. If we later make DOM constructors full objects + // we can give them class names instead and Object.prototype.toString + // will work so we can remove this code. + static v8::Persistent<v8::FunctionTemplate> to_string_template; + if (to_string_template.IsEmpty()) { + to_string_template = v8::Persistent<v8::FunctionTemplate>::New( + v8::FunctionTemplate::New(ConstructorToString)); + } + desc->Set(GetToStringName(), to_string_template); + switch (type) { + case V8ClassIndex::CSSSTYLEDECLARATION: + // The named property handler for style declarations has a + // setter. Therefore, the interceptor has to be on the object + // itself and not on the prototype object. + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(CSSStyleDeclaration), + USE_NAMED_PROPERTY_SETTER(CSSStyleDeclaration)); + setCollectionStringOrNullIndexedGetter<CSSStyleDeclaration>(desc); + break; + case V8ClassIndex::CSSRULELIST: + setCollectionIndexedGetter<CSSRuleList, CSSRule>(desc, + V8ClassIndex::CSSRULE); + break; + case V8ClassIndex::CSSVALUELIST: + setCollectionIndexedGetter<CSSValueList, CSSValue>( + desc, + V8ClassIndex::CSSVALUE); + break; + case V8ClassIndex::CSSVARIABLESDECLARATION: + setCollectionStringOrNullIndexedGetter<CSSVariablesDeclaration>(desc); + break; + case V8ClassIndex::WEBKITCSSTRANSFORMVALUE: + setCollectionIndexedGetter<WebKitCSSTransformValue, CSSValue>( + desc, + V8ClassIndex::CSSVALUE); + break; + case V8ClassIndex::UNDETECTABLEHTMLCOLLECTION: + desc->InstanceTemplate()->MarkAsUndetectable(); // fall through + case V8ClassIndex::HTMLCOLLECTION: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLCollection)); + desc->InstanceTemplate()->SetCallAsFunctionHandler( + USE_CALLBACK(HTMLCollectionCallAsFunction)); + setCollectionIndexedGetter<HTMLCollection, Node>(desc, + V8ClassIndex::NODE); + break; + case V8ClassIndex::HTMLOPTIONSCOLLECTION: + setCollectionNamedGetter<HTMLOptionsCollection, Node>( + desc, + V8ClassIndex::NODE); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(HTMLOptionsCollection), + USE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection)); + desc->InstanceTemplate()->SetCallAsFunctionHandler( + USE_CALLBACK(HTMLCollectionCallAsFunction)); + break; + case V8ClassIndex::HTMLSELECTELEMENT: + desc->InstanceTemplate()->SetNamedPropertyHandler( + nodeCollectionNamedPropertyGetter<HTMLSelectElement>, + 0, + 0, + 0, + 0, + v8::Integer::New(V8ClassIndex::NODE)); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + nodeCollectionIndexedPropertyGetter<HTMLSelectElement>, + USE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection), + 0, + 0, + nodeCollectionIndexedPropertyEnumerator<HTMLSelectElement>, + v8::Integer::New(V8ClassIndex::NODE)); + break; + case V8ClassIndex::HTMLDOCUMENT: { + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLDocument), + 0, + 0, + USE_NAMED_PROPERTY_DELETER(HTMLDocument)); + + // We add an extra internal field to all Document wrappers for + // storing a per document DOMImplementation wrapper. + // + // Additionally, we add two extra internal fields for + // HTMLDocuments to implement temporary shadowing of + // document.all. One field holds an object that is used as a + // marker. The other field holds the marker object if + // document.all is not shadowed and some other value if + // document.all is shadowed. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + ASSERT(instance_template->InternalFieldCount() == + V8Custom::kDefaultWrapperInternalFieldCount); + instance_template->SetInternalFieldCount( + V8Custom::kHTMLDocumentInternalFieldCount); + break; + } +#if ENABLE(SVG) + case V8ClassIndex::SVGDOCUMENT: // fall through +#endif + case V8ClassIndex::DOCUMENT: { + // We add an extra internal field to all Document wrappers for + // storing a per document DOMImplementation wrapper. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + ASSERT(instance_template->InternalFieldCount() == + V8Custom::kDefaultWrapperInternalFieldCount); + instance_template->SetInternalFieldCount( + V8Custom::kDocumentMinimumInternalFieldCount); + break; + } + case V8ClassIndex::HTMLAPPLETELEMENT: // fall through + case V8ClassIndex::HTMLEMBEDELEMENT: // fall through + case V8ClassIndex::HTMLOBJECTELEMENT: + // HTMLAppletElement, HTMLEmbedElement and HTMLObjectElement are + // inherited from HTMLPlugInElement, and they share the same property + // handling code. + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLPlugInElement), + USE_NAMED_PROPERTY_SETTER(HTMLPlugInElement)); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(HTMLPlugInElement), + USE_INDEXED_PROPERTY_SETTER(HTMLPlugInElement)); + desc->InstanceTemplate()->SetCallAsFunctionHandler( + USE_CALLBACK(HTMLPlugInElement)); + break; + case V8ClassIndex::HTMLFRAMESETELEMENT: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLFrameSetElement)); + break; + case V8ClassIndex::HTMLFORMELEMENT: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLFormElement)); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(HTMLFormElement), + 0, + 0, + 0, + nodeCollectionIndexedPropertyEnumerator<HTMLFormElement>, + v8::Integer::New(V8ClassIndex::NODE)); + break; + case V8ClassIndex::CANVASPIXELARRAY: + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(CanvasPixelArray), + USE_INDEXED_PROPERTY_SETTER(CanvasPixelArray)); + break; + case V8ClassIndex::STYLESHEET: // fall through + case V8ClassIndex::CSSSTYLESHEET: { + // We add an extra internal field to hold a reference to + // the owner node. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + ASSERT(instance_template->InternalFieldCount() == + V8Custom::kDefaultWrapperInternalFieldCount); + instance_template->SetInternalFieldCount( + V8Custom::kStyleSheetInternalFieldCount); + break; + } + case V8ClassIndex::MEDIALIST: + setCollectionStringOrNullIndexedGetter<MediaList>(desc); + break; + case V8ClassIndex::MIMETYPEARRAY: + setCollectionIndexedAndNamedGetters<MimeTypeArray, MimeType>( + desc, + V8ClassIndex::MIMETYPE); + break; + case V8ClassIndex::NAMEDNODEMAP: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(NamedNodeMap)); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(NamedNodeMap), + 0, + 0, + 0, + collectionIndexedPropertyEnumerator<NamedNodeMap>, + v8::Integer::New(V8ClassIndex::NODE)); + break; + case V8ClassIndex::NODELIST: + setCollectionIndexedGetter<NodeList, Node>(desc, V8ClassIndex::NODE); + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(NodeList)); + break; + case V8ClassIndex::PLUGIN: + setCollectionIndexedAndNamedGetters<Plugin, MimeType>( + desc, + V8ClassIndex::MIMETYPE); + break; + case V8ClassIndex::PLUGINARRAY: + setCollectionIndexedAndNamedGetters<PluginArray, Plugin>( + desc, + V8ClassIndex::PLUGIN); + break; + case V8ClassIndex::STYLESHEETLIST: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(StyleSheetList)); + setCollectionIndexedGetter<StyleSheetList, StyleSheet>( + desc, + V8ClassIndex::STYLESHEET); + break; + case V8ClassIndex::DOMWINDOW: { + v8::Local<v8::Signature> default_signature = v8::Signature::New(desc); + + desc->PrototypeTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(DOMWindow)); + desc->PrototypeTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(DOMWindow)); + + desc->SetHiddenPrototype(true); + + // Reserve spaces for references to location, history and + // navigator objects. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kDOMWindowInternalFieldCount); + + // Set access check callbacks, but turned off initially. + // When a context is detached from a frame, turn on the access check. + // Turning on checks also invalidates inline caches of the object. + instance_template->SetAccessCheckCallbacks( + V8Custom::v8DOMWindowNamedSecurityCheck, + V8Custom::v8DOMWindowIndexedSecurityCheck, + v8::Integer::New(V8ClassIndex::DOMWINDOW), + false); + break; + } + case V8ClassIndex::LOCATION: { + // For security reasons, these functions are on the instance + // instead of on the prototype object to insure that they cannot + // be overwritten. + v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate(); + instance->SetAccessor( + v8::String::New("reload"), + V8Custom::v8LocationReloadAccessorGetter, + 0, + v8::Handle<v8::Value>(), + v8::ALL_CAN_READ, + static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly)); + + instance->SetAccessor( + v8::String::New("replace"), + V8Custom::v8LocationReplaceAccessorGetter, + 0, + v8::Handle<v8::Value>(), + v8::ALL_CAN_READ, + static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly)); + + instance->SetAccessor( + v8::String::New("assign"), + V8Custom::v8LocationAssignAccessorGetter, + 0, + v8::Handle<v8::Value>(), + v8::ALL_CAN_READ, + static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly)); + break; + } + case V8ClassIndex::HISTORY: { + break; + } + + case V8ClassIndex::MESSAGECHANNEL: { + // Reserve two more internal fields for referencing the port1 + // and port2 wrappers. This ensures that the port wrappers are + // kept alive when the channel wrapper is. + desc->SetCallHandler(USE_CALLBACK(MessageChannelConstructor)); + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kMessageChannelInternalFieldCount); + break; + } + + case V8ClassIndex::MESSAGEPORT: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kMessagePortInternalFieldCount); + break; + } + +#if ENABLE(WORKERS) + case V8ClassIndex::WORKER: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kWorkerInternalFieldCount); + desc->SetCallHandler(USE_CALLBACK(WorkerConstructor)); + break; + } + + case V8ClassIndex::WORKERCONTEXT: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kWorkerContextInternalFieldCount); + break; + } +#endif // WORKERS + + + // The following objects are created from JavaScript. + case V8ClassIndex::DOMPARSER: + desc->SetCallHandler(USE_CALLBACK(DOMParserConstructor)); + break; + case V8ClassIndex::WEBKITCSSMATRIX: + desc->SetCallHandler(USE_CALLBACK(WebKitCSSMatrixConstructor)); + break; + case V8ClassIndex::WEBKITPOINT: + desc->SetCallHandler(USE_CALLBACK(WebKitPointConstructor)); + break; + case V8ClassIndex::XMLSERIALIZER: + desc->SetCallHandler(USE_CALLBACK(XMLSerializerConstructor)); + break; + case V8ClassIndex::XMLHTTPREQUEST: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kXMLHttpRequestInternalFieldCount); + desc->SetCallHandler(USE_CALLBACK(XMLHttpRequestConstructor)); + break; + } + case V8ClassIndex::XMLHTTPREQUESTUPLOAD: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kXMLHttpRequestInternalFieldCount); + break; + } + case V8ClassIndex::XPATHEVALUATOR: + desc->SetCallHandler(USE_CALLBACK(XPathEvaluatorConstructor)); + break; + case V8ClassIndex::XSLTPROCESSOR: + desc->SetCallHandler(USE_CALLBACK(XSLTProcessorConstructor)); + break; + default: + break; + } + + *cache_cell = desc; + return desc; +} + + +bool V8Proxy::ContextInitialized() +{ + // m_context, m_global, m_object_prototype and m_wrapper_boilerplates should + // all be non-empty if if m_context is non-empty. + ASSERT(m_context.IsEmpty() || !m_global.IsEmpty()); + ASSERT(m_context.IsEmpty() || !m_object_prototype.IsEmpty()); + ASSERT(m_context.IsEmpty() || !m_wrapper_boilerplates.IsEmpty()); + return !m_context.IsEmpty(); +} + + +DOMWindow* V8Proxy::retrieveWindow() +{ + // TODO: This seems very fragile. How do we know that the global object + // from the current context is something sensible? Do we need to use the + // last entered here? Who calls this? + return retrieveWindow(v8::Context::GetCurrent()); +} + + +DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context) +{ + v8::Handle<v8::Object> global = context->Global(); + ASSERT(!global.IsEmpty()); + global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); + ASSERT(!global.IsEmpty()); + return ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, global); +} + + +Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context) +{ + return retrieveWindow(context)->frame(); +} + + +Frame* V8Proxy::retrieveActiveFrame() +{ + v8::Handle<v8::Context> context = v8::Context::GetEntered(); + if (context.IsEmpty()) + return 0; + return retrieveFrame(context); +} + + +Frame* V8Proxy::retrieveFrame() +{ + DOMWindow* window = retrieveWindow(); + return window ? window->frame() : 0; +} + + +V8Proxy* V8Proxy::retrieve() +{ + DOMWindow* window = retrieveWindow(); + ASSERT(window); + return retrieve(window->frame()); +} + +V8Proxy* V8Proxy::retrieve(Frame* frame) +{ + if (!frame) + return 0; + return frame->script()->isEnabled() ? frame->script()->proxy() : 0; +} + + +V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context) +{ + if (!context->isDocument()) + return 0; + return retrieve(static_cast<Document*>(context)->frame()); +} + + +void V8Proxy::disconnectFrame() +{ + // disconnect all event listeners + DisconnectEventListeners(); +} + + +bool V8Proxy::isEnabled() +{ + Settings* settings = m_frame->settings(); + if (!settings) + return false; + + // In the common case, JavaScript is enabled and we're done. + if (settings->isJavaScriptEnabled()) + return true; + + // If JavaScript has been disabled, we need to look at the frame to tell + // whether this script came from the web or the embedder. Scripts from the + // embedder are safe to run, but scripts from the other sources are + // disallowed. + Document* document = m_frame->document(); + if (!document) + return false; + + SecurityOrigin* origin = document->securityOrigin(); + if (origin->protocol().isEmpty()) + return false; // Uninitialized document + + if (origin->protocol() == "http" || origin->protocol() == "https") + return false; // Web site + + // TODO(darin): the following are application decisions, and they should + // not be made at this layer. instead, we should bridge out to the + // embedder to allow them to override policy here. + + if (origin->protocol() == ChromiumBridge::uiResourceProtocol()) + return true; // Embedder's scripts are ok to run + + // If the scheme is ftp: or file:, an empty file name indicates a directory + // listing, which requires JavaScript to function properly. + const char* kDirProtocols[] = { "ftp", "file" }; + for (size_t i = 0; i < arraysize(kDirProtocols); ++i) { + if (origin->protocol() == kDirProtocols[i]) { + const KURL& url = document->url(); + return url.pathAfterLastSlash() == url.pathEnd(); + } + } + + return false; // Other protocols fall through to here +} + + +void V8Proxy::UpdateDocumentWrapper(v8::Handle<v8::Value> wrapper) { + ClearDocumentWrapper(); + + ASSERT(m_document.IsEmpty()); + m_document = v8::Persistent<v8::Value>::New(wrapper); +#ifndef NDEBUG + RegisterGlobalHandle(PROXY, this, m_document); +#endif +} + + +void V8Proxy::ClearDocumentWrapper() +{ + if (!m_document.IsEmpty()) { +#ifndef NDEBUG + UnregisterGlobalHandle(this, m_document); +#endif + m_document.Dispose(); + m_document.Clear(); + } +} + + +void V8Proxy::DisposeContextHandles() { + if (!m_context.IsEmpty()) { + m_context.Dispose(); + m_context.Clear(); + } + + if (!m_wrapper_boilerplates.IsEmpty()) { +#ifndef NDEBUG + UnregisterGlobalHandle(this, m_wrapper_boilerplates); +#endif + m_wrapper_boilerplates.Dispose(); + m_wrapper_boilerplates.Clear(); + } + + if (!m_object_prototype.IsEmpty()) { +#ifndef NDEBUG + UnregisterGlobalHandle(this, m_object_prototype); +#endif + m_object_prototype.Dispose(); + m_object_prototype.Clear(); + } +} + +void V8Proxy::clearForClose() +{ + if (!m_context.IsEmpty()) { + v8::HandleScope handle_scope; + + ClearDocumentWrapper(); + DisposeContextHandles(); + } +} + + +void V8Proxy::clearForNavigation() +{ + if (!m_context.IsEmpty()) { + v8::HandleScope handle; + ClearDocumentWrapper(); + + v8::Context::Scope context_scope(m_context); + + // Turn on access check on the old DOMWindow wrapper. + v8::Handle<v8::Object> wrapper = + LookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global); + ASSERT(!wrapper.IsEmpty()); + wrapper->TurnOnAccessCheck(); + + // disconnect all event listeners + DisconnectEventListeners(); + + // Separate the context from its global object. + m_context->DetachGlobal(); + + DisposeContextHandles(); + + // Reinitialize the context so the global object points to + // the new DOM window. + InitContextIfNeeded(); + } +} + + +void V8Proxy::SetSecurityToken() { + Document* document = m_frame->document(); + // Setup security origin and security token + if (!document) { + m_context->UseDefaultSecurityToken(); + return; + } + + // Ask the document's SecurityOrigin to generate a security token. + // If two tokens are equal, then the SecurityOrigins canAccess each other. + // If two tokens are not equal, then we have to call canAccess. + // Note: we can't use the HTTPOrigin if it was set from the DOM. + SecurityOrigin* origin = document->securityOrigin(); + String token; + if (!origin->domainWasSetInDOM()) + token = document->securityOrigin()->toString(); + + // An empty or "null" token means we always have to call + // canAccess. The toString method on securityOrigins returns the + // string "null" for empty security origins and for security + // origins that should only allow access to themselves. In this + // case, we use the global object as the security token to avoid + // calling canAccess when a script accesses its own objects. + if (token.isEmpty() || token == "null") { + m_context->UseDefaultSecurityToken(); + return; + } + + CString utf8_token = token.utf8(); + // NOTE: V8 does identity comparison in fast path, must use a symbol + // as the security token. + m_context->SetSecurityToken( + v8::String::NewSymbol(utf8_token.data(), utf8_token.length())); +} + + +void V8Proxy::updateDocument() +{ + if (!m_frame->document()) + return; + + if (m_global.IsEmpty()) { + ASSERT(m_context.IsEmpty()); + return; + } + + { + v8::HandleScope scope; + SetSecurityToken(); + } +} + +void V8Proxy::updateSecurityOrigin() +{ + v8::HandleScope scope; + SetSecurityToken(); +} + +// Same origin policy implementation: +// +// Same origin policy prevents JS code from domain A access JS & DOM objects +// in a different domain B. There are exceptions and several objects are +// accessible by cross-domain code. For example, the window.frames object is +// accessible by code from a different domain, but window.document is not. +// +// The binding code sets security check callbacks on a function template, +// and accessing instances of the template calls the callback function. +// The callback function checks same origin policy. +// +// Callback functions are expensive. V8 uses a security token string to do +// fast access checks for the common case where source and target are in the +// same domain. A security token is a string object that represents +// the protocol/url/port of a domain. +// +// There are special cases where a security token matching is not enough. +// For example, JavaScript can set its domain to a super domain by calling +// document.setDomain(...). In these cases, the binding code can reset +// a context's security token to its global object so that the fast access +// check will always fail. + +// Check if the current execution context can access a target frame. +// First it checks same domain policy using the lexical context +// +// This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&). +bool V8Proxy::CanAccessPrivate(DOMWindow* target_window) +{ + ASSERT(target_window); + + String message; + + DOMWindow* origin_window = retrieveWindow(); + if (origin_window == target_window) + return true; + + if (!origin_window) + return false; + + // JS may be attempting to access the "window" object, which should be + // valid, even if the document hasn't been constructed yet. + // If the document doesn't exist yet allow JS to access the window object. + if (!origin_window->document()) + return true; + + const SecurityOrigin* active_security_origin = origin_window->securityOrigin(); + const SecurityOrigin* target_security_origin = target_window->securityOrigin(); + + // We have seen crashes were the security origin of the target has not been + // initialized. Defend against that. + ASSERT(target_security_origin); + if (!target_security_origin) + return false; + + if (active_security_origin->canAccess(target_security_origin)) + return true; + + // Allow access to a "about:blank" page if the dynamic context is a + // detached context of the same frame as the blank page. + if (target_security_origin->isEmpty() && + origin_window->frame() == target_window->frame()) + return true; + + return false; +} + + +bool V8Proxy::CanAccessFrame(Frame* target, bool report_error) +{ + // The subject is detached from a frame, deny accesses. + if (!target) + return false; + + if (!CanAccessPrivate(target->domWindow())) { + if (report_error) + ReportUnsafeAccessTo(target, REPORT_NOW); + return false; + } + return true; +} + + +bool V8Proxy::CheckNodeSecurity(Node* node) +{ + if (!node) + return false; + + Frame* target = node->document()->frame(); + + if (!target) + return false; + + return CanAccessFrame(target, true); +} + +v8::Persistent<v8::Context> V8Proxy::createNewContext( + v8::Handle<v8::Object> global) +{ + v8::Persistent<v8::Context> result; + + // Create a new environment using an empty template for the shadow + // object. Reuse the global object if one has been created earlier. + v8::Persistent<v8::ObjectTemplate> globalTemplate = + V8DOMWindow::GetShadowObjectTemplate(); + if (globalTemplate.IsEmpty()) + return result; + + // Install a security handler with V8. + globalTemplate->SetAccessCheckCallbacks( + V8Custom::v8DOMWindowNamedSecurityCheck, + V8Custom::v8DOMWindowIndexedSecurityCheck, + v8::Integer::New(V8ClassIndex::DOMWINDOW)); + + // Dynamically tell v8 about our extensions now. + const char** extensionNames = new const char*[m_extensions.size()]; + int index = 0; + for (V8ExtensionList::iterator it = m_extensions.begin(); + it != m_extensions.end(); ++it) { + if (it->scheme.length() > 0 && + it->scheme != m_frame->document()->url().protocol()) + continue; + + extensionNames[index++] = it->extension->name(); + } + v8::ExtensionConfiguration extensions(index, extensionNames); + result = v8::Context::New(&extensions, globalTemplate, global); + delete [] extensionNames; + extensionNames = 0; + + return result; +} + +// Create a new environment and setup the global object. +// +// The global object corresponds to a DOMWindow instance. However, to +// allow properties of the JS DOMWindow instance to be shadowed, we +// use a shadow object as the global object and use the JS DOMWindow +// instance as the prototype for that shadow object. The JS DOMWindow +// instance is undetectable from javascript code because the __proto__ +// accessors skip that object. +// +// The shadow object and the DOMWindow instance are seen as one object +// from javascript. The javascript object that corresponds to a +// DOMWindow instance is the shadow object. When mapping a DOMWindow +// instance to a V8 object, we return the shadow object. +// +// To implement split-window, see +// 1) https://bugs.webkit.org/show_bug.cgi?id=17249 +// 2) https://wiki.mozilla.org/Gecko:SplitWindow +// 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639 +// we need to split the shadow object further into two objects: +// an outer window and an inner window. The inner window is the hidden +// prototype of the outer window. The inner window is the default +// global object of the context. A variable declared in the global +// scope is a property of the inner window. +// +// The outer window sticks to a Frame, it is exposed to JavaScript +// via window.window, window.self, window.parent, etc. The outer window +// has a security token which is the domain. The outer window cannot +// have its own properties. window.foo = 'x' is delegated to the +// inner window. +// +// When a frame navigates to a new page, the inner window is cut off +// the outer window, and the outer window identify is preserved for +// the frame. However, a new inner window is created for the new page. +// If there are JS code holds a closure to the old inner window, +// it won't be able to reach the outer window via its global object. +void V8Proxy::InitContextIfNeeded() +{ + // Bail out if the context has already been initialized. + if (!m_context.IsEmpty()) + return; + + // Create a handle scope for all local handles. + v8::HandleScope handle_scope; + + // Setup the security handlers and message listener. This only has + // to be done once. + static bool v8_initialized = false; + if (!v8_initialized) { + // Tells V8 not to call the default OOM handler, binding code + // will handle it. + v8::V8::IgnoreOutOfMemoryException(); + v8::V8::SetFatalErrorHandler(ReportFatalErrorInV8); + + v8::V8::SetGlobalGCPrologueCallback(&GCPrologue); + v8::V8::SetGlobalGCEpilogueCallback(&GCEpilogue); + + v8::V8::AddMessageListener(HandleConsoleMessage); + + v8::V8::SetFailedAccessCheckCallbackFunction(ReportUnsafeJavaScriptAccess); + + v8_initialized = true; + } + + m_context = createNewContext(m_global); + if (m_context.IsEmpty()) + return; + + // Starting from now, use local context only. + v8::Local<v8::Context> context = GetContext(); + v8::Context::Scope context_scope(context); + + // Store the first global object created so we can reuse it. + if (m_global.IsEmpty()) { + m_global = v8::Persistent<v8::Object>::New(context->Global()); + // Bail out if allocation of the first global objects fails. + if (m_global.IsEmpty()) { + DisposeContextHandles(); + return; + } +#ifndef NDEBUG + RegisterGlobalHandle(PROXY, this, m_global); +#endif + } + + // Allocate strings used during initialization. + v8::Handle<v8::String> object_string = v8::String::New("Object"); + v8::Handle<v8::String> prototype_string = v8::String::New("prototype"); + v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__"); + // Bail out if allocation failed. + if (object_string.IsEmpty() || + prototype_string.IsEmpty() || + implicit_proto_string.IsEmpty()) { + DisposeContextHandles(); + return; + } + + // Allocate clone cache and pre-allocated objects + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast( + m_global->Get(object_string)); + m_object_prototype = v8::Persistent<v8::Value>::New( + object->Get(prototype_string)); + m_wrapper_boilerplates = v8::Persistent<v8::Array>::New( + v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT)); + // Bail out if allocation failed. + if (m_object_prototype.IsEmpty()) { + DisposeContextHandles(); + return; + } +#ifndef NDEBUG + RegisterGlobalHandle(PROXY, this, m_object_prototype); + RegisterGlobalHandle(PROXY, this, m_wrapper_boilerplates); +#endif + + // Create a new JS window object and use it as the prototype for the + // shadow global object. + v8::Handle<v8::Function> window_constructor = + GetConstructor(V8ClassIndex::DOMWINDOW); + v8::Local<v8::Object> js_window = + SafeAllocation::NewInstance(window_constructor); + // Bail out if allocation failed. + if (js_window.IsEmpty()) { + DisposeContextHandles(); + return; + } + + DOMWindow* window = m_frame->domWindow(); + + // Wrap the window. + SetDOMWrapper(js_window, + V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), + window); + + window->ref(); + V8Proxy::SetJSWrapperForDOMObject(window, + v8::Persistent<v8::Object>::New(js_window)); + + // Insert the window instance as the prototype of the shadow object. + v8::Handle<v8::Object> v8_global = context->Global(); + v8_global->Set(implicit_proto_string, js_window); + + SetSecurityToken(); + + m_frame->loader()->dispatchWindowObjectAvailable(); +} + + +void V8Proxy::SetDOMException(int exception_code) +{ + if (exception_code <= 0) + return; + + ExceptionCodeDescription description; + getExceptionCodeDescription(exception_code, description); + + v8::Handle<v8::Value> exception; + switch (description.type) { + case DOMExceptionType: + exception = ToV8Object(V8ClassIndex::DOMCOREEXCEPTION, + DOMCoreException::create(description)); + break; + case RangeExceptionType: + exception = ToV8Object(V8ClassIndex::RANGEEXCEPTION, + RangeException::create(description)); + break; + case EventExceptionType: + exception = ToV8Object(V8ClassIndex::EVENTEXCEPTION, + EventException::create(description)); + break; + case XMLHttpRequestExceptionType: + exception = ToV8Object(V8ClassIndex::XMLHTTPREQUESTEXCEPTION, + XMLHttpRequestException::create(description)); + break; +#if ENABLE(SVG) + case SVGExceptionType: + exception = ToV8Object(V8ClassIndex::SVGEXCEPTION, + SVGException::create(description)); + break; +#endif +#if ENABLE(XPATH) + case XPathExceptionType: + exception = ToV8Object(V8ClassIndex::XPATHEXCEPTION, + XPathException::create(description)); + break; +#endif + } + + ASSERT(!exception.IsEmpty()); + v8::ThrowException(exception); +} + +v8::Handle<v8::Value> V8Proxy::ThrowError(ErrorType type, const char* message) +{ + switch (type) { + case RANGE_ERROR: + return v8::ThrowException(v8::Exception::RangeError(v8String(message))); + case REFERENCE_ERROR: + return v8::ThrowException( + v8::Exception::ReferenceError(v8String(message))); + case SYNTAX_ERROR: + return v8::ThrowException(v8::Exception::SyntaxError(v8String(message))); + case TYPE_ERROR: + return v8::ThrowException(v8::Exception::TypeError(v8String(message))); + case GENERAL_ERROR: + return v8::ThrowException(v8::Exception::Error(v8String(message))); + default: + ASSERT(false); + return v8::Handle<v8::Value>(); + } +} + +v8::Local<v8::Context> V8Proxy::GetContext(Frame* frame) +{ + V8Proxy* proxy = retrieve(frame); + if (!proxy) + return v8::Local<v8::Context>(); + + proxy->InitContextIfNeeded(); + return proxy->GetContext(); +} + +v8::Local<v8::Context> V8Proxy::GetCurrentContext() +{ + return v8::Context::GetCurrent(); +} + +v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, void* imp) +{ + ASSERT(type != V8ClassIndex::EVENTLISTENER); + ASSERT(type != V8ClassIndex::EVENTTARGET); + ASSERT(type != V8ClassIndex::EVENT); + + bool is_active_dom_object = false; + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: + DOM_NODE_TYPES(MAKE_CASE) +#if ENABLE(SVG) + SVG_NODE_TYPES(MAKE_CASE) +#endif + return NodeToV8Object(static_cast<Node*>(imp)); + case V8ClassIndex::CSSVALUE: + return CSSValueToV8Object(static_cast<CSSValue*>(imp)); + case V8ClassIndex::CSSRULE: + return CSSRuleToV8Object(static_cast<CSSRule*>(imp)); + case V8ClassIndex::STYLESHEET: + return StyleSheetToV8Object(static_cast<StyleSheet*>(imp)); + case V8ClassIndex::DOMWINDOW: + return WindowToV8Object(static_cast<DOMWindow*>(imp)); +#if ENABLE(SVG) + SVG_NONNODE_TYPES(MAKE_CASE) + if (type == V8ClassIndex::SVGELEMENTINSTANCE) + return SVGElementInstanceToV8Object(static_cast<SVGElementInstance*>(imp)); + return SVGObjectWithContextToV8Object(type, imp); +#endif + + ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + is_active_dom_object = true; + break; + default: + break; + } + +#undef MAKE_CASE + + if (!imp) return v8::Null(); + + // Non DOM node + v8::Persistent<v8::Object> result = is_active_dom_object ? + getActiveDOMObjectMap().get(imp) : + getDOMObjectMap().get(imp); + if (result.IsEmpty()) { + v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, imp); + if (!v8obj.IsEmpty()) { + // Go through big switch statement, it has some duplications + // that were handled by code above (such as CSSVALUE, CSSRULE, etc). + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(imp)->ref(); break; + DOM_OBJECT_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: + ASSERT(false); + } + result = v8::Persistent<v8::Object>::New(v8obj); + if (is_active_dom_object) + SetJSWrapperForActiveDOMObject(imp, result); + else + SetJSWrapperForDOMObject(imp, result); + + // Special case for non-node objects History, Location and + // Navigator. Both Safari and FF let Location and Navigator JS + // wrappers survive GC. To mimic their behaviors, V8 creates + // hidden references from the DOMWindow to these wrapper + // objects. These references get cleared when the DOMWindow is + // reused by a new page. + switch (type) { + case V8ClassIndex::HISTORY: + SetHiddenWindowReference(static_cast<History*>(imp)->frame(), + V8Custom::kDOMWindowHistoryIndex, result); + break; + case V8ClassIndex::NAVIGATOR: + SetHiddenWindowReference(static_cast<Navigator*>(imp)->frame(), + V8Custom::kDOMWindowNavigatorIndex, result); + break; + case V8ClassIndex::LOCATION: + SetHiddenWindowReference(static_cast<Location*>(imp)->frame(), + V8Custom::kDOMWindowLocationIndex, result); + break; + default: + break; + } + } + } + return result; +} + + +void V8Proxy::SetHiddenWindowReference(Frame* frame, + const int internal_index, + v8::Handle<v8::Object> jsobj) +{ + // Get DOMWindow + if (!frame) return; // Object might be detached from window + v8::Handle<v8::Context> context = GetContext(frame); + if (context.IsEmpty()) return; + + ASSERT(internal_index < V8Custom::kDOMWindowInternalFieldCount); + + v8::Handle<v8::Object> global = context->Global(); + // Look for real DOM wrapper. + global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); + ASSERT(!global.IsEmpty()); + ASSERT(global->GetInternalField(internal_index)->IsUndefined()); + global->SetInternalField(internal_index, jsobj); +} + + +V8ClassIndex::V8WrapperType V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object> object) +{ + ASSERT(MaybeDOMWrapper(object)); + v8::Handle<v8::Value> type = + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex); + return V8ClassIndex::FromInt(type->Int32Value()); +} + + +void* V8Proxy::ToNativeObjectImpl(V8ClassIndex::V8WrapperType type, + v8::Handle<v8::Value> object) +{ + // Native event listener is per frame, it cannot be handled + // by this generic function. + ASSERT(type != V8ClassIndex::EVENTLISTENER); + ASSERT(type != V8ClassIndex::EVENTTARGET); + + ASSERT(MaybeDOMWrapper(object)); + + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: + DOM_NODE_TYPES(MAKE_CASE) +#if ENABLE(SVG) + SVG_NODE_TYPES(MAKE_CASE) +#endif + ASSERT(false); + return NULL; + case V8ClassIndex::XMLHTTPREQUEST: + return DOMWrapperToNative<XMLHttpRequest>(object); + case V8ClassIndex::EVENT: + return DOMWrapperToNative<Event>(object); + case V8ClassIndex::CSSRULE: + return DOMWrapperToNative<CSSRule>(object); + default: + break; + } +#undef MAKE_CASE + + return DOMWrapperToNative<void>(object); +} + +v8::Handle<v8::Object> V8Proxy::LookupDOMWrapper( + V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> value) +{ + if (value.IsEmpty()) + return v8::Handle<v8::Object>(); + + v8::Handle<v8::FunctionTemplate> desc = V8Proxy::GetTemplate(type); + while (value->IsObject()) { + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); + if (desc->HasInstance(object)) + return object; + + value = object->GetPrototype(); + } + return v8::Handle<v8::Object>(); +} + + +PassRefPtr<NodeFilter> V8Proxy::ToNativeNodeFilter(v8::Handle<v8::Value> filter) +{ + // A NodeFilter is used when walking through a DOM tree or iterating tree + // nodes. + // TODO: we may want to cache NodeFilterCondition and NodeFilter + // object, but it is minor. + // NodeFilter is passed to NodeIterator that has a ref counted pointer + // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition. + // In NodeFilterCondition, filter object is persisted in its constructor, + // and disposed in its destructor. + if (!filter->IsFunction()) + return 0; + + NodeFilterCondition* cond = new V8NodeFilterCondition(filter); + return NodeFilter::create(cond); +} + + +v8::Local<v8::Object> V8Proxy::InstantiateV8Object( + V8ClassIndex::V8WrapperType desc_type, + V8ClassIndex::V8WrapperType cptr_type, + void* imp) +{ + // Make a special case for document.all + if (desc_type == V8ClassIndex::HTMLCOLLECTION && + static_cast<HTMLCollection*>(imp)->type() == HTMLCollection::DocAll) { + desc_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION; + } + + V8Proxy* proxy = V8Proxy::retrieve(); + v8::Local<v8::Object> instance; + if (proxy) { + instance = proxy->CreateWrapperFromCache(desc_type); + } else { + v8::Local<v8::Function> function = GetTemplate(desc_type)->GetFunction(); + instance = SafeAllocation::NewInstance(function); + } + if (!instance.IsEmpty()) { + // Avoid setting the DOM wrapper for failed allocations. + SetDOMWrapper(instance, V8ClassIndex::ToInt(cptr_type), imp); + } + return instance; +} + +v8::Handle<v8::Value> V8Proxy::CheckNewLegal(const v8::Arguments& args) +{ + if (!AllowAllocation::m_current) + return ThrowError(TYPE_ERROR, "Illegal constructor"); + + return args.This(); +} + +void V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) +{ + ASSERT(obj->InternalFieldCount() >= 2); + obj->SetInternalField(V8Custom::kDOMWrapperObjectIndex, WrapCPointer(cptr)); + obj->SetInternalField(V8Custom::kDOMWrapperTypeIndex, v8::Integer::New(type)); +} + + +#ifndef NDEBUG +bool V8Proxy::MaybeDOMWrapper(v8::Handle<v8::Value> value) +{ + if (value.IsEmpty() || !value->IsObject()) return false; + + v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value); + if (obj->InternalFieldCount() == 0) return false; + + ASSERT(obj->InternalFieldCount() >= + V8Custom::kDefaultWrapperInternalFieldCount); + + v8::Handle<v8::Value> type = + obj->GetInternalField(V8Custom::kDOMWrapperTypeIndex); + ASSERT(type->IsInt32()); + ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && + type->Int32Value() < V8ClassIndex::CLASSINDEX_END); + + v8::Handle<v8::Value> wrapper = + obj->GetInternalField(V8Custom::kDOMWrapperObjectIndex); + ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); + + return true; +} +#endif + + +bool V8Proxy::IsDOMEventWrapper(v8::Handle<v8::Value> value) +{ + // All kinds of events use EVENT as dom type in JS wrappers. + // See EventToV8Object + return IsWrapperOfType(value, V8ClassIndex::EVENT); +} + +bool V8Proxy::IsWrapperOfType(v8::Handle<v8::Value> value, + V8ClassIndex::V8WrapperType classType) +{ + if (value.IsEmpty() || !value->IsObject()) return false; + + v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value); + if (obj->InternalFieldCount() == 0) return false; + + ASSERT(obj->InternalFieldCount() >= + V8Custom::kDefaultWrapperInternalFieldCount); + + v8::Handle<v8::Value> wrapper = + obj->GetInternalField(V8Custom::kDOMWrapperObjectIndex); + ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); + + v8::Handle<v8::Value> type = + obj->GetInternalField(V8Custom::kDOMWrapperTypeIndex); + ASSERT(type->IsInt32()); + ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && + type->Int32Value() < V8ClassIndex::CLASSINDEX_END); + + return V8ClassIndex::FromInt(type->Int32Value()) == classType; +} + +#if ENABLE(VIDEO) +#define FOR_EACH_VIDEO_TAG(macro) \ + macro(audio, AUDIO) \ + macro(source, SOURCE) \ + macro(video, VIDEO) +#else +#define FOR_EACH_VIDEO_TAG(macro) +#endif + +#define FOR_EACH_TAG(macro) \ + macro(a, ANCHOR) \ + macro(applet, APPLET) \ + macro(area, AREA) \ + macro(base, BASE) \ + macro(basefont, BASEFONT) \ + macro(blockquote, BLOCKQUOTE) \ + macro(body, BODY) \ + macro(br, BR) \ + macro(button, BUTTON) \ + macro(caption, TABLECAPTION) \ + macro(col, TABLECOL) \ + macro(colgroup, TABLECOL) \ + macro(del, MOD) \ + macro(canvas, CANVAS) \ + macro(dir, DIRECTORY) \ + macro(div, DIV) \ + macro(dl, DLIST) \ + macro(embed, EMBED) \ + macro(fieldset, FIELDSET) \ + macro(font, FONT) \ + macro(form, FORM) \ + macro(frame, FRAME) \ + macro(frameset, FRAMESET) \ + macro(h1, HEADING) \ + macro(h2, HEADING) \ + macro(h3, HEADING) \ + macro(h4, HEADING) \ + macro(h5, HEADING) \ + macro(h6, HEADING) \ + macro(head, HEAD) \ + macro(hr, HR) \ + macro(html, HTML) \ + macro(img, IMAGE) \ + macro(iframe, IFRAME) \ + macro(image, IMAGE) \ + macro(input, INPUT) \ + macro(ins, MOD) \ + macro(isindex, ISINDEX) \ + macro(keygen, SELECT) \ + macro(label, LABEL) \ + macro(legend, LEGEND) \ + macro(li, LI) \ + macro(link, LINK) \ + macro(listing, PRE) \ + macro(map, MAP) \ + macro(marquee, MARQUEE) \ + macro(menu, MENU) \ + macro(meta, META) \ + macro(object, OBJECT) \ + macro(ol, OLIST) \ + macro(optgroup, OPTGROUP) \ + macro(option, OPTION) \ + macro(p, PARAGRAPH) \ + macro(param, PARAM) \ + macro(pre, PRE) \ + macro(q, QUOTE) \ + macro(script, SCRIPT) \ + macro(select, SELECT) \ + macro(style, STYLE) \ + macro(table, TABLE) \ + macro(thead, TABLESECTION) \ + macro(tbody, TABLESECTION) \ + macro(tfoot, TABLESECTION) \ + macro(td, TABLECELL) \ + macro(th, TABLECELL) \ + macro(tr, TABLEROW) \ + macro(textarea, TEXTAREA) \ + macro(title, TITLE) \ + macro(ul, ULIST) \ + macro(xmp, PRE) + +V8ClassIndex::V8WrapperType V8Proxy::GetHTMLElementType(HTMLElement* element) +{ + static HashMap<String, V8ClassIndex::V8WrapperType> map; + if (map.isEmpty()) { +#define ADD_TO_HASH_MAP(tag, name) \ + map.set(#tag, V8ClassIndex::HTML##name##ELEMENT); +FOR_EACH_TAG(ADD_TO_HASH_MAP) +#if ENABLE(VIDEO) + if (MediaPlayer::isAvailable()) { +FOR_EACH_VIDEO_TAG(ADD_TO_HASH_MAP) + } +#endif +#undef ADD_TO_HASH_MAP + } + + V8ClassIndex::V8WrapperType t = map.get(element->localName().impl()); + if (t == 0) + return V8ClassIndex::HTMLELEMENT; + return t; +} +#undef FOR_EACH_TAG + +#if ENABLE(SVG) + +#if ENABLE(SVG_ANIMATION) +#define FOR_EACH_ANIMATION_TAG(macro) \ + macro(animateColor, ANIMATECOLOR) \ + macro(animate, ANIMATE) \ + macro(animateTransform, ANIMATETRANSFORM) \ + macro(set, SET) +#else +#define FOR_EACH_ANIMATION_TAG(macro) +#endif + +#if ENABLE(SVG_FILTERS) +#define FOR_EACH_FILTERS_TAG(macro) \ + macro(feBlend, FEBLEND) \ + macro(feColorMatrix, FECOLORMATRIX) \ + macro(feComponentTransfer, FECOMPONENTTRANSFER) \ + macro(feComposite, FECOMPOSITE) \ + macro(feDiffuseLighting, FEDIFFUSELIGHTING) \ + macro(feDisplacementMap, FEDISPLACEMENTMAP) \ + macro(feDistantLight, FEDISTANTLIGHT) \ + macro(feFlood, FEFLOOD) \ + macro(feFuncA, FEFUNCA) \ + macro(feFuncB, FEFUNCB) \ + macro(feFuncG, FEFUNCG) \ + macro(feFuncR, FEFUNCR) \ + macro(feGaussianBlur, FEGAUSSIANBLUR) \ + macro(feImage, FEIMAGE) \ + macro(feMerge, FEMERGE) \ + macro(feMergeNode, FEMERGENODE) \ + macro(feOffset, FEOFFSET) \ + macro(fePointLight, FEPOINTLIGHT) \ + macro(feSpecularLighting, FESPECULARLIGHTING) \ + macro(feSpotLight, FESPOTLIGHT) \ + macro(feTile, FETILE) \ + macro(feTurbulence, FETURBULENCE) \ + macro(filter, FILTER) +#else +#define FOR_EACH_FILTERS_TAG(macro) +#endif + +#if ENABLE(SVG_FONTS) +#define FOR_EACH_FONTS_TAG(macro) \ + macro(definition-src, DEFINITIONSRC) \ + macro(font-face, FONTFACE) \ + macro(font-face-format, FONTFACEFORMAT) \ + macro(font-face-name, FONTFACENAME) \ + macro(font-face-src, FONTFACESRC) \ + macro(font-face-uri, FONTFACEURI) +#else +#define FOR_EACH_FONTS_TAG(marco) +#endif + +#if ENABLE(SVG_FOREIGN_OBJECT) +#define FOR_EACH_FOREIGN_OBJECT_TAG(macro) \ + macro(foreignObject, FOREIGNOBJECT) +#else +#define FOR_EACH_FOREIGN_OBJECT_TAG(macro) +#endif + +#if ENABLE(SVG_USE) +#define FOR_EACH_USE_TAG(macro) \ + macro(use, USE) +#else +#define FOR_EACH_USE_TAG(macro) +#endif + +#define FOR_EACH_TAG(macro) \ + FOR_EACH_ANIMATION_TAG(macro) \ + FOR_EACH_FILTERS_TAG(macro) \ + FOR_EACH_FONTS_TAG(macro) \ + FOR_EACH_FOREIGN_OBJECT_TAG(macro) \ + FOR_EACH_USE_TAG(macro) \ + macro(a, A) \ + macro(altGlyph, ALTGLYPH) \ + macro(circle, CIRCLE) \ + macro(clipPath, CLIPPATH) \ + macro(cursor, CURSOR) \ + macro(defs, DEFS) \ + macro(desc, DESC) \ + macro(ellipse, ELLIPSE) \ + macro(g, G) \ + macro(glyph, GLYPH) \ + macro(image, IMAGE) \ + macro(linearGradient, LINEARGRADIENT) \ + macro(line, LINE) \ + macro(marker, MARKER) \ + macro(mask, MASK) \ + macro(metadata, METADATA) \ + macro(path, PATH) \ + macro(pattern, PATTERN) \ + macro(polyline, POLYLINE) \ + macro(polygon, POLYGON) \ + macro(radialGradient, RADIALGRADIENT) \ + macro(rect, RECT) \ + macro(script, SCRIPT) \ + macro(stop, STOP) \ + macro(style, STYLE) \ + macro(svg, SVG) \ + macro(switch, SWITCH) \ + macro(symbol, SYMBOL) \ + macro(text, TEXT) \ + macro(textPath, TEXTPATH) \ + macro(title, TITLE) \ + macro(tref, TREF) \ + macro(tspan, TSPAN) \ + macro(view, VIEW) \ + // end of macro + +V8ClassIndex::V8WrapperType V8Proxy::GetSVGElementType(SVGElement* element) +{ + static HashMap<String, V8ClassIndex::V8WrapperType> map; + if (map.isEmpty()) { +#define ADD_TO_HASH_MAP(tag, name) \ + map.set(#tag, V8ClassIndex::SVG##name##ELEMENT); +FOR_EACH_TAG(ADD_TO_HASH_MAP) +#undef ADD_TO_HASH_MAP + } + + V8ClassIndex::V8WrapperType t = map.get(element->localName().impl()); + if (t == 0) return V8ClassIndex::SVGELEMENT; + return t; +} +#undef FOR_EACH_TAG + +#endif // ENABLE(SVG) + + +v8::Handle<v8::Value> V8Proxy::EventToV8Object(Event* event) +{ + if (!event) + return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(event); + if (!wrapper.IsEmpty()) + return wrapper; + + V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT; + + if (event->isUIEvent()) { + if (event->isKeyboardEvent()) + type = V8ClassIndex::KEYBOARDEVENT; + else if (event->isTextEvent()) + type = V8ClassIndex::TEXTEVENT; + else if (event->isMouseEvent()) + type = V8ClassIndex::MOUSEEVENT; + else if (event->isWheelEvent()) + type = V8ClassIndex::WHEELEVENT; +#if ENABLE(SVG) + else if (event->isSVGZoomEvent()) + type = V8ClassIndex::SVGZOOMEVENT; +#endif + else + type = V8ClassIndex::UIEVENT; + } else if (event->isMutationEvent()) + type = V8ClassIndex::MUTATIONEVENT; + else if (event->isOverflowEvent()) + type = V8ClassIndex::OVERFLOWEVENT; + else if (event->isMessageEvent()) + type = V8ClassIndex::MESSAGEEVENT; + else if (event->isProgressEvent()) { + if (event->isXMLHttpRequestProgressEvent()) + type = V8ClassIndex::XMLHTTPREQUESTPROGRESSEVENT; + else + type = V8ClassIndex::PROGRESSEVENT; + } else if (event->isWebKitAnimationEvent()) + type = V8ClassIndex::WEBKITANIMATIONEVENT; + else if (event->isWebKitTransitionEvent()) + type = V8ClassIndex::WEBKITTRANSITIONEVENT; + + + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::EVENT, event); + if (result.IsEmpty()) { + // Instantiation failed. Avoid updating the DOM object map and + // return null which is already handled by callers of this function + // in case the event is NULL. + return v8::Null(); + } + + event->ref(); // fast ref + SetJSWrapperForDOMObject(event, v8::Persistent<v8::Object>::New(result)); + + return result; +} + + +// Caller checks node is not null. +v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) +{ + if (!node) return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMNodeMap().get(node); + if (!wrapper.IsEmpty()) + return wrapper; + + bool is_document = false; // document type node has special handling + V8ClassIndex::V8WrapperType type; + + switch (node->nodeType()) { + case Node::ELEMENT_NODE: + if (node->isHTMLElement()) + type = GetHTMLElementType(static_cast<HTMLElement*>(node)); +#if ENABLE(SVG) + else if (node->isSVGElement()) + type = GetSVGElementType(static_cast<SVGElement*>(node)); +#endif + else + type = V8ClassIndex::ELEMENT; + break; + case Node::ATTRIBUTE_NODE: + type = V8ClassIndex::ATTR; + break; + case Node::TEXT_NODE: + type = V8ClassIndex::TEXT; + break; + case Node::CDATA_SECTION_NODE: + type = V8ClassIndex::CDATASECTION; + break; + case Node::ENTITY_NODE: + type = V8ClassIndex::ENTITY; + break; + case Node::PROCESSING_INSTRUCTION_NODE: + type = V8ClassIndex::PROCESSINGINSTRUCTION; + break; + case Node::COMMENT_NODE: + type = V8ClassIndex::COMMENT; + break; + case Node::DOCUMENT_NODE: { + is_document = true; + Document* doc = static_cast<Document*>(node); + if (doc->isHTMLDocument()) + type = V8ClassIndex::HTMLDOCUMENT; +#if ENABLE(SVG) + else if (doc->isSVGDocument()) + type = V8ClassIndex::SVGDOCUMENT; +#endif + else + type = V8ClassIndex::DOCUMENT; + break; + } + case Node::DOCUMENT_TYPE_NODE: + type = V8ClassIndex::DOCUMENTTYPE; + break; + case Node::NOTATION_NODE: + type = V8ClassIndex::NOTATION; + break; + case Node::DOCUMENT_FRAGMENT_NODE: + type = V8ClassIndex::DOCUMENTFRAGMENT; + break; + case Node::ENTITY_REFERENCE_NODE: + type = V8ClassIndex::ENTITYREFERENCE; + break; + default: + type = V8ClassIndex::NODE; + } + + // Find the context to which the node belongs and create the wrapper + // in that context. If the node is not in a document, the current + // context is used. + v8::Local<v8::Context> context; + Document* doc = node->document(); + if (doc) { + context = V8Proxy::GetContext(doc->frame()); + } + if (!context.IsEmpty()) { + context->Enter(); + } + + v8::Local<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::NODE, node); + + // Exit the node's context if it was entered. + if (!context.IsEmpty()) { + context->Exit(); + } + + if (result.IsEmpty()) { + // If instantiation failed it's important not to add the result + // to the DOM node map. Instead we return an empty handle, which + // should already be handled by callers of this function in case + // the node is NULL. + return result; + } + + node->ref(); + SetJSWrapperForDOMNode(node, v8::Persistent<v8::Object>::New(result)); + + if (is_document) { + Document* doc = static_cast<Document*>(node); + V8Proxy* proxy = V8Proxy::retrieve(doc->frame()); + if (proxy) + proxy->UpdateDocumentWrapper(result); + + if (type == V8ClassIndex::HTMLDOCUMENT) { + // Create marker object and insert it in two internal fields. + // This is used to implement temporary shadowing of + // document.all. + ASSERT(result->InternalFieldCount() == + V8Custom::kHTMLDocumentInternalFieldCount); + v8::Local<v8::Object> marker = v8::Object::New(); + result->SetInternalField(V8Custom::kHTMLDocumentMarkerIndex, marker); + result->SetInternalField(V8Custom::kHTMLDocumentShadowIndex, marker); + } + } + + return result; +} + + +// A JS object of type EventTarget can only be the following possible types: +// 1) EventTargetNode; 2) XMLHttpRequest; 3) MessagePort; 4) SVGElementInstance; +// 5) XMLHttpRequestUpload 6) Worker +// check EventTarget.h for new type conversion methods +v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) +{ + if (!target) + return v8::Null(); + +#if ENABLE(SVG) + SVGElementInstance* instance = target->toSVGElementInstance(); + if (instance) + return ToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance); +#endif + +#if ENABLE(WORKERS) + Worker* worker = target->toWorker(); + if (worker) + return ToV8Object(V8ClassIndex::WORKER, worker); +#endif // WORKERS + + Node* node = target->toNode(); + if (node) + return NodeToV8Object(node); + + // XMLHttpRequest is created within its JS counterpart. + XMLHttpRequest* xhr = target->toXMLHttpRequest(); + if (xhr) { + v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xhr); + ASSERT(!wrapper.IsEmpty()); + return wrapper; + } + + // MessagePort is created within its JS counterpart + MessagePort* port = target->toMessagePort(); + if (port) { + v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port); + ASSERT(!wrapper.IsEmpty()); + return wrapper; + } + + XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload(); + if (upload) { + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload); + ASSERT(!wrapper.IsEmpty()); + return wrapper; + } + + ASSERT(0); + return v8::Handle<v8::Value>(); +} + + +v8::Handle<v8::Value> V8Proxy::EventListenerToV8Object( + EventListener* listener) +{ + if (listener == 0) return v8::Null(); + + // TODO(fqian): can a user take a lazy event listener and set to other places? + V8AbstractEventListener* v8listener = + static_cast<V8AbstractEventListener*>(listener); + return v8listener->getListenerObject(); +} + + +v8::Handle<v8::Value> V8Proxy::DOMImplementationToV8Object( + DOMImplementation* impl) +{ + v8::Handle<v8::Object> result = + InstantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, + V8ClassIndex::DOMIMPLEMENTATION, + impl); + if (result.IsEmpty()) { + // If the instantiation failed, we ignore it and return null instead + // of returning an empty handle. + return v8::Null(); + } + return result; +} + + +v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) +{ + if (!sheet) return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(sheet); + if (!wrapper.IsEmpty()) + return wrapper; + + V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET; + if (sheet->isCSSStyleSheet()) + type = V8ClassIndex::CSSSTYLESHEET; + + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::STYLESHEET, sheet); + if (!result.IsEmpty()) { + // Only update the DOM object map if the result is non-empty. + sheet->ref(); + SetJSWrapperForDOMObject(sheet, v8::Persistent<v8::Object>::New(result)); + } + + // Add a hidden reference from stylesheet object to its owner node. + Node* owner_node = sheet->ownerNode(); + if (owner_node) { + v8::Handle<v8::Object> owner = + v8::Handle<v8::Object>::Cast(NodeToV8Object(owner_node)); + result->SetInternalField(V8Custom::kStyleSheetOwnerNodeIndex, owner); + } + + return result; +} + + +v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) +{ + if (!value) return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(value); + if (!wrapper.IsEmpty()) + return wrapper; + + V8ClassIndex::V8WrapperType type; + + if (value->isWebKitCSSTransformValue()) + type = V8ClassIndex::WEBKITCSSTRANSFORMVALUE; + else if (value->isValueList()) + type = V8ClassIndex::CSSVALUELIST; + else if (value->isPrimitiveValue()) + type = V8ClassIndex::CSSPRIMITIVEVALUE; +#if ENABLE(SVG) + else if (value->isSVGPaint()) + type = V8ClassIndex::SVGPAINT; + else if (value->isSVGColor()) + type = V8ClassIndex::SVGCOLOR; +#endif + else + type = V8ClassIndex::CSSVALUE; + + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::CSSVALUE, value); + if (!result.IsEmpty()) { + // Only update the DOM object map if the result is non-empty. + value->ref(); + SetJSWrapperForDOMObject(value, v8::Persistent<v8::Object>::New(result)); + } + + return result; +} + + +v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule) +{ + if (!rule) return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(rule); + if (!wrapper.IsEmpty()) + return wrapper; + + V8ClassIndex::V8WrapperType type; + + switch (rule->type()) { + case CSSRule::STYLE_RULE: + type = V8ClassIndex::CSSSTYLERULE; + break; + case CSSRule::CHARSET_RULE: + type = V8ClassIndex::CSSCHARSETRULE; + break; + case CSSRule::IMPORT_RULE: + type = V8ClassIndex::CSSIMPORTRULE; + break; + case CSSRule::MEDIA_RULE: + type = V8ClassIndex::CSSMEDIARULE; + break; + case CSSRule::FONT_FACE_RULE: + type = V8ClassIndex::CSSFONTFACERULE; + break; + case CSSRule::PAGE_RULE: + type = V8ClassIndex::CSSPAGERULE; + break; + case CSSRule::VARIABLES_RULE: + type = V8ClassIndex::CSSVARIABLESRULE; + break; + case CSSRule::WEBKIT_KEYFRAME_RULE: + type = V8ClassIndex::WEBKITCSSKEYFRAMERULE; + break; + case CSSRule::WEBKIT_KEYFRAMES_RULE: + type = V8ClassIndex::WEBKITCSSKEYFRAMESRULE; + break; + default: // CSSRule::UNKNOWN_RULE + type = V8ClassIndex::CSSRULE; + break; + } + + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::CSSRULE, rule); + if (!result.IsEmpty()) { + // Only update the DOM object map if the result is non-empty. + rule->ref(); + SetJSWrapperForDOMObject(rule, v8::Persistent<v8::Object>::New(result)); + } + return result; +} + +v8::Handle<v8::Value> V8Proxy::WindowToV8Object(DOMWindow* window) +{ + if (!window) return v8::Null(); + // Initializes environment of a frame, and return the global object + // of the frame. + Frame* frame = window->frame(); + if (!frame) + return v8::Handle<v8::Object>(); + + // Special case: Because of evaluateInNewContext() one DOMWindow can have + // multipe contexts and multiple global objects associated with it. When + // code running in one of those contexts accesses the window object, we + // want to return the global object associated with that context, not + // necessarily the first global object associated with that DOMWindow. + v8::Handle<v8::Context> current_context = v8::Context::GetCurrent(); + v8::Handle<v8::Object> current_global = current_context->Global(); + v8::Handle<v8::Object> windowWrapper = + LookupDOMWrapper(V8ClassIndex::DOMWINDOW, current_global); + if (!windowWrapper.IsEmpty()) + if (DOMWrapperToNative<DOMWindow>(windowWrapper) == window) + return current_global; + + // Otherwise, return the global object associated with this frame. + v8::Handle<v8::Context> context = GetContext(frame); + if (context.IsEmpty()) + return v8::Handle<v8::Object>(); + + v8::Handle<v8::Object> global = context->Global(); + ASSERT(!global.IsEmpty()); + return global; +} + +void V8Proxy::BindJSObjectToWindow(Frame* frame, + const char* name, + int type, + v8::Handle<v8::FunctionTemplate> desc, + void* imp) +{ + // Get environment. + v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return; // JS not enabled. + + v8::Context::Scope scope(context); + v8::Handle<v8::Object> instance = desc->GetFunction(); + SetDOMWrapper(instance, type, imp); + + v8::Handle<v8::Object> global = context->Global(); + global->Set(v8::String::New(name), instance); +} + +void V8Proxy::ProcessConsoleMessages() +{ + ConsoleMessageManager::ProcessDelayedMessages(); +} + + +// Create the utility context for holding JavaScript functions used internally +// which are not visible to JavaScript executing on the page. +void V8Proxy::CreateUtilityContext() { + ASSERT(m_utilityContext.IsEmpty()); + + v8::HandleScope scope; + v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); + m_utilityContext = v8::Context::New(NULL, global_template); + v8::Context::Scope context_scope(m_utilityContext); + + // Compile JavaScript function for retrieving the source line of the top + // JavaScript stack frame. + static const char* frame_source_line_source = + "function frame_source_line(exec_state) {" + " return exec_state.frame(0).sourceLine();" + "}"; + v8::Script::Compile(v8::String::New(frame_source_line_source))->Run(); + + // Compile JavaScript function for retrieving the source name of the top + // JavaScript stack frame. + static const char* frame_source_name_source = + "function frame_source_name(exec_state) {" + " var frame = exec_state.frame(0);" + " if (frame.func().resolved() && " + " frame.func().script() && " + " frame.func().script().name()) {" + " return frame.func().script().name();" + " }" + "}"; + v8::Script::Compile(v8::String::New(frame_source_name_source))->Run(); +} + + +int V8Proxy::GetSourceLineNumber() { + v8::HandleScope scope; + v8::Handle<v8::Context> utility_context = V8Proxy::GetUtilityContext(); + if (utility_context.IsEmpty()) { + return 0; + } + v8::Context::Scope context_scope(utility_context); + v8::Handle<v8::Function> frame_source_line; + frame_source_line = v8::Local<v8::Function>::Cast( + utility_context->Global()->Get(v8::String::New("frame_source_line"))); + if (frame_source_line.IsEmpty()) { + return 0; + } + v8::Handle<v8::Value> result = v8::Debug::Call(frame_source_line); + if (result.IsEmpty()) { + return 0; + } + return result->Int32Value(); +} + + +String V8Proxy::GetSourceName() { + v8::HandleScope scope; + v8::Handle<v8::Context> utility_context = GetUtilityContext(); + if (utility_context.IsEmpty()) { + return String(); + } + v8::Context::Scope context_scope(utility_context); + v8::Handle<v8::Function> frame_source_name; + frame_source_name = v8::Local<v8::Function>::Cast( + utility_context->Global()->Get(v8::String::New("frame_source_name"))); + if (frame_source_name.IsEmpty()) { + return String(); + } + return ToWebCoreString(v8::Debug::Call(frame_source_name)); +} + +void V8Proxy::RegisterExtension(v8::Extension* extension, + const String& schemeRestriction) { + v8::RegisterExtension(extension); + V8ExtensionInfo info = {schemeRestriction, extension}; + m_extensions.push_back(info); +} + +} // namespace WebCore diff --git a/V8Binding/v8/v8_proxy.h b/V8Binding/v8/v8_proxy.h new file mode 100644 index 0000000..d1a7a9f --- /dev/null +++ b/V8Binding/v8/v8_proxy.h @@ -0,0 +1,648 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_PROXY_H__ +#define V8_PROXY_H__ + +#include <v8.h> +#include "v8_index.h" +#include "v8_custom.h" +#include "v8_utility.h" +#include "ChromiumBridge.h" +#include "Node.h" +#include "NodeFilter.h" +#include "PlatformString.h" // for WebCore::String +#include "ScriptSourceCode.h" // for WebCore::ScriptSourceCode +#include "SecurityOrigin.h" // for WebCore::SecurityOrigin +#include "V8DOMMap.h" +#include <wtf/Assertions.h> +#include <wtf/PassRefPtr.h> // so generated bindings don't have to +#include <wtf/Vector.h> + +#include <iterator> +#include <list> + +#ifdef ENABLE_DOM_STATS_COUNTERS +#define INC_STATS(name) ChromiumBridge::incrementStatsCounter(name) +#else +#define INC_STATS(name) +#endif + +// FIXME: Remove the following hack when we replace all references to GetDOMObjectMap. +#define GetDOMObjectMap getDOMObjectMap + +namespace WebCore { + +class CSSStyleDeclaration; +class DOMImplementation; +class Element; +class Event; +class EventListener; +class Frame; +class HTMLCollection; +class HTMLOptionsCollection; +class HTMLElement; +class HTMLDocument; +class MediaList; +class NamedNodeMap; +class Node; +class NodeList; +class Screen; +class String; +class StyleSheet; +class SVGElement; +class DOMWindow; +class Document; +class EventTarget; +class Event; +class EventListener; +class Navigator; +class MimeType; +class MimeTypeArray; +class Plugin; +class PluginArray; +class StyleSheetList; +class CSSValue; +class CSSRule; +class CSSRuleList; +class CSSValueList; +class NodeFilter; +class ScriptExecutionContext; + +#if ENABLE(SVG) +class SVGElementInstance; +#endif + +class V8EventListener; +class V8ObjectEventListener; + +// This is a container for V8EventListener objects that also does some +// caching to speed up finding entries by v8::Object. +class V8EventListenerList { + public: + static const size_t kMaxKeyNameLength = 254; + // The name should be distinct from any other V8EventListenerList + // within the same process, and <= kMaxKeyNameLength characters. + explicit V8EventListenerList(const char* name); + ~V8EventListenerList(); + + typedef Vector<V8EventListener*>::iterator iterator; + V8EventListenerList::iterator begin(); + iterator end(); + + // In addition to adding the listener to this list, this also caches the + // V8EventListener as a hidden property on its wrapped v8 listener object, + // so we can quickly look it up later. + void add(V8EventListener*); + void remove(V8EventListener*); + V8EventListener* find(v8::Local<v8::Object>, bool isInline); + void clear(); + + private: + v8::Handle<v8::String> getKey(bool isInline); + v8::Persistent<v8::String> m_inlineKey; + v8::Persistent<v8::String> m_nonInlineKey; + Vector<V8EventListener*> m_list; +}; + + +// TODO(fqian): use standard logging facilities in WebCore. +void log_info(Frame* frame, const String& msg, const String& url); + + +#ifndef NDEBUG + +#define GlobalHandleTypeList(V) \ + V(PROXY) \ + V(NPOBJECT) \ + V(SCHEDULED_ACTION) \ + V(EVENT_LISTENER) \ + V(NODE_FILTER) \ + V(SCRIPTINSTANCE) \ + V(SCRIPTVALUE) + + +// Host information of persistent handles. +enum GlobalHandleType { +#define ENUM(name) name, + GlobalHandleTypeList(ENUM) +#undef ENUM +}; + + +class GlobalHandleInfo { + public: + GlobalHandleInfo(void* host, GlobalHandleType type) + : host_(host), type_(type) { } + void* host_; + GlobalHandleType type_; +}; + +#endif // NDEBUG + +// The following Batch structs and methods are used for setting multiple +// properties on an ObjectTemplate, used from the generated bindings +// initialization (ConfigureXXXTemplate). This greatly reduces the binary +// size by moving from code driven setup to data table driven setup. + +// BatchedAttribute translates into calls to SetAccessor() on either the +// instance or the prototype ObjectTemplate, based on |on_proto|. +struct BatchedAttribute { + const char* const name; + v8::AccessorGetter getter; + v8::AccessorSetter setter; + V8ClassIndex::V8WrapperType data; + v8::AccessControl settings; + v8::PropertyAttribute attribute; + bool on_proto; +}; + +void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst, + v8::Handle<v8::ObjectTemplate> proto, + const BatchedAttribute* attrs, + size_t num_attrs); + +// BatchedConstant translates into calls to Set() for setting up an object's +// constants. It sets the constant on both the FunctionTemplate |desc| and the +// ObjectTemplate |proto|. PropertyAttributes is always ReadOnly. +struct BatchedConstant { + const char* const name; + int value; +}; + +void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc, + v8::Handle<v8::ObjectTemplate> proto, + const BatchedConstant* consts, + size_t num_consts); + +const int kMaxRecursionDepth = 20; + +// Information about an extension that is registered for use with V8. If scheme +// is non-empty, it contains the URL scheme the extension should be used with. +// Otherwise, the extension is used with all schemes. +struct V8ExtensionInfo { + String scheme; + v8::Extension* extension; +}; +typedef std::list<V8ExtensionInfo> V8ExtensionList; + +class V8Proxy { + public: + // The types of javascript errors that can be thrown. + enum ErrorType { + RANGE_ERROR, + REFERENCE_ERROR, + SYNTAX_ERROR, + TYPE_ERROR, + GENERAL_ERROR + }; + + explicit V8Proxy(Frame* frame) + : m_frame(frame), m_event_listeners("m_event_listeners"), + m_xhr_listeners("m_xhr_listeners"), m_inlineCode(false), + m_timerCallback(false), m_recursion(0) { } + + ~V8Proxy(); + + Frame* frame() { return m_frame; } + + // Clear page-specific data, but keep the global object identify. + void clearForNavigation(); + + // Clear page-specific data before shutting down the proxy object. + void clearForClose(); + + // Update document object of the frame. + void updateDocument(); + + // Update the security origin of a document + // (e.g., after setting docoument.domain). + void updateSecurityOrigin(); + + // Destroy the global object. + void DestroyGlobal(); + + // TODO(mpcomplete): Need comment. User Gesture related. + bool inlineCode() const { return m_inlineCode; } + void setInlineCode(bool value) { m_inlineCode = value; } + + bool timerCallback() const { return m_timerCallback; } + void setTimerCallback(bool value) { m_timerCallback = value; } + + // Has the context for this proxy been initialized? + bool ContextInitialized(); + + // Disconnects the proxy from its owner frame, + // and clears all timeouts on the DOM window. + void disconnectFrame(); + + bool isEnabled(); + + // Find/Create/Remove event listener wrappers. + PassRefPtr<V8EventListener> FindV8EventListener(v8::Local<v8::Value> listener, + bool html); + PassRefPtr<V8EventListener> FindOrCreateV8EventListener(v8::Local<v8::Value> listener, + bool html); + + PassRefPtr<V8EventListener> FindObjectEventListener(v8::Local<v8::Value> listener, + bool html); + PassRefPtr<V8EventListener> FindOrCreateObjectEventListener(v8::Local<v8::Value> listener, + bool html); + + void RemoveV8EventListener(V8EventListener* listener); + void RemoveObjectEventListener(V8ObjectEventListener* listener); + + // Protect/Unprotect JS wrappers of a DOM object. + static void GCProtect(void* dom_object); + static void GCUnprotect(void* dom_object); + + // Create a lazy event listener. + PassRefPtr<EventListener> createInlineEventListener( + const String& functionName, const String& code, Node* node); +#if ENABLE(SVG) + PassRefPtr<EventListener> createSVGEventHandler( + const String& functionName, const String& code, Node* node); + + static void SetSVGContext(void* object, SVGElement* context); + static SVGElement* GetSVGContext(void* object); +#endif + + void setEventHandlerLineno(int lineno) { m_handlerLineno = lineno; } + void finishedWithEvent(Event* event) { } + + // Evaluate JavaScript in a new context. The script gets its own global scope + // and its own prototypes for intrinsic JavaScript objects (String, Array, + // and so-on). It shares the wrappers for all DOM nodes and DOM constructors. + void evaluateInNewContext(const Vector<ScriptSourceCode>& sources); + + // Evaluate a script file in the current execution environment. + // The caller must hold an execution context. + // If cannot evalute the script, it returns an error. + v8::Local<v8::Value> evaluate(const ScriptSourceCode& source, + Node* node); + + // Run an already compiled script. + v8::Local<v8::Value> RunScript(v8::Handle<v8::Script> script, + bool inline_code); + + // Call the function with the given receiver and arguments. + v8::Local<v8::Value> CallFunction(v8::Handle<v8::Function> function, + v8::Handle<v8::Object> receiver, + int argc, + v8::Handle<v8::Value> argv[]); + + // Returns the dom constructor function for the given node type. + v8::Local<v8::Function> GetConstructor(V8ClassIndex::V8WrapperType type); + + // To create JS Wrapper objects, we create a cache of a 'boiler plate' + // object, and then simply Clone that object each time we need a new one. + // This is faster than going through the full object creation process. + v8::Local<v8::Object> CreateWrapperFromCache(V8ClassIndex::V8WrapperType type); + + // Returns the window object of the currently executing context. + static DOMWindow* retrieveWindow(); + // Returns the window object associated with a context. + static DOMWindow* retrieveWindow(v8::Handle<v8::Context> context); + // Returns V8Proxy object of the currently executing context. + static V8Proxy* retrieve(); + // Returns V8Proxy object associated with a frame. + static V8Proxy* retrieve(Frame* frame); + // Returns V8Proxy object associated with a script execution context. + static V8Proxy* retrieve(ScriptExecutionContext* context); + + // Returns the frame object of the window object associated + // with the currently executing context. + static Frame* retrieveFrame(); + // Returns the frame object of the window object associated with + // a context. + static Frame* retrieveFrame(v8::Handle<v8::Context> context); + // Returns the frame that started JS execution. + // NOTE: cannot declare retrieveActiveFrame as inline function, + // VS complains at linking time. + static Frame* retrieveActiveFrame(); + + // Returns V8 Context of a frame. If none exists, creates + // a new context. It is potentially slow and consumes memory. + static v8::Local<v8::Context> GetContext(Frame* frame); + static v8::Local<v8::Context> GetCurrentContext(); + + // If the current context causes out of memory, JavaScript setting + // is disabled and it returns true. + static bool HandleOutOfMemory(); + + // Check if the active execution context can access the target frame. + static bool CanAccessFrame(Frame* target, bool report_error); + + // Check if it is safe to access the given node from the + // current security context. + static bool CheckNodeSecurity(Node* node); + + static v8::Handle<v8::Value> CheckNewLegal(const v8::Arguments& args); + + // Create a V8 wrapper for a C pointer + static v8::Handle<v8::Value> WrapCPointer(void* cptr) { + // Represent void* as int + int addr = reinterpret_cast<int>(cptr); + ASSERT((addr & 0x01) == 0); // the address must be aligned. + return v8::Integer::New(addr >> 1); + } + + // Take C pointer out of a v8 wrapper + template <class C> + static C* ExtractCPointer(v8::Handle<v8::Value> obj) { + return static_cast<C*>(ExtractCPointerImpl(obj)); + } + + static v8::Handle<v8::Script> CompileScript(v8::Handle<v8::String> code, + const String& fileName, + int baseLine); + +#ifndef NDEBUG + // Checks if a v8 value can be a DOM wrapper + static bool MaybeDOMWrapper(v8::Handle<v8::Value> value); +#endif + + // Sets contents of a DOM wrapper. + static void SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* ptr); + + static v8::Handle<v8::Object> LookupDOMWrapper( + V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> value); + + // A helper function extract native object pointer from a DOM wrapper + // and cast to the specified type. + template <class C> + static C* DOMWrapperToNative(v8::Handle<v8::Value> object) { + ASSERT(MaybeDOMWrapper(object)); + v8::Handle<v8::Value> ptr = + v8::Handle<v8::Object>::Cast(object)->GetInternalField( + V8Custom::kDOMWrapperObjectIndex); + return ExtractCPointer<C>(ptr); + } + + // A help function extract a node type pointer from a DOM wrapper. + // Wrapped pointer must be cast to Node* first. + template <class C> + static C* DOMWrapperToNode(v8::Handle<v8::Value> value) { + ASSERT(MaybeDOMWrapper(value)); + + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); + + ASSERT(GetDOMWrapperType(object) == V8ClassIndex::NODE); + + v8::Handle<v8::Value> wrapper = + object->GetInternalField(V8Custom::kDOMWrapperObjectIndex); + return static_cast<C*>(ExtractCPointer<Node>(wrapper)); + } + + template<typename T> + static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type, PassRefPtr<T> imp) + { + return ToV8Object(type, imp.get()); + } + static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type, + void* imp); + // Fast-path for Node objects. + static v8::Handle<v8::Value> NodeToV8Object(Node* node); + + template <class C> + static C* ToNativeObject(V8ClassIndex::V8WrapperType type, + v8::Handle<v8::Value> object) { + return static_cast<C*>(ToNativeObjectImpl(type, object)); + } + + static V8ClassIndex::V8WrapperType GetDOMWrapperType( + v8::Handle<v8::Object> object); + + // If the exception code is different from zero, a DOM exception is + // schedule to be thrown. + static void SetDOMException(int exception_code); + + // Schedule an error object to be thrown. + static v8::Handle<v8::Value> ThrowError(ErrorType type, const char* message); + + // Create an instance of a function descriptor and set to the global object + // as a named property. Used by v8_test_shell. + static void BindJSObjectToWindow(Frame* frame, + const char* name, + int type, + v8::Handle<v8::FunctionTemplate> desc, + void* imp); + + static v8::Handle<v8::Value> EventToV8Object(Event* event); + static Event* ToNativeEvent(v8::Handle<v8::Value> jsevent) { + if (!IsDOMEventWrapper(jsevent)) return 0; + return DOMWrapperToNative<Event>(jsevent); + } + + static v8::Handle<v8::Value> EventTargetToV8Object(EventTarget* target); + // Wrap and unwrap JS event listeners + static v8::Handle<v8::Value> EventListenerToV8Object(EventListener* target); + + // DOMImplementation is a singleton and it is handled in a special + // way. A wrapper is generated per document and stored in an + // internal field of the document. + static v8::Handle<v8::Value> DOMImplementationToV8Object( + DOMImplementation* impl); + + // Wrap JS node filter in C++ + static PassRefPtr<NodeFilter> ToNativeNodeFilter(v8::Handle<v8::Value> filter); + + static v8::Persistent<v8::FunctionTemplate> GetTemplate( + V8ClassIndex::V8WrapperType type); + + template <int tag, typename T> + static v8::Handle<v8::Value> ConstructDOMObject(const v8::Arguments& args); + + // Checks whether a DOM object has a JS wrapper. + static bool DOMObjectHasJSWrapper(void* obj); + // Set JS wrapper of a DOM object, the caller in charge of increase ref. + static void SetJSWrapperForDOMObject(void* obj, + v8::Persistent<v8::Object> wrapper); + static void SetJSWrapperForActiveDOMObject(void* obj, + v8::Persistent<v8::Object> wrapper); + static void SetJSWrapperForDOMNode(Node* node, + v8::Persistent<v8::Object> wrapper); + + // Process any pending JavaScript console messages. + static void ProcessConsoleMessages(); + +#ifndef NDEBUG + // For debugging and leak detection purpose + static void RegisterGlobalHandle(GlobalHandleType type, + void* host, + v8::Persistent<v8::Value> handle); + static void UnregisterGlobalHandle(void* host, + v8::Persistent<v8::Value> handle); +#endif + + // Check whether a V8 value is a wrapper of type |classType|. + static bool IsWrapperOfType(v8::Handle<v8::Value> obj, + V8ClassIndex::V8WrapperType classType); + + // Function for retrieving the line number and source name for the top + // JavaScript stack frame. + static int GetSourceLineNumber(); + static String GetSourceName(); + + + // Returns a local handle of the context. + v8::Local<v8::Context> GetContext() { + return v8::Local<v8::Context>::New(m_context); + } + + // Registers an extension to be available on webpages with a particular scheme + // If the scheme argument is empty, the extension is available on all pages. + // Will only affect v8 contexts initialized after this call. Takes ownership + // of the v8::Extension object passed. + static void RegisterExtension(v8::Extension* extension, + const String& schemeRestriction); + + private: + v8::Persistent<v8::Context> createNewContext(v8::Handle<v8::Object> global); + void InitContextIfNeeded(); + void DisconnectEventListeners(); + void SetSecurityToken(); + void ClearDocumentWrapper(); + void UpdateDocumentWrapper(v8::Handle<v8::Value> wrapper); + // Dispose global handles of m_contexts and friends. + void DisposeContextHandles(); + + static bool CanAccessPrivate(DOMWindow* target); + + // Check whether a V8 value is a DOM Event wrapper + static bool IsDOMEventWrapper(v8::Handle<v8::Value> obj); + + static void* ToNativeObjectImpl(V8ClassIndex::V8WrapperType type, + v8::Handle<v8::Value> object); + + // Take C pointer out of a v8 wrapper + static void* ExtractCPointerImpl(v8::Handle<v8::Value> obj) { + ASSERT(obj->IsNumber()); + int addr = obj->Int32Value(); + return reinterpret_cast<void*>(addr << 1); + } + + + static v8::Handle<v8::Value> StyleSheetToV8Object(StyleSheet* sheet); + static v8::Handle<v8::Value> CSSValueToV8Object(CSSValue* value); + static v8::Handle<v8::Value> CSSRuleToV8Object(CSSRule* rule); + // Returns the JS wrapper of a window object, initializes the environment + // of the window frame if needed. + static v8::Handle<v8::Value> WindowToV8Object(DOMWindow* window); + +#if ENABLE(SVG) + static v8::Handle<v8::Value> SVGElementInstanceToV8Object( + SVGElementInstance* instance); + static v8::Handle<v8::Value> SVGObjectWithContextToV8Object( + V8ClassIndex::V8WrapperType type, void* object); +#endif + + // Set hidden references in a DOMWindow object of a frame. + static void SetHiddenWindowReference(Frame* frame, + const int internal_index, + v8::Handle<v8::Object> jsobj); + + static V8ClassIndex::V8WrapperType GetHTMLElementType(HTMLElement* elm); + + // The first parameter, desc_type, specifies the function descriptor + // used to create JS object. The second parameter, cptr_type, specifies + // the type of third parameter, impl, for type casting. + // For example, a HTML element has HTMLELEMENT desc_type, but always + // use NODE as cptr_type. JS wrapper stores cptr_type and impl as + // internal fields. + static v8::Local<v8::Object> InstantiateV8Object( + V8ClassIndex::V8WrapperType desc_type, + V8ClassIndex::V8WrapperType cptr_type, + void* impl); + + static const char* GetRangeExceptionName(int exception_code); + static const char* GetEventExceptionName(int exception_code); + static const char* GetXMLHttpRequestExceptionName(int exception_code); + static const char* GetDOMExceptionName(int exception_code); + +#if ENABLE(XPATH) + static const char* GetXPathExceptionName(int exception_code); +#endif + +#if ENABLE(SVG) + static V8ClassIndex::V8WrapperType GetSVGElementType(SVGElement* elm); + static const char* GetSVGExceptionName(int exception_code); +#endif + + // Create and populate the utility context. + static void CreateUtilityContext(); + + // Returns a local handle of the utility context. + static v8::Local<v8::Context> GetUtilityContext() { + if (m_utilityContext.IsEmpty()) { + CreateUtilityContext(); + } + return v8::Local<v8::Context>::New(m_utilityContext); + } + + Frame* m_frame; + + v8::Persistent<v8::Context> m_context; + // For each possible type of wrapper, we keep a boilerplate object. + // The boilerplate is used to create additional wrappers of the same type. + // We keep a single persistent handle to an array of the activated + // boilerplates. + v8::Persistent<v8::Array> m_wrapper_boilerplates; + v8::Persistent<v8::Value> m_object_prototype; + + v8::Persistent<v8::Object> m_global; + v8::Persistent<v8::Value> m_document; + + // Utility context holding JavaScript functions used internally. + static v8::Persistent<v8::Context> m_utilityContext; + + int m_handlerLineno; + + // A list of event listeners created for this frame, + // the list gets cleared when removing all timeouts. + V8EventListenerList m_event_listeners; + + // A list of event listeners create for XMLHttpRequest object for this frame, + // the list gets cleared when removing all timeouts. + V8EventListenerList m_xhr_listeners; + + // True for <a href="javascript:foo()"> and false for <script>foo()</script>. + // Only valid during execution. + bool m_inlineCode; + + // True when executing from within a timer callback. Only valid during + // execution. + bool m_timerCallback; + + // Track the recursion depth to be able to avoid too deep recursion. The V8 + // engine allows much more recursion than KJS does so we need to guard against + // excessive recursion in the binding layer. + int m_recursion; + + // List of extensions registered with the context. + static V8ExtensionList m_extensions; +}; + +template <int tag, typename T> +v8::Handle<v8::Value> V8Proxy::ConstructDOMObject(const v8::Arguments& args) { + if (!args.IsConstructCall()) { + V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, + "DOM object constructor cannot be called as a function."); + return v8::Undefined(); + } + + + // Note: it's OK to let this RefPtr go out of scope because we also call + // SetDOMWrapper(), which effectively holds a reference to obj. + RefPtr<T> obj = T::create(); + V8Proxy::SetDOMWrapper(args.Holder(), tag, obj.get()); + obj->ref(); + V8Proxy::SetJSWrapperForDOMObject( + obj.get(), v8::Persistent<v8::Object>::New(args.Holder())); + return args.Holder(); +} + +} // namespace WebCore + +#endif // V8_PROXY_H__ diff --git a/V8Binding/v8/v8_utility.h b/V8Binding/v8/v8_utility.h new file mode 100644 index 0000000..620c04c --- /dev/null +++ b/V8Binding/v8/v8_utility.h @@ -0,0 +1,58 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_UTILITY_H__ +#define V8_UTILITY_H__ + +namespace WebCore { + +class AllowAllocation { + public: + inline AllowAllocation() { + m_prev = m_current; + m_current = true; + } + inline ~AllowAllocation() { + m_current = m_prev; + } + static bool m_current; + private: + bool m_prev; +}; + +class SafeAllocation { + public: + static inline v8::Local<v8::Object> NewInstance( + v8::Handle<v8::Function> fun); + static inline v8::Local<v8::Object> NewInstance( + v8::Handle<v8::ObjectTemplate> templ); + static inline v8::Local<v8::Object> NewInstance( + v8::Handle<v8::Function> fun, int argc, v8::Handle<v8::Value> argv[]); +}; + +v8::Local<v8::Object> SafeAllocation::NewInstance( + v8::Handle<v8::Function> fun) { + if (fun.IsEmpty()) + return v8::Local<v8::Object>(); + AllowAllocation allow; + return fun->NewInstance(); +} + +v8::Local<v8::Object> SafeAllocation::NewInstance( + v8::Handle<v8::ObjectTemplate> templ) { + if (templ.IsEmpty()) return v8::Local<v8::Object>(); + AllowAllocation allow; + return templ->NewInstance(); +} + +v8::Local<v8::Object> SafeAllocation::NewInstance( + v8::Handle<v8::Function> fun, int argc, v8::Handle<v8::Value> argv[]) { + if (fun.IsEmpty()) return v8::Local<v8::Object>(); + AllowAllocation allow; + return fun->NewInstance(argc, argv); +} + +} // namespace WebCore + +#endif // V8_UTILITY_H__ |