author | David Zbarsky <dzbarsky@gmail.com> |
Fri, 26 Jul 2013 11:25:54 -0700 | |
changeset 140200 | 889041639eb9248ba0c0402e4f0cbe1c607b33ca |
parent 140199 | e7045ef73a3d7735eb8eccff9152791de89dc767 |
child 140201 | 9bdc850e67f6743cb63d56aa9c775a91dc84235c |
push id | 31638 |
push user | dzbarsky@gmail.com |
push date | Fri, 26 Jul 2013 18:25:42 +0000 |
treeherder | mozilla-inbound@9bdc850e67f6 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bz |
bugs | 865998 |
milestone | 25.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/devtools/webconsole/test/Makefile.in +++ b/browser/devtools/webconsole/test/Makefile.in @@ -181,18 +181,16 @@ MOCHITEST_BROWSER_FILES += \ test-bug-595934-css-loader.css \ test-bug-595934-css-loader.css^headers^ \ test-bug-595934-imagemap.html \ test-bug-595934-html.html \ test-bug-595934-malformedxml.xhtml \ test-bug-595934-svg.xhtml \ test-bug-595934-workers.html \ test-bug-595934-workers.js \ - test-bug-595934-canvas.html \ - test-bug-595934-canvas.js \ test-bug-595934-css-parser.html \ test-bug-595934-css-parser.css \ test-bug-595934-canvas-css.html \ test-bug-595934-canvas-css.js \ test-bug-595934-malformedxml-external.html \ test-bug-595934-malformedxml-external.xml \ test-bug-595934-empty-getelementbyid.html \ test-bug-595934-empty-getelementbyid.js \
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js @@ -41,41 +41,36 @@ const TESTS = [ matchString: "no element found", }, { // #5 file: "test-bug-595934-svg.xhtml", category: "SVG", matchString: "fooBarSVG", }, { // #6 - file: "test-bug-595934-canvas.html", - category: "Canvas", - matchString: "strokeStyle", - }, - { // #7 file: "test-bug-595934-css-parser.html", category: "CSS Parser", matchString: "foobarCssParser", }, - { // #8 + { // #7 file: "test-bug-595934-malformedxml-external.html", category: "malformed-xml", matchString: "</html>", }, - { // #9 + { // #8 file: "test-bug-595934-empty-getelementbyid.html", category: "DOM", matchString: "getElementById", }, - { // #10 + { // #9 file: "test-bug-595934-canvas-css.html", category: "CSS Parser", matchString: "foobarCanvasCssParser", }, - { // #11 + { // #10 file: "test-bug-595934-image.html", category: "Image", matchString: "corrupt", }, ]; let pos = -1;
deleted file mode 100644 --- a/browser/devtools/webconsole/test/test-bug-595934-canvas.html +++ /dev/null @@ -1,15 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8"> - <title>Web Console test for bug 595934 - category: Canvas</title> -<!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> - <script type="text/javascript" - src="test-bug-595934-canvas.js"></script> - </head> - <body> - <p>Web Console test for bug 595934 - category "Canvas".</p> - <p><canvas width="200" height="200">Canvas support is required!</canvas></p> - </body> -</html>
deleted file mode 100644 --- a/browser/devtools/webconsole/test/test-bug-595934-canvas.js +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -window.addEventListener("DOMContentLoaded", function() { - var canvas = document.querySelector("canvas"); - var context = canvas.getContext("2d"); - context.strokeStyle = document; -}, false); -
--- a/content/canvas/src/CanvasGradient.h +++ b/content/canvas/src/CanvasGradient.h @@ -8,27 +8,23 @@ #include "mozilla/Attributes.h" #include "nsTArray.h" #include "mozilla/RefPtr.h" #include "mozilla/dom/CanvasRenderingContext2DBinding.h" #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/gfx/2D.h" #include "nsWrapperCache.h" -#define NS_CANVASGRADIENTAZURE_PRIVATE_IID \ - {0x28425a6a, 0x90e0, 0x4d42, {0x9c, 0x75, 0xff, 0x60, 0x09, 0xb3, 0x10, 0xa8}} - namespace mozilla { namespace dom { class CanvasGradient : public nsISupports, public nsWrapperCache { public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENTAZURE_PRIVATE_IID) NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CanvasGradient) enum Type { LINEAR = 0, RADIAL };
--- a/content/canvas/src/CanvasPattern.h +++ b/content/canvas/src/CanvasPattern.h @@ -7,32 +7,29 @@ #include "mozilla/Attributes.h" #include "mozilla/dom/CanvasRenderingContext2DBinding.h" #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/RefPtr.h" #include "nsISupports.h" #include "nsWrapperCache.h" -#define NS_CANVASPATTERNAZURE_PRIVATE_IID \ - {0xc9bacc25, 0x28da, 0x421e, {0x9a, 0x4b, 0xbb, 0xd6, 0x93, 0x05, 0x12, 0xbc}} class nsIPrincipal; namespace mozilla { namespace gfx { class SourceSurface; } namespace dom { class CanvasPattern MOZ_FINAL : public nsISupports, public nsWrapperCache { public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERNAZURE_PRIVATE_IID) NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CanvasPattern) enum RepeatMode { REPEAT, REPEATX, REPEATY,
--- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -87,20 +87,21 @@ #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "mozilla/unused.h" #include "nsCCUncollectableMarker.h" #include "nsWrapperCacheInlines.h" #include "nsJSUtils.h" #include "XPCQuickStubs.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/CanvasRenderingContext2DBinding.h" #include "mozilla/dom/HTMLImageElement.h" #include "mozilla/dom/HTMLVideoElement.h" -#include "mozilla/dom/CanvasRenderingContext2DBinding.h" #include "mozilla/dom/TextMetrics.h" +#include "mozilla/dom/UnionTypes.h" #ifdef USE_SKIA_GPU #undef free // apparently defined by some windows header, clashing with a free() // method in SkTypes.h #include "GLContext.h" #include "GLContextProvider.h" #include "GLContextSkia.h" #include "SurfaceTypes.h" @@ -395,39 +396,33 @@ CanvasGradient::AddColorStop(float offse GradientStop newStop; newStop.offset = offset; newStop.color = Color::FromABGR(color); mRawStops.AppendElement(newStop); } -NS_DEFINE_STATIC_IID_ACCESSOR(CanvasGradient, NS_CANVASGRADIENTAZURE_PRIVATE_IID) - NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasGradient) NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasGradient) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(CanvasGradient, mContext) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasGradient) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(mozilla::dom::CanvasGradient) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_DEFINE_STATIC_IID_ACCESSOR(CanvasPattern, NS_CANVASPATTERNAZURE_PRIVATE_IID) - NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasPattern) NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasPattern) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(CanvasPattern, mContext) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasPattern) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(mozilla::dom::CanvasPattern) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END class CanvasRenderingContext2DUserData : public LayerUserData { public: CanvasRenderingContext2DUserData(CanvasRenderingContext2D *aContext) : mContext(aContext) { @@ -643,62 +638,42 @@ CanvasRenderingContext2D::Reset() // Since the target changes the backing texture will change, and this will // no longer be valid. mIsEntireFrameInvalid = false; mPredictManyRedrawCalls = false; return NS_OK; } -static void -WarnAboutUnexpectedStyle(HTMLCanvasElement* canvasElement) -{ - nsContentUtils::ReportToConsole( - nsIScriptError::warningFlag, - "Canvas", - canvasElement ? canvasElement->OwnerDoc() : nullptr, - nsContentUtils::eDOM_PROPERTIES, - "UnexpectedCanvasVariantStyle"); -} - void CanvasRenderingContext2D::SetStyleFromString(const nsAString& str, Style whichStyle) { MOZ_ASSERT(!str.IsVoid()); nscolor color; if (!ParseColor(str, &color)) { return; } CurrentState().SetColorStyle(whichStyle, color); } -nsISupports* -CanvasRenderingContext2D::GetStyleAsStringOrInterface(nsAString& aStr, - CanvasMultiGetterType& aType, - Style aWhichStyle) +void +CanvasRenderingContext2D::GetStyleAsUnion(StringOrCanvasGradientOrCanvasPatternReturnValue& aValue, + Style aWhichStyle) { const ContextState &state = CurrentState(); - nsISupports* supports; if (state.patternStyles[aWhichStyle]) { - aStr.SetIsVoid(true); - supports = state.patternStyles[aWhichStyle]; - aType = CMG_STYLE_PATTERN; + aValue.SetAsCanvasPattern() = state.patternStyles[aWhichStyle]; } else if (state.gradientStyles[aWhichStyle]) { - aStr.SetIsVoid(true); - supports = state.gradientStyles[aWhichStyle]; - aType = CMG_STYLE_GRADIENT; + aValue.SetAsCanvasGradient() = state.gradientStyles[aWhichStyle]; } else { - StyleColorToString(state.colorStyles[aWhichStyle], aStr); - supports = nullptr; - aType = CMG_STYLE_STRING; + StyleColorToString(state.colorStyles[aWhichStyle], aValue.SetAsString()); } - return supports; } // static void CanvasRenderingContext2D::StyleColorToString(const nscolor& aColor, nsAString& aStr) { // We can't reuse the normal CSS color stringification code, // because the spec calls for a different algorithm for canvas. @@ -1344,102 +1319,35 @@ CanvasRenderingContext2D::GetMozCurrentT return MatrixToJSObject(cx, ctm, error); } // // colors // void -CanvasRenderingContext2D::SetStyleFromJSValue(JSContext* cx, - JS::Handle<JS::Value> value, - Style whichStyle) +CanvasRenderingContext2D::SetStyleFromUnion(const StringOrCanvasGradientOrCanvasPattern& value, + Style whichStyle) { - if (value.isString()) { - nsDependentJSString strokeStyle; - if (strokeStyle.init(cx, value.toString())) { - SetStyleFromString(strokeStyle, whichStyle); - } + if (value.IsString()) { + SetStyleFromString(value.GetAsString(), whichStyle); return; } - if (value.isObject()) { - nsCOMPtr<nsISupports> holder; - - CanvasGradient* gradient; - JS::Rooted<JS::Value> rootedVal(cx, value); - nsresult rv = xpc_qsUnwrapArg<CanvasGradient>(cx, value, &gradient, - static_cast<nsISupports**>(getter_AddRefs(holder)), - rootedVal.address()); - if (NS_SUCCEEDED(rv)) { - SetStyleFromGradient(gradient, whichStyle); - return; - } - - CanvasPattern* pattern; - rv = xpc_qsUnwrapArg<CanvasPattern>(cx, value, &pattern, - static_cast<nsISupports**>(getter_AddRefs(holder)), - rootedVal.address()); - if (NS_SUCCEEDED(rv)) { - SetStyleFromPattern(pattern, whichStyle); - return; - } + if (value.IsCanvasGradient()) { + SetStyleFromGradient(value.GetAsCanvasGradient(), whichStyle); + return; } - WarnAboutUnexpectedStyle(mCanvasElement); -} - -static JS::Value -WrapStyle(JSContext* cx, JSObject* objArg, - CanvasRenderingContext2D::CanvasMultiGetterType type, - nsAString& str, nsISupports* supports, ErrorResult& error) -{ - JS::Rooted<JS::Value> v(cx); - bool ok; - switch (type) { - case CanvasRenderingContext2D::CMG_STYLE_STRING: - { - ok = xpc::StringToJsval(cx, str, v.address()); - break; - } - case CanvasRenderingContext2D::CMG_STYLE_PATTERN: - case CanvasRenderingContext2D::CMG_STYLE_GRADIENT: - { - JS::Rooted<JSObject*> obj(cx, objArg); - ok = dom::WrapObject(cx, obj, supports, &v); - break; - } - default: - MOZ_CRASH("unexpected CanvasMultiGetterType"); + if (value.IsCanvasPattern()) { + SetStyleFromPattern(value.GetAsCanvasPattern(), whichStyle); + return; } - if (!ok) { - error.Throw(NS_ERROR_FAILURE); - } - return v; -} - - -JS::Value -CanvasRenderingContext2D::GetStrokeStyle(JSContext* cx, - ErrorResult& error) -{ - nsString str; - CanvasMultiGetterType t; - nsISupports* supports = GetStyleAsStringOrInterface(str, t, STYLE_STROKE); - return WrapStyle(cx, GetWrapper(), t, str, supports, error); -} - -JS::Value -CanvasRenderingContext2D::GetFillStyle(JSContext* cx, - ErrorResult& error) -{ - nsString str; - CanvasMultiGetterType t; - nsISupports* supports = GetStyleAsStringOrInterface(str, t, STYLE_FILL); - return WrapStyle(cx, GetWrapper(), t, str, supports, error); + + MOZ_ASSUME_UNREACHABLE("Invalid union value"); } void CanvasRenderingContext2D::SetFillRule(const nsAString& aString) { FillRule rule; if (aString.EqualsLiteral("evenodd"))
--- a/content/canvas/src/CanvasRenderingContext2D.h +++ b/content/canvas/src/CanvasRenderingContext2D.h @@ -12,47 +12,49 @@ #include "mozilla/RefPtr.h" #include "nsColor.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLVideoElement.h" #include "CanvasUtils.h" #include "gfxFont.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/ImageData.h" -#include "mozilla/dom/UnionTypes.h" #include "mozilla/dom/CanvasGradient.h" #include "mozilla/dom/CanvasRenderingContext2DBinding.h" #include "mozilla/dom/CanvasPattern.h" #include "mozilla/gfx/Rect.h" class nsXULElement; namespace mozilla { namespace gfx { class SourceSurface; } namespace dom { +class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement; +class StringOrCanvasGradientOrCanvasPattern; +class StringOrCanvasGradientOrCanvasPatternReturnValue; class TextMetrics; extern const mozilla::gfx::Float SIGMA_MAX; template<typename T> class Optional; struct CanvasBidiProcessor; class CanvasRenderingContext2DUserData; /** ** CanvasRenderingContext2D **/ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal, public nsWrapperCache { -typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement +typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement HTMLImageOrCanvasOrVideoElement; public: CanvasRenderingContext2D(); virtual ~CanvasRenderingContext2D(); virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) MOZ_OVERRIDE; @@ -86,28 +88,35 @@ public: if (globalAlpha >= 0.0 && globalAlpha <= 1.0) { CurrentState().globalAlpha = ToFloat(globalAlpha); } } void GetGlobalCompositeOperation(nsAString& op, mozilla::ErrorResult& error); void SetGlobalCompositeOperation(const nsAString& op, mozilla::ErrorResult& error); - JS::Value GetStrokeStyle(JSContext* cx, mozilla::ErrorResult& error); - void SetStrokeStyle(JSContext* cx, JS::Handle<JS::Value> value) + void GetStrokeStyle(StringOrCanvasGradientOrCanvasPatternReturnValue& value) { - SetStyleFromJSValue(cx, value, STYLE_STROKE); + GetStyleAsUnion(value, STYLE_STROKE); } - JS::Value GetFillStyle(JSContext* cx, mozilla::ErrorResult& error); + void SetStrokeStyle(const StringOrCanvasGradientOrCanvasPattern& value) + { + SetStyleFromUnion(value, STYLE_STROKE); + } - void SetFillStyle(JSContext* cx, JS::Handle<JS::Value> value) + void GetFillStyle(StringOrCanvasGradientOrCanvasPatternReturnValue& value) { - SetStyleFromJSValue(cx, value, STYLE_FILL); + GetStyleAsUnion(value, STYLE_FILL); + } + + void SetFillStyle(const StringOrCanvasGradientOrCanvasPattern& value) + { + SetStyleFromUnion(value, STYLE_FILL); } already_AddRefed<CanvasGradient> CreateLinearGradient(double x0, double y0, double x1, double y1); already_AddRefed<CanvasGradient> CreateRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1, ErrorResult& aError); already_AddRefed<CanvasPattern> @@ -157,20 +166,20 @@ public: void StrokeRect(double x, double y, double w, double h); void BeginPath(); void Fill(const CanvasWindingRule& winding); void Stroke(); void Clip(const CanvasWindingRule& winding); bool IsPointInPath(double x, double y, const CanvasWindingRule& winding); bool IsPointInStroke(double x, double y); void FillText(const nsAString& text, double x, double y, - const mozilla::dom::Optional<double>& maxWidth, + const Optional<double>& maxWidth, mozilla::ErrorResult& error); void StrokeText(const nsAString& text, double x, double y, - const mozilla::dom::Optional<double>& maxWidth, + const Optional<double>& maxWidth, mozilla::ErrorResult& error); TextMetrics* MeasureText(const nsAString& rawText, mozilla::ErrorResult& error); void DrawImage(const HTMLImageOrCanvasOrVideoElement& image, double dx, double dy, mozilla::ErrorResult& error) { DrawImage(image, 0.0, 0.0, 0.0, 0.0, dx, dy, 0.0, 0.0, 0, error); @@ -185,28 +194,28 @@ public: void DrawImage(const HTMLImageOrCanvasOrVideoElement& image, double sx, double sy, double sw, double sh, double dx, double dy, double dw, double dh, mozilla::ErrorResult& error) { DrawImage(image, sx, sy, sw, sh, dx, dy, dw, dh, 6, error); } - already_AddRefed<mozilla::dom::ImageData> + already_AddRefed<ImageData> CreateImageData(JSContext* cx, double sw, double sh, mozilla::ErrorResult& error); - already_AddRefed<mozilla::dom::ImageData> - CreateImageData(JSContext* cx, mozilla::dom::ImageData& imagedata, + already_AddRefed<ImageData> + CreateImageData(JSContext* cx, ImageData& imagedata, mozilla::ErrorResult& error); - already_AddRefed<mozilla::dom::ImageData> + already_AddRefed<ImageData> GetImageData(JSContext* cx, double sx, double sy, double sw, double sh, mozilla::ErrorResult& error); - void PutImageData(mozilla::dom::ImageData& imageData, + void PutImageData(ImageData& imageData, double dx, double dy, mozilla::ErrorResult& error); - void PutImageData(mozilla::dom::ImageData& imageData, + void PutImageData(ImageData& imageData, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight, mozilla::ErrorResult& error); double LineWidth() { return CurrentState().lineWidth; } @@ -266,17 +275,17 @@ public: mDSPathBuilder->MoveTo(mTarget->GetTransform() * mozilla::gfx::Point(ToFloat(x), ToFloat(y))); } } void LineTo(double x, double y) { EnsureWritablePath(); - + LineTo(mozilla::gfx::Point(ToFloat(x), ToFloat(y))); } void QuadraticCurveTo(double cpx, double cpy, double x, double y) { EnsureWritablePath(); if (mPathBuilder) { @@ -469,31 +478,32 @@ protected: /** * Lookup table used to speed up PutImageData(). */ static uint8_t (*sPremultiplyTable)[256]; static mozilla::gfx::DrawTarget* sErrorTarget; // Some helpers. Doesn't modify a color on failure. - void SetStyleFromJSValue(JSContext* cx, JS::Handle<JS::Value> value, - Style whichStyle); + void SetStyleFromUnion(const StringOrCanvasGradientOrCanvasPattern& value, + Style whichStyle); void SetStyleFromString(const nsAString& str, Style whichStyle); - void SetStyleFromGradient(CanvasGradient *gradient, Style whichStyle) + void SetStyleFromGradient(CanvasGradient& gradient, Style whichStyle) { - CurrentState().SetGradientStyle(whichStyle, gradient); + CurrentState().SetGradientStyle(whichStyle, &gradient); } - void SetStyleFromPattern(CanvasPattern *pattern, Style whichStyle) + void SetStyleFromPattern(CanvasPattern& pattern, Style whichStyle) { - CurrentState().SetPatternStyle(whichStyle, pattern); + CurrentState().SetPatternStyle(whichStyle, &pattern); } - nsISupports* GetStyleAsStringOrInterface(nsAString& aStr, CanvasMultiGetterType& aType, Style aWhichStyle); + void GetStyleAsUnion(StringOrCanvasGradientOrCanvasPatternReturnValue& aValue, + Style aWhichStyle); // Returns whether a color was successfully parsed. bool ParseColor(const nsAString& aString, nscolor* aColor); static void StyleColorToString(const nscolor& aColor, nsAString& aStr); /** * Creates the error target, if it doesn't exist @@ -711,17 +721,17 @@ protected: /* * Implementation of the fillText, strokeText, and measure functions with * the operation abstracted to a flag. */ nsresult DrawOrMeasureText(const nsAString& text, float x, float y, - const mozilla::dom::Optional<double>& maxWidth, + const Optional<double>& maxWidth, TextDrawOperation op, float* aWidth); // state stack handling class ContextState { public: ContextState() : textAlign(TEXT_ALIGN_START), textBaseline(TEXT_BASELINE_ALPHABETIC),
--- a/content/html/content/src/HTMLCanvasElement.cpp +++ b/content/html/content/src/HTMLCanvasElement.cpp @@ -8,16 +8,17 @@ #include "BasicLayers.h" #include "imgIEncoder.h" #include "jsapi.h" #include "jsfriendapi.h" #include "mozilla/Base64.h" #include "mozilla/CheckedInt.h" #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/dom/HTMLCanvasElementBinding.h" +#include "mozilla/dom/UnionTypes.h" #include "mozilla/gfx/Rect.h" #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "nsAsyncDOMEvent.h" #include "nsAttrValueInlines.h" #include "nsContentUtils.h" #include "nsDisplayList.h" #include "nsDOMFile.h"
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -154,18 +154,17 @@ DOMInterfaces = { 'CameraManager': { 'nativeType': 'nsDOMCameraManager', 'headerFile': 'DOMCameraManager.h' }, 'CanvasRenderingContext2D': { 'implicitJSContext': [ - 'createImageData', 'getImageData', 'strokeStyle', - 'fillStyle', 'mozDash' + 'createImageData', 'getImageData', 'mozDash' ], 'resultNotAddRefed': [ 'canvas', 'measureText' ], 'binaryNames': { 'mozImageSmoothingEnabled': 'imageSmoothingEnabled', 'mozFillRule': 'fillRule' } },
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -4,16 +4,17 @@ # Common codegen classes. import operator import os import re import string import math +import itertools from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor AUTOGENERATED_WARNING_COMMENT = \ "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n" ADDPROPERTY_HOOK_NAME = '_addProperty' FINALIZE_HOOK_NAME = '_finalize' @@ -730,32 +731,37 @@ def UnionTypes(descriptors, dictionaries """ # Now find all the things we'll need as arguments and return values because # we need to wrap or unwrap them. headers = set() implheaders = set(["UnionTypes.h"]) declarations = set() unionStructs = dict() + unionReturnValues = dict() def addInfoForType(t, descriptor=None, dictionary=None): """ Add info for the given type. descriptor and dictionary, if passed, are used to figure out what to do with interface types. """ assert not descriptor or not dictionary t = t.unroll() if not t.isUnion(): return name = str(t) if not name in unionStructs: providers = getRelevantProviders(descriptor, dictionary, config) # FIXME: Unions are broken in workers. See bug 809899. unionStructs[name] = CGUnionStruct(t, providers[0]) + # Unions cannot contain JSObject*. + if not any(member.isObject() or member.isSpiderMonkeyInterface() for member in t.flatMemberTypes): + unionReturnValues[name] = CGUnionReturnValueStruct(t, providers[0]) + for f in t.flatMemberTypes: f = f.unroll() if f.isInterface(): if f.isSpiderMonkeyInterface(): headers.add("jsfriendapi.h") headers.add("mozilla/dom/TypedArray.h") else: for p in providers: @@ -767,17 +773,18 @@ def UnionTypes(descriptors, dictionaries implheaders.add(typeDesc.headerFile) elif f.isDictionary(): declarations.add((f.inner.identifier.name, True)) implheaders.add(CGHeaders.getDeclarationFilename(f.inner)) callForEachType(descriptors, dictionaries, callbacks, addInfoForType) return (headers, implheaders, declarations, - CGList(SortedDictValues(unionStructs), "\n")) + CGList(itertools.chain(SortedDictValues(unionStructs), + SortedDictValues(unionReturnValues)), "\n")) def UnionConversions(descriptors, dictionaries, callbacks, config): """ Returns a CGThing to declare all union argument conversion helper structs. """ # Now find all the things we'll need as arguments because we # need to unwrap them. headers = set() @@ -2064,17 +2071,17 @@ def GetAccessCheck(descriptor, object): def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturnValue=""): """ properties is a PropertyArrays instance """ failureReturn = "return" if len(failureReturnValue) > 0: failureReturn += " " + failureReturnValue failureReturn += ";" - + defineUnforgeables = ("if (!DefineUnforgeableAttributes(aCx, " + obj + ", %s)) {\n" " " + failureReturn + "\n" "}") unforgeableAttrs = properties.unforgeableAttrs unforgeables = [] if unforgeableAttrs.hasNonChromeOnly(): unforgeables.append(CGGeneric(defineUnforgeables % @@ -2483,16 +2490,17 @@ def getJSToNativeConversionInfo(type, de treatUndefinedAs="Default", isEnforceRange=False, isClamp=False, isNullOrUndefined=False, exceptionCode=None, lenientFloatCode=None, allowTreatNonCallableAsNull=False, isCallbackReturnValue=False, + isInUnionReturnValue=False, sourceDescription="value"): """ Get a template for converting a JS value to a native object based on the given type and descriptor. If failureCode is given, then we're actually testing whether we can convert the argument to the desired type. That means that failures to convert due to the JS value being the wrong type of value need to use failureCode instead of throwing exceptions. Failures to convert that are due to JS exceptions (from toString or valueOf methods) or @@ -3031,23 +3039,26 @@ for (uint32_t i = 0; i < length; ++i) { # Allow null pointers for nullable types and old-binding classes, and # use an nsRefPtr or raw pointer for callback return values to make # them easier to return. argIsPointer = (type.nullable() or type.unroll().inner.isExternal() or isCallbackReturnValue) # Sequences and non-worker callbacks have to hold a strong ref to the - # thing being passed down. Also, callback return values always end up + # thing being passed down. Union return values must hold a strong ref + # because they may be returning an addrefed pointer. + # Also, callback return values always end up # addrefing anyway, so there is no point trying to avoid it here and it # makes other things simpler since we can assume the return value is a # strong ref. forceOwningType = ((descriptor.interface.isCallback() and not descriptor.workers) or isMember or + isInUnionReturnValue or isCallbackReturnValue) typeName = descriptor.nativeType typePtr = typeName + "*" # Compute a few things: # - declType is the type we want to return as the first element of our # tuple. @@ -3254,16 +3265,18 @@ for (uint32_t i = 0; i < length; ++i) { " FakeDependentString str;\n" "%s\n" " ${declName} = str;\n" "}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(), declType=declType, dealWithOptional=isOptional) if isOptional: declType = "Optional<nsAString>" + elif isInUnionReturnValue: + declType = "nsString" else: declType = "NonNull<nsAString>" # No need to deal with optional here; we handled it already return JSToNativeConversionInfo( "%s\n" "${declName} = &${holderName};" % getConversionCode("${holderName}"), @@ -4095,35 +4108,31 @@ if (!returnArray) { toValue = "JS::ObjectValue(*%s)" if type.isSpiderMonkeyInterface(): wrapType = "nonDOMObject" else: wrapType = "object" # NB: setValue(..., True) calls JS_WrapValue(), so is fallible return (setValue(toValue % result, wrapType), False) - if type.isUnion(): - if type.nullable(): - prefix = "%s->" - else: - prefix = "%s." - return (wrapAndSetPtr((prefix % result) + - "ToJSVal(cx, ${obj}, ${jsvalHandle})"), False) - - if not (type.isPrimitive() or type.isDictionary() or type.isDate()): + if not (type.isUnion() or type.isPrimitive() or type.isDictionary() or type.isDate()): raise TypeError("Need to learn to wrap %s" % type) if type.nullable(): (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider, "%s.Value()" % result, successCode, isCreator, exceptionCode) return ("if (%s.IsNull()) {\n" % result + CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" + "}\n" + recTemplate, recInfal) + if type.isUnion(): + return (wrapAndSetPtr("%s.ToJSVal(cx, ${obj}, ${jsvalHandle})" % result), + False) + if type.isDictionary(): return (wrapAndSetPtr("%s.ToObject(cx, ${obj}, ${jsvalHandle})" % result), False) if type.isDate(): return (wrapAndSetPtr("%s.ToDateObject(cx, ${jsvalHandle})" % result), False) @@ -4317,17 +4326,20 @@ def getRetvalDeclarationForType(returnTy else: result = CGTemplatedType("RootedDictionary", result) resultArgs = "cx" elif nullable: result = CGTemplatedType("Nullable", result) resultArgs = None return result, True, None, resultArgs if returnType.isUnion(): - raise TypeError("Need to sort out ownership model for union retvals"); + result = CGGeneric(returnType.unroll().name + "ReturnValue") + if returnType.nullable(): + result = CGTemplatedType("Nullable", result) + return result, True, None, None if returnType.isDate(): result = CGGeneric("Date") if returnType.nullable(): result = CGTemplatedType("Nullable", result) return result, False, None, None raise TypeError("Don't know how to declare return value for %s" % returnType) @@ -4425,17 +4437,17 @@ class CGCallGenerator(CGThing): if not resultOutParam: call = CGWrapper(call, pre="result = ") call = CGWrapper(call) self.cgRoot.append(call) if isFallible: self.cgRoot.prepend(CGGeneric("ErrorResult rv;")) - self.cgRoot.append(CGGeneric("rv.WouldReportJSException();")); + self.cgRoot.append(CGGeneric("rv.WouldReportJSException();")) self.cgRoot.append(CGGeneric("if (rv.Failed()) {")) self.cgRoot.append(CGIndenter(errorReport)) self.cgRoot.append(CGGeneric("}")) def define(self): return self.cgRoot.define() class MethodNotCreatorError(Exception): @@ -5834,17 +5846,17 @@ def getUnionAccessorSignatureType(type, if not type.isPrimitive(): raise TypeError("Need native type for argument type '%s'" % str(type)) typeName = CGGeneric(builtinNames[type.tag()]) if type.nullable(): typeName = CGTemplatedType("Nullable", typeName, isReference=True) return typeName -def getUnionTypeTemplateVars(unionType, type, descriptorProvider): +def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isReturnValue=False): # For dictionaries and sequences we need to pass None as the failureCode # for getJSToNativeConversionInfo. # Also, for dictionaries we would need to handle conversion of # null/undefined to the dictionary correctly. if type.isDictionary() or type.isSequence(): raise TypeError("Can't handle dictionaries or sequences in unions") if type.isGeckoInterface(): @@ -5859,17 +5871,17 @@ def getUnionTypeTemplateVars(unionType, tryNextCode = """tryNext = true; return true;""" if type.isGeckoInterface(): tryNextCode = ("""if (mUnion.mType != mUnion.eUninitialized) { mUnion.Destroy%s(); }""" % name) + tryNextCode conversionInfo = getJSToNativeConversionInfo( type, descriptorProvider, failureCode=tryNextCode, - isDefinitelyObject=True, + isDefinitelyObject=True, isInUnionReturnValue=isReturnValue, sourceDescription="member of %s" % unionType) # This is ugly, but UnionMember needs to call a constructor with no # arguments so the type can't be const. structType = conversionInfo.declType.define() if structType.startswith("const "): structType = structType[6:] externalType = getUnionAccessorSignatureType(type, descriptorProvider).define() @@ -5953,17 +5965,17 @@ class CGUnionStruct(CGThing): } ${externalType} GetAs${name}() const { MOZ_ASSERT(Is${name}(), "Wrong type!"); return const_cast<${structType}&>(mValue.m${name}.Value()); }""" methods.extend(mapTemplate(methodTemplate, templateVars)) # Now have to be careful: we do not want the SetAsObject() method! - setterTemplate = """ ${structType}& SetAs${name}() + setterTemplate = """ ${structType}& SetAs${name}() { mType = e${name}; return mValue.m${name}.SetValue(); }""" methods.extend(mapTemplate(setterTemplate, filter(lambda v: v["name"] != "Object", templateVars))) values = mapTemplate("UnionMember<${structType} > m${name};", templateVars) @@ -6015,17 +6027,17 @@ private: }) def define(self): templateVars = self.templateVars conversionsToJS = [] if self.type.hasNullableType: conversionsToJS.append(" case eNull:\n" " {\n" - " rval.set(JS::NullValue());\n" + " rval.setNull();\n" " return true;\n" " }") conversionsToJS.extend( map(self.getConversionToJS, zip(templateVars, self.type.flatMemberTypes))) return string.Template("""bool ${structName}::ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj, @@ -6057,17 +6069,171 @@ private: val = "%s.get()->Obj()" % val wrapCode = wrapForType( type, self.descriptorProvider, { "jsvalRef": "rval", "jsvalHandle": "rval", "obj": "scopeObj", "result": val, - "objectCanBeNonNull": True + }) + return CGIndenter(CGList([CGGeneric("case e%(name)s:" % templateVars), + CGWrapper(CGIndenter(CGGeneric(wrapCode)), + pre="{\n", + post="\n}")], + "\n"), + 4).define() + +class CGUnionReturnValueStruct(CGThing): + def __init__(self, type, descriptorProvider): + CGThing.__init__(self) + self.type = type.unroll() + self.descriptorProvider = descriptorProvider + self.templateVars = map( + lambda t: getUnionTypeTemplateVars(self.type, t, + self.descriptorProvider, + isReturnValue=True), + self.type.flatMemberTypes) + + def declare(self): + templateVars = self.templateVars + + enumValues = [] + methods = [] + if self.type.hasNullableType: + enumValues.append("eNull") + methods.append(""" bool IsNull() const + { + return mType == eNull; + } + + bool SetNull() + { + mType = eNull; + return true; + }""") + + enumValues.extend(mapTemplate("e${name}", templateVars)) + methodTemplate = " ${structType}& SetAs${name}();" + methods.extend(mapTemplate(methodTemplate, templateVars)) + values = mapTemplate("UnionMember<${structType} > m${name};", templateVars) + return string.Template(""" +class ${structName}ReturnValue { +public: + ${structName}ReturnValue() : mType(eUninitialized) + { + } + ~${structName}ReturnValue(); + +${methods} + + bool ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj, + JS::MutableHandle<JS::Value> rval) const; + +private: + enum Type { + eUninitialized, + ${enumValues} + }; + union Value { + ${values} + }; + + Type mType; + Value mValue; +}; + +""").substitute( + { + "structName": self.type.__str__(), + "methods": "\n\n".join(methods), + "enumValues": ",\n ".join(enumValues), + "values": "\n ".join(values) + }) + + def define(self): + templateVars = self.templateVars + conversionsToJS = [] + if self.type.hasNullableType: + conversionsToJS.append(" case eNull:\n" + " {\n" + " rval.setNull();\n" + " return true;\n" + " }") + conversionsToJS.extend( + map(self.getConversionToJS, + zip(templateVars, self.type.flatMemberTypes))) + + toJSVal = string.Template(""" + +bool +${structName}ReturnValue::ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj, JS::MutableHandle<JS::Value> rval) const +{ + switch (mType) { +${doConversionsToJS} + + case eUninitialized: + { + break; + } + } + return false; +} +""").substitute({ + "structName": str(self.type), + "doConversionsToJS": "\n\n".join(conversionsToJS) + }) + templateVars = self.templateVars + + methods = [] + methodTemplate = """${structType}& +%sReturnValue::SetAs${name}() +{ + mType = e${name}; + return mValue.m${name}.SetValue(); +}""" % str(self.type) + methods.extend(mapTemplate(methodTemplate, templateVars)) + + callDestructors = [] + if self.type.hasNullableType: + callDestructors.append(" case eNull:\n" + " break;") + callDestructors.extend(mapTemplate(" case e${name}:\n" + " mValue.m${name}.Destroy();\n" + " mType = eUninitialized;\n" + " break;", templateVars)) + destructor = string.Template(""" +${structName}ReturnValue::~${structName}ReturnValue() +{ + switch (mType) { +${callDestructors} + case eUninitialized: + break; + } +} + +""").substitute( + { + "structName": self.type.__str__(), + "callDestructors": "\n".join(callDestructors), + }) + + return destructor + "\n\n".join(methods) + toJSVal + + def getConversionToJS(self, arg): + (templateVars, type) = arg + assert not type.nullable() # flatMemberTypes never has nullable types + val = "mValue.m%(name)s.Value()" % templateVars + wrapCode = wrapForType( + type, self.descriptorProvider, + { + "jsvalRef": "rval", + "jsvalHandle": "rval", + "obj": "scopeObj", + "result": val, }) return CGIndenter(CGList([CGGeneric("case e%(name)s:" % templateVars), CGWrapper(CGIndenter(CGGeneric(wrapCode)), pre="{\n", post="\n}")], "\n"), 4).define()
--- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -2499,17 +2499,17 @@ class IDLAttribute(IDLInterfaceMember): if self.type.isDictionary(): raise WebIDLError("An attribute cannot be of a dictionary type", [self.location]) if self.type.isSequence(): raise WebIDLError("An attribute cannot be of a sequence type", [self.location]) if self.type.isUnion(): - for f in self.type.flatMemberTypes: + for f in self.type.unroll().flatMemberTypes: if f.isDictionary(): raise WebIDLError("An attribute cannot be of a union " "type if one of its member types (or " "one of its member types's member " "types, and so on) is a dictionary " "type", [self.location, f.location]) if f.isSequence(): raise WebIDLError("An attribute cannot be of a union "
--- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -502,16 +502,26 @@ public: //void PassUnionWithInterfaces(const TestInterfaceOrTestExternalInterface& arg); //void PassUnionWithInterfacesAndNullable(const TestInterfaceOrNullOrTestExternalInterface& arg); void PassUnionWithArrayBuffer(const ArrayBufferOrLong&); void PassUnionWithString(JSContext*, const StringOrObject&); //void PassUnionWithEnum(JSContext*, const TestEnumOrObject&); //void PassUnionWithCallback(JSContext*, const TestCallbackOrLong&); void PassUnionWithObject(JSContext*, const ObjectOrLong&); + void ReceiveUnion(const CanvasPatternOrCanvasGradientReturnValue&); + void ReceiveUnionContainingNull(const CanvasPatternOrNullOrCanvasGradientReturnValue&); + void ReceiveNullableUnion(const Nullable<CanvasPatternOrCanvasGradientReturnValue>&); + void GetWritableUnion(const CanvasPatternOrCanvasGradientReturnValue&); + void SetWritableUnion(const CanvasPatternOrCanvasGradient&); + void GetWritableUnionContainingNull(const CanvasPatternOrNullOrCanvasGradientReturnValue&); + void SetWritableUnionContainingNull(const CanvasPatternOrNullOrCanvasGradient&); + void GetWritableNullableUnion(const Nullable<CanvasPatternOrCanvasGradientReturnValue>&); + void SetWritableNullableUnion(const Nullable<CanvasPatternOrCanvasGradient>&); + // Date types void PassDate(Date); void PassNullableDate(const Nullable<Date>&); void PassOptionalDate(const Optional<Date>&); void PassOptionalNullableDate(const Optional<Nullable<Date> >&); void PassOptionalNullableDateWithDefaultValue(const Nullable<Date>&); void PassDateSequence(const Sequence<Date>&); void PassNullableDateSequence(const Sequence<Nullable<Date> >&);
--- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -447,16 +447,24 @@ interface TestInterface { void passUnionWithString((DOMString or object) arg); //void passUnionWithEnum((TestEnum or object) arg); // Trying to use a callback in a union won't include the test // headers, unfortunately, so won't compile. //void passUnionWithCallback((TestCallback or long) arg); void passUnionWithObject((object or long) arg); //void passUnionWithDict((Dict or long) arg); + (CanvasPattern or CanvasGradient) receiveUnion(); + (CanvasPattern? or CanvasGradient) receiveUnionContainingNull(); + (CanvasPattern or CanvasGradient)? receiveNullableUnion(); + + attribute (CanvasPattern or CanvasGradient) writableUnion; + attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull; + attribute (CanvasPattern or CanvasGradient)? writableNullableUnion; + // Date types void passDate(Date arg); void passNullableDate(Date? arg); void passOptionalDate(optional Date arg); void passOptionalNullableDate(optional Date? arg); void passOptionalNullableDateWithDefaultValue(optional Date? arg = null); void passDateSequence(sequence<Date> arg); void passNullableDateSequence(sequence<Date?> arg);
--- a/dom/bindings/test/TestExampleGen.webidl +++ b/dom/bindings/test/TestExampleGen.webidl @@ -343,16 +343,24 @@ interface TestExampleInterface { void passUnionWithString((DOMString or object) arg); //void passUnionWithEnum((TestEnum or object) arg); // Trying to use a callback in a union won't include the test // headers, unfortunately, so won't compile. // void passUnionWithCallback((TestCallback or long) arg); void passUnionWithObject((object or long) arg); //void passUnionWithDict((Dict or long) arg); + //(CanvasPattern or CanvasGradient) receiveUnion(); + //(CanvasPattern? or CanvasGradient) receiveUnionContainingNull(); + //(CanvasPattern or CanvasGradient)? receiveNullableUnion(); + + //attribute (CanvasPattern or CanvasGradient) writableUnion; + //attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull; + //attribute (CanvasPattern or CanvasGradient)? writableNullableUnion; + // Date types void passDate(Date arg); void passNullableDate(Date? arg); void passOptionalDate(optional Date arg); void passOptionalNullableDate(optional Date? arg); void passOptionalNullableDateWithDefaultValue(optional Date? arg = null); void passDateSequence(sequence<Date> arg); void passNullableDateSequence(sequence<Date?> arg);
--- a/dom/bindings/test/TestJSImplGen.webidl +++ b/dom/bindings/test/TestJSImplGen.webidl @@ -367,16 +367,24 @@ interface TestJSImplInterface { void passUnionWithString((DOMString or object) arg); //void passUnionWithEnum((MyTestEnum or object) arg); // Trying to use a callback in a union won't include the test // headers, unfortunately, so won't compile. // void passUnionWithCallback((MyTestCallback or long) arg); void passUnionWithObject((object or long) arg); //void passUnionWithDict((Dict or long) arg); + //(CanvasPattern or CanvasGradient) receiveUnion(); + //(CanvasPattern? or CanvasGradient) receiveUnionContainingNull(); + //(CanvasPattern or CanvasGradient)? receiveNullableUnion(); + + //attribute (CanvasPattern or CanvasGradient) writableUnion; + //attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull; + //attribute (CanvasPattern or CanvasGradient)? writableNullableUnion; + // Date types void passDate(Date arg); void passNullableDate(Date? arg); void passOptionalDate(optional Date arg); void passOptionalNullableDate(optional Date? arg); void passOptionalNullableDateWithDefaultValue(optional Date? arg = null); void passDateSequence(sequence<Date> arg); void passNullableDateSequence(sequence<Date?> arg);
--- a/dom/src/events/Makefile.in +++ b/dom/src/events/Makefile.in @@ -12,9 +12,10 @@ FAIL_ON_WARNINGS := 1 include $(DEPTH)/config/autoconf.mk MSVC_ENABLE_PGO := 1 LIBXUL_LIBRARY = 1 include $(topsrcdir)/config/rules.mk INCLUDES += -I$(topsrcdir)/dom/base +INCLUDES += -I$(topsrcdir)/content/base/src
--- a/dom/webidl/CanvasRenderingContext2D.webidl +++ b/dom/webidl/CanvasRenderingContext2D.webidl @@ -41,20 +41,18 @@ interface CanvasRenderingContext2D { // NOT IMPLEMENTED void resetTransform(); // compositing attribute unrestricted double globalAlpha; // (default 1.0) [Throws] attribute DOMString globalCompositeOperation; // (default source-over) // colors and styles (see also the CanvasDrawingStyles interface) - [GetterThrows] - attribute any strokeStyle; // (default black) - [GetterThrows] - attribute any fillStyle; // (default black) + attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black) + attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) [Creator] CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1); [Creator, Throws] CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1); [Creator, Throws] CanvasPattern createPattern((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, [TreatNullAs=EmptyString] DOMString repetition); // shadows