diff --git a/browser/components/shell/src/nsMacShellService.h b/browser/components/shell/src/nsMacShellService.h index 285ae1e93252..7ca1c71ac325 100644 --- a/browser/components/shell/src/nsMacShellService.h +++ b/browser/components/shell/src/nsMacShellService.h @@ -16,7 +16,6 @@ class nsMacShellService : public nsIMacShellService, { public: nsMacShellService() : mCheckedThisSession(false) {}; - virtual ~nsMacShellService() {}; NS_DECL_ISUPPORTS NS_DECL_NSISHELLSERVICE @@ -24,6 +23,7 @@ public: NS_DECL_NSIWEBPROGRESSLISTENER protected: + virtual ~nsMacShellService() {}; private: nsCOMPtr mBackgroundFile; diff --git a/content/base/src/DOMMatrix.h b/content/base/src/DOMMatrix.h index 7ae3541f043c..19d0ae21f00a 100644 --- a/content/base/src/DOMMatrix.h +++ b/content/base/src/DOMMatrix.h @@ -43,10 +43,6 @@ public: SetIsDOMBinding(); } - ~DOMMatrixReadOnly() - { - } - #define GetMatrixMember(entry2D, entry3D, default) \ { \ if (mMatrix3D) { \ @@ -135,6 +131,10 @@ protected: nsCOMPtr mParent; nsAutoPtr mMatrix2D; nsAutoPtr mMatrix3D; + + ~DOMMatrixReadOnly() + { + } private: DOMMatrixReadOnly() MOZ_DELETE; DOMMatrixReadOnly(const DOMMatrixReadOnly&) MOZ_DELETE; @@ -248,6 +248,8 @@ public: DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv); private: void Ensure3DMatrix(); + + ~DOMMatrix() {} }; } diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 2e71468c61e0..d064ab517ff3 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -1385,7 +1385,6 @@ public: NS_DECL_NSIDOMEVENTLISTENER WebGLObserver(WebGLContext* aContext); - ~WebGLObserver(); void Destroy(); @@ -1396,6 +1395,8 @@ public: void UnregisterMemoryPressureEvent(); private: + ~WebGLObserver(); + WebGLContext* mContext; }; diff --git a/content/svg/content/src/SVGCircleElement.cpp b/content/svg/content/src/SVGCircleElement.cpp index eed1ded5f9cb..3b233d6a82b0 100644 --- a/content/svg/content/src/SVGCircleElement.cpp +++ b/content/svg/content/src/SVGCircleElement.cpp @@ -94,7 +94,7 @@ SVGCircleElement::ConstructPath(gfxContext *aCtx) } TemporaryRef -SVGCircleElement::BuildPath() +SVGCircleElement::BuildPath(PathBuilder* aBuilder) { float x, y, r; GetAnimatedLengthValues(&x, &y, &r, nullptr); @@ -103,7 +103,7 @@ SVGCircleElement::BuildPath() return nullptr; } - RefPtr pathBuilder = CreatePathBuilder(); + RefPtr pathBuilder = aBuilder ? aBuilder : CreatePathBuilder(); pathBuilder->Arc(Point(x, y), r, 0, Float(2*M_PI)); diff --git a/content/svg/content/src/SVGCircleElement.h b/content/svg/content/src/SVGCircleElement.h index ab18beb4c889..9c4e675144ec 100644 --- a/content/svg/content/src/SVGCircleElement.h +++ b/content/svg/content/src/SVGCircleElement.h @@ -31,7 +31,7 @@ public: // nsSVGPathGeometryElement methods: virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE; - virtual TemporaryRef BuildPath() MOZ_OVERRIDE; + virtual TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; diff --git a/content/svg/content/src/SVGContentUtils.cpp b/content/svg/content/src/SVGContentUtils.cpp index a6d8c288e983..f414d99420c7 100644 --- a/content/svg/content/src/SVGContentUtils.cpp +++ b/content/svg/content/src/SVGContentUtils.cpp @@ -8,8 +8,13 @@ #include "SVGContentUtils.h" // Keep others in (case-insensitive) order: +#include "gfx2DGlue.h" #include "gfxMatrix.h" +#include "gfxPlatform.h" +#include "gfxSVGGlyphs.h" +#include "mozilla/gfx/2D.h" #include "mozilla/dom/SVGSVGElement.h" +#include "mozilla/RefPtr.h" #include "nsComputedDOMStyle.h" #include "nsFontMetrics.h" #include "nsIFrame.h" @@ -20,12 +25,14 @@ #include "nsContentUtils.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Types.h" -#include "gfx2DGlue.h" +#include "nsStyleContext.h" #include "nsSVGPathDataParser.h" #include "SVGPathData.h" +#include "SVGPathElement.h" using namespace mozilla; using namespace mozilla::dom; +using namespace mozilla::gfx; SVGSVGElement* SVGContentUtils::GetOuterSVGElement(nsSVGElement *aSVGElement) @@ -54,6 +61,179 @@ SVGContentUtils::ActivateByHyperlink(nsIContent *aContent) static_cast(aContent)->ActivateByHyperlink(); } +enum DashState { + eDashedStroke, + eContinuousStroke, //< all dashes, no gaps + eNoStroke //< all gaps, no dashes +}; + +static DashState +GetStrokeDashData(SVGContentUtils::AutoStrokeOptions* aStrokeOptions, + nsSVGElement* aElement, + const nsStyleSVG* aStyleSVG, + gfxTextContextPaint *aContextPaint) +{ + size_t dashArrayLength; + Float totalLengthOfDashes = 0.0, totalLengthOfGaps = 0.0; + + if (aContextPaint && aStyleSVG->mStrokeDasharrayFromObject) { + const FallibleTArray& dashSrc = aContextPaint->GetStrokeDashArray(); + dashArrayLength = dashSrc.Length(); + if (dashArrayLength <= 0) { + return eContinuousStroke; + } + Float* dashPattern = aStrokeOptions->InitDashPattern(dashArrayLength); + if (!dashPattern) { + return eContinuousStroke; + } + for (size_t i = 0; i < dashArrayLength; i++) { + if (dashSrc[i] < 0.0) { + return eContinuousStroke; // invalid + } + dashPattern[i] = Float(dashSrc[i]); + (i % 2 ? totalLengthOfGaps : totalLengthOfDashes) += dashSrc[i]; + } + } else { + const nsStyleCoord *dasharray = aStyleSVG->mStrokeDasharray; + dashArrayLength = aStyleSVG->mStrokeDasharrayLength; + if (dashArrayLength <= 0) { + return eContinuousStroke; + } + Float pathScale = 1.0; + if (aElement->Tag() == nsGkAtoms::path) { + pathScale = static_cast(aElement)-> + GetPathLengthScale(SVGPathElement::eForStroking); + if (pathScale <= 0) { + return eContinuousStroke; + } + } + Float* dashPattern = aStrokeOptions->InitDashPattern(dashArrayLength); + if (!dashPattern) { + return eContinuousStroke; + } + for (uint32_t i = 0; i < dashArrayLength; i++) { + Float dashLength = + SVGContentUtils::CoordToFloat(aElement, dasharray[i]) * pathScale; + if (dashLength < 0.0) { + return eContinuousStroke; // invalid + } + dashPattern[i] = dashLength; + (i % 2 ? totalLengthOfGaps : totalLengthOfDashes) += dashLength; + } + } + + // Now that aStrokeOptions.mDashPattern is fully initialized we can safely + // set mDashLength: + aStrokeOptions->mDashLength = dashArrayLength; + + if (totalLengthOfDashes <= 0 || totalLengthOfGaps <= 0) { + if (totalLengthOfGaps > 0 && totalLengthOfDashes <= 0) { + return eNoStroke; + } + return eContinuousStroke; + } + + if (aContextPaint && aStyleSVG->mStrokeDashoffsetFromObject) { + aStrokeOptions->mDashOffset = Float(aContextPaint->GetStrokeDashOffset()); + } else { + aStrokeOptions->mDashOffset = + SVGContentUtils::CoordToFloat(aElement, aStyleSVG->mStrokeDashoffset); + } + + return eDashedStroke; +} + +void +SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions, + nsSVGElement* aElement, + nsStyleContext* aStyleContext, + gfxTextContextPaint *aContextPaint) +{ + nsRefPtr styleContext; + if (aStyleContext) { + styleContext = aStyleContext; + } else { + styleContext = + nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr, + nullptr); + } + + if (!styleContext) { + return; + } + + const nsStyleSVG* styleSVG = styleContext->StyleSVG(); + + DashState dashState = + GetStrokeDashData(aStrokeOptions, aElement, styleSVG, aContextPaint); + + if (dashState == eNoStroke) { + // Hopefully this will shortcircuit any stroke operations: + aStrokeOptions->mLineWidth = 0; + return; + } + if (dashState == eContinuousStroke) { + // Prevent our caller from wasting time looking at the dash array: + aStrokeOptions->mDashLength = 0; + } + + aStrokeOptions->mLineWidth = + GetStrokeWidth(aElement, styleContext, aContextPaint); + + aStrokeOptions->mMiterLimit = Float(styleSVG->mStrokeMiterlimit); + + switch (styleSVG->mStrokeLinejoin) { + case NS_STYLE_STROKE_LINEJOIN_MITER: + aStrokeOptions->mLineJoin = JoinStyle::MITER; + break; + case NS_STYLE_STROKE_LINEJOIN_ROUND: + aStrokeOptions->mLineJoin = JoinStyle::ROUND; + break; + case NS_STYLE_STROKE_LINEJOIN_BEVEL: + aStrokeOptions->mLineJoin = JoinStyle::BEVEL; + break; + } + + switch (styleSVG->mStrokeLinecap) { + case NS_STYLE_STROKE_LINECAP_BUTT: + aStrokeOptions->mLineCap = CapStyle::BUTT; + break; + case NS_STYLE_STROKE_LINECAP_ROUND: + aStrokeOptions->mLineCap = CapStyle::ROUND; + break; + case NS_STYLE_STROKE_LINECAP_SQUARE: + aStrokeOptions->mLineCap = CapStyle::SQUARE; + break; + } +} + +Float +SVGContentUtils::GetStrokeWidth(nsSVGElement* aElement, + nsStyleContext* aStyleContext, + gfxTextContextPaint *aContextPaint) +{ + nsRefPtr styleContext; + if (aStyleContext) { + styleContext = aStyleContext; + } else { + styleContext = + nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr, + nullptr); + } + + if (!styleContext) { + return 0.0f; + } + + const nsStyleSVG* styleSVG = styleContext->StyleSVG(); + + if (aContextPaint && styleSVG->mStrokeWidthFromObject) { + return aContextPaint->GetStrokeWidth(); + } + + return SVGContentUtils::CoordToFloat(aElement, styleSVG->mStrokeWidth); +} + float SVGContentUtils::GetFontSize(Element *aElement) { @@ -596,5 +776,10 @@ SVGContentUtils::GetPath(const nsAString& aPathString) return NULL; } - return pathData.BuildPath(mozilla::gfx::FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 1); + RefPtr drawTarget = + gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); + RefPtr builder = + drawTarget->CreatePathBuilder(FillRule::FILL_WINDING); + + return pathData.BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 1); } diff --git a/content/svg/content/src/SVGContentUtils.h b/content/svg/content/src/SVGContentUtils.h index 7f8a8b3fd54f..178dc747beb8 100644 --- a/content/svg/content/src/SVGContentUtils.h +++ b/content/svg/content/src/SVGContentUtils.h @@ -10,12 +10,15 @@ #define _USE_MATH_DEFINES #include +#include "mozilla/fallible.h" +#include "mozilla/gfx/2D.h" // for StrokeOptions #include "mozilla/gfx/Matrix.h" #include "mozilla/RangedPtr.h" #include "nsError.h" #include "nsStringFwd.h" #include "gfx2DGlue.h" +class gfxTextContextPaint; class nsIContent; class nsIDocument; class nsIFrame; @@ -58,6 +61,8 @@ IsSVGWhitespace(char16_t aChar) class SVGContentUtils { public: + typedef mozilla::gfx::Float Float; + typedef mozilla::gfx::StrokeOptions StrokeOptions; typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio; typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio; @@ -76,6 +81,64 @@ public: */ static void ActivateByHyperlink(nsIContent *aContent); + /** + * Moz2D's StrokeOptions requires someone else to own its mDashPattern + * buffer, which is a pain when you want to initialize a StrokeOptions object + * in a helper function and pass it out. This sub-class owns the mDashPattern + * buffer so that consumers of such a helper function don't need to worry + * about creating it, passing it in, or deleting it. (An added benefit is + * that in the typical case when stroke-dasharray is short it will avoid + * allocating.) + */ + struct AutoStrokeOptions : public StrokeOptions { + AutoStrokeOptions() + { + MOZ_ASSERT(mDashLength == 0, "InitDashPattern() depends on this"); + } + ~AutoStrokeOptions() { + if (mDashPattern && mDashPattern != mSmallArray) { + delete [] mDashPattern; + } + } + /** + * Creates the buffer to store the stroke-dasharray, assuming out-of-memory + * does not occur. The buffer's address is assigned to mDashPattern and + * returned to the caller as a non-const pointer (so that the caller can + * initialize the values in the buffer, since mDashPattern is const). + */ + Float* InitDashPattern(size_t aDashCount) { + if (aDashCount <= MOZ_ARRAY_LENGTH(mSmallArray)) { + mDashPattern = mSmallArray; + return mSmallArray; + } + static const mozilla::fallible_t fallible = mozilla::fallible_t(); + Float* nonConstArray = new (fallible) Float[aDashCount]; + mDashPattern = nonConstArray; + return nonConstArray; + } + private: + // Most dasharrays will fit in this and save us allocating + Float mSmallArray[16]; + }; + + static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions, + nsSVGElement* aElement, + nsStyleContext* aStyleContext, + gfxTextContextPaint *aContextPaint); + + /** + * Returns the current computed value of the CSS property 'stroke-width' for + * the given element. aStyleContext may be provided as an optimization. + * aContextPaint is also optional. + * + * Note that this function does NOT take account of the value of the 'stroke' + * and 'stroke-opacity' properties to, say, return zero if they are "none" or + * "0", respectively. + */ + static Float GetStrokeWidth(nsSVGElement* aElement, + nsStyleContext* aStyleContext, + gfxTextContextPaint *aContextPaint); + /* * Get the number of CSS px (user units) per em (i.e. the em-height in user * units) for an nsIContent diff --git a/content/svg/content/src/SVGEllipseElement.cpp b/content/svg/content/src/SVGEllipseElement.cpp index 9aa96dbf66a8..502286e94276 100644 --- a/content/svg/content/src/SVGEllipseElement.cpp +++ b/content/svg/content/src/SVGEllipseElement.cpp @@ -7,6 +7,7 @@ #include "mozilla/dom/SVGEllipseElementBinding.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/PathHelpers.h" +#include "mozilla/RefPtr.h" #include "gfxContext.h" NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Ellipse) @@ -96,7 +97,12 @@ void SVGEllipseElement::ConstructPath(gfxContext *aCtx) { if (!aCtx->IsCairo()) { - RefPtr path = BuildPath(); + RefPtr dt = aCtx->GetDrawTarget(); + FillRule fillRule = + aCtx->CurrentFillRule() == gfxContext::FILL_RULE_WINDING ? + FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD; + RefPtr builder = dt->CreatePathBuilder(fillRule); + RefPtr path = BuildPath(builder); if (path) { nsRefPtr gfxpath = new gfxPath(path); aCtx->SetPath(gfxpath); @@ -114,7 +120,7 @@ SVGEllipseElement::ConstructPath(gfxContext *aCtx) } TemporaryRef -SVGEllipseElement::BuildPath() +SVGEllipseElement::BuildPath(PathBuilder* aBuilder) { float x, y, rx, ry; GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr); @@ -123,7 +129,7 @@ SVGEllipseElement::BuildPath() return nullptr; } - RefPtr pathBuilder = CreatePathBuilder(); + RefPtr pathBuilder = aBuilder ? aBuilder : CreatePathBuilder(); EllipseToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry)); diff --git a/content/svg/content/src/SVGEllipseElement.h b/content/svg/content/src/SVGEllipseElement.h index 4d54241d4bc8..0e6a4e8a73e2 100644 --- a/content/svg/content/src/SVGEllipseElement.h +++ b/content/svg/content/src/SVGEllipseElement.h @@ -31,7 +31,7 @@ public: // nsSVGPathGeometryElement methods: virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE; - virtual TemporaryRef BuildPath() MOZ_OVERRIDE; + virtual TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; diff --git a/content/svg/content/src/SVGImageElement.cpp b/content/svg/content/src/SVGImageElement.cpp index 4f45def1a4c0..69a62da71e40 100644 --- a/content/svg/content/src/SVGImageElement.cpp +++ b/content/svg/content/src/SVGImageElement.cpp @@ -241,7 +241,7 @@ SVGImageElement::ConstructPath(gfxContext *aCtx) } TemporaryRef -SVGImageElement::BuildPath() +SVGImageElement::BuildPath(PathBuilder* aBuilder) { // We get called in order to get bounds for this element, and for // hit-testing against it. For that we just pretend to be a rectangle. @@ -253,7 +253,7 @@ SVGImageElement::BuildPath() return nullptr; } - RefPtr pathBuilder = CreatePathBuilder(); + RefPtr pathBuilder = aBuilder ? aBuilder : CreatePathBuilder(); Rect r(x, y, width, height); pathBuilder->MoveTo(r.TopLeft()); diff --git a/content/svg/content/src/SVGImageElement.h b/content/svg/content/src/SVGImageElement.h index add2f11aae27..bd7061dbd4c1 100644 --- a/content/svg/content/src/SVGImageElement.h +++ b/content/svg/content/src/SVGImageElement.h @@ -54,7 +54,7 @@ public: // nsSVGPathGeometryElement methods: virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE; - virtual TemporaryRef BuildPath() MOZ_OVERRIDE; + virtual TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE; // nsSVGSVGElement methods: virtual bool HasValidDimensions() const MOZ_OVERRIDE; diff --git a/content/svg/content/src/SVGLineElement.cpp b/content/svg/content/src/SVGLineElement.cpp index 563987c5d7d9..873424e0b8d0 100644 --- a/content/svg/content/src/SVGLineElement.cpp +++ b/content/svg/content/src/SVGLineElement.cpp @@ -119,9 +119,9 @@ SVGLineElement::ConstructPath(gfxContext *aCtx) } TemporaryRef -SVGLineElement::BuildPath() +SVGLineElement::BuildPath(PathBuilder* aBuilder) { - RefPtr pathBuilder = CreatePathBuilder(); + RefPtr pathBuilder = aBuilder ? aBuilder : CreatePathBuilder(); float x1, y1, x2, y2; GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr); diff --git a/content/svg/content/src/SVGLineElement.h b/content/svg/content/src/SVGLineElement.h index 205725db7713..ce5833d3471f 100644 --- a/content/svg/content/src/SVGLineElement.h +++ b/content/svg/content/src/SVGLineElement.h @@ -33,7 +33,7 @@ public: virtual bool IsMarkable() MOZ_OVERRIDE { return true; } virtual void GetMarkPoints(nsTArray *aMarks) MOZ_OVERRIDE; virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE; - virtual TemporaryRef BuildPath() MOZ_OVERRIDE; + virtual TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const; diff --git a/content/svg/content/src/SVGPathData.cpp b/content/svg/content/src/SVGPathData.cpp index f131d86161bc..5f9dc6c7c804 100644 --- a/content/svg/content/src/SVGPathData.cpp +++ b/content/svg/content/src/SVGPathData.cpp @@ -302,7 +302,7 @@ ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx) } while(0) TemporaryRef -SVGPathData::BuildPath(FillRule aFillRule, +SVGPathData::BuildPath(PathBuilder* builder, uint8_t aStrokeLineCap, Float aStrokeWidth) const { @@ -310,14 +310,6 @@ SVGPathData::BuildPath(FillRule aFillRule, return nullptr; // paths without an initial moveto are invalid } - RefPtr drawTarget = - gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); - NS_ASSERTION(gfxPlatform::GetPlatform()-> - SupportsAzureContentForDrawTarget(drawTarget), - "Should support Moz2D content drawing"); - - RefPtr builder = drawTarget->CreatePathBuilder(aFillRule); - bool capsAreSquare = aStrokeLineCap == NS_STYLE_STROKE_LINECAP_SQUARE; bool subpathHasLength = false; // visual length bool subpathContainsNonArc = false; @@ -814,15 +806,19 @@ TemporaryRef SVGPathData::ToPathForLengthOrPositionMeasuring() const { // Since the path that we return will not be used for painting it doesn't - // matter what we pass to BuildPath as aFillRule. Hawever, we do want to - // pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as aStrokeLineCap - // to avoid the insertion of extra little lines (by + // matter what we pass to CreatePathBuilder as aFillRule. Hawever, we do want + // to pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as + // aStrokeLineCap to avoid the insertion of extra little lines (by // ApproximateZeroLengthSubpathSquareCaps), in which case the value that we // pass as aStrokeWidth doesn't matter (since it's only used to determine the // length of those extra little lines). if (!mCachedPath) { - mCachedPath = BuildPath(FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0); + RefPtr drawTarget = + gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); + RefPtr builder = + drawTarget->CreatePathBuilder(FillRule::FILL_WINDING); + mCachedPath = BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 0); } return mCachedPath; diff --git a/content/svg/content/src/SVGPathData.h b/content/svg/content/src/SVGPathData.h index 292e8d430739..8fc6f66d91c8 100644 --- a/content/svg/content/src/SVGPathData.h +++ b/content/svg/content/src/SVGPathData.h @@ -84,6 +84,7 @@ class SVGPathData typedef gfx::DrawTarget DrawTarget; typedef gfx::Path Path; + typedef gfx::PathBuilder PathBuilder; typedef gfx::FillRule FillRule; typedef gfx::Float Float; typedef gfx::CapStyle CapStyle; @@ -166,7 +167,7 @@ public: TemporaryRef ToPathForLengthOrPositionMeasuring() const; void ConstructPath(gfxContext *aCtx) const; - TemporaryRef BuildPath(FillRule aFillRule, + TemporaryRef BuildPath(PathBuilder* aBuilder, uint8_t aCapStyle, Float aStrokeWidth) const; diff --git a/content/svg/content/src/SVGPathElement.cpp b/content/svg/content/src/SVGPathElement.cpp index 19f338cbf9af..b05f0e5a469a 100644 --- a/content/svg/content/src/SVGPathElement.cpp +++ b/content/svg/content/src/SVGPathElement.cpp @@ -11,8 +11,10 @@ #include "DOMSVGPathSegList.h" #include "DOMSVGPoint.h" #include "gfx2DGlue.h" +#include "gfxPlatform.h" #include "mozilla/dom/SVGPathElementBinding.h" #include "mozilla/gfx/2D.h" +#include "mozilla/RefPtr.h" #include "nsCOMPtr.h" #include "nsComputedDOMStyle.h" #include "nsGkAtoms.h" @@ -370,7 +372,7 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor) } TemporaryRef -SVGPathElement::BuildPath() +SVGPathElement::BuildPath(PathBuilder* aBuilder) { // The Moz2D PathBuilder that our SVGPathData will be using only cares about // the fill rule. However, in order to fulfill the requirements of the SVG @@ -392,19 +394,28 @@ SVGPathElement::BuildPath() // opacity here. if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) { strokeLineCap = style->mStrokeLinecap; - strokeWidth = GetStrokeWidth(); + strokeWidth = SVGContentUtils::GetStrokeWidth(this, styleContext, nullptr); } } - // The fill rule that we pass must be the current - // computed value of our CSS 'fill-rule' property if the path that we return - // will be used for painting or hit-testing. For all other uses (bounds - // calculatons, length measurement, position-at-offset calculations) the fill - // rule that we pass doesn't matter. As a result we can just pass the current - // computed value regardless of who's calling us, or what they're going to do - // with the path that we return. + RefPtr builder; + if (aBuilder) { + builder = aBuilder; + } else { + RefPtr drawTarget = + gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); + // The fill rule that we pass must be the current computed value of our + // CSS 'fill-rule' property if the path that we return will be used for + // painting or hit-testing. For all other uses (bounds calculatons, length + // measurement, position-at-offset calculations) the fill rule that we pass + // doesn't matter. As a result we can just pass the current computed value + // regardless of who's calling us, or what they're going to do with the + // path that we return. + RefPtr builder = + drawTarget->CreatePathBuilder(GetFillRule()); + } - return mD.GetAnimValue().BuildPath(GetFillRule(), strokeLineCap, strokeWidth); + return mD.GetAnimValue().BuildPath(builder, strokeLineCap, strokeWidth); } } // namespace dom diff --git a/content/svg/content/src/SVGPathElement.h b/content/svg/content/src/SVGPathElement.h index 81bc7d3dd801..9eccd65372f2 100644 --- a/content/svg/content/src/SVGPathElement.h +++ b/content/svg/content/src/SVGPathElement.h @@ -53,7 +53,7 @@ public: virtual bool IsMarkable() MOZ_OVERRIDE; virtual void GetMarkPoints(nsTArray *aMarks) MOZ_OVERRIDE; virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE; - virtual TemporaryRef BuildPath() MOZ_OVERRIDE; + virtual TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE; /** * This returns a path without the extra little line segments that diff --git a/content/svg/content/src/SVGRectElement.cpp b/content/svg/content/src/SVGRectElement.cpp index 6cb3306724e4..2074f2148038 100644 --- a/content/svg/content/src/SVGRectElement.cpp +++ b/content/svg/content/src/SVGRectElement.cpp @@ -153,7 +153,7 @@ SVGRectElement::ConstructPath(gfxContext *aCtx) } TemporaryRef -SVGRectElement::BuildPath() +SVGRectElement::BuildPath(PathBuilder* aBuilder) { float x, y, width, height, rx, ry; GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr); @@ -162,7 +162,7 @@ SVGRectElement::BuildPath() return nullptr; } - RefPtr pathBuilder = CreatePathBuilder(); + RefPtr pathBuilder = aBuilder ? aBuilder : CreatePathBuilder(); rx = std::max(rx, 0.0f); ry = std::max(ry, 0.0f); diff --git a/content/svg/content/src/SVGRectElement.h b/content/svg/content/src/SVGRectElement.h index 62fc30a6d177..36d8c774f80b 100644 --- a/content/svg/content/src/SVGRectElement.h +++ b/content/svg/content/src/SVGRectElement.h @@ -31,7 +31,7 @@ public: // nsSVGPathGeometryElement methods: virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE; - virtual TemporaryRef BuildPath() MOZ_OVERRIDE; + virtual TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; diff --git a/content/svg/content/src/nsSVGPathGeometryElement.cpp b/content/svg/content/src/nsSVGPathGeometryElement.cpp index c63ca8aa862b..982c0c753aad 100644 --- a/content/svg/content/src/nsSVGPathGeometryElement.cpp +++ b/content/svg/content/src/nsSVGPathGeometryElement.cpp @@ -111,15 +111,3 @@ nsSVGPathGeometryElement::GetFillRule() return fillRule; } - -Float -nsSVGPathGeometryElement::GetStrokeWidth() -{ - nsRefPtr styleContext = - nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr, - nullptr); - return styleContext ? - SVGContentUtils::CoordToFloat(this, - styleContext->StyleSVG()->mStrokeWidth) : - 0.0f; -} diff --git a/content/svg/content/src/nsSVGPathGeometryElement.h b/content/svg/content/src/nsSVGPathGeometryElement.h index 1609713879b8..ccdebaa114ac 100644 --- a/content/svg/content/src/nsSVGPathGeometryElement.h +++ b/content/svg/content/src/nsSVGPathGeometryElement.h @@ -62,7 +62,7 @@ public: * Returns a Path that can be used to paint, hit-test or calculate bounds for * this element. May return nullptr if there is no [valid] path. */ - virtual mozilla::TemporaryRef BuildPath() = 0; + virtual mozilla::TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) = 0; virtual mozilla::TemporaryRef GetPathForLengthOrPositionMeasuring(); @@ -77,14 +77,6 @@ public: * this element. */ FillRule GetFillRule(); - - /** - * Returns the current computed value of the CSS property 'stroke-width' for - * this element. (I.e. this does NOT take account of the value of the - * 'stroke' and 'stroke-opacity' properties to, say, return zero if they are - * "none" or "0", respectively.) - */ - Float GetStrokeWidth(); }; #endif diff --git a/content/svg/content/src/nsSVGPolyElement.cpp b/content/svg/content/src/nsSVGPolyElement.cpp index da42b21a71df..a807186af7f3 100644 --- a/content/svg/content/src/nsSVGPolyElement.cpp +++ b/content/svg/content/src/nsSVGPolyElement.cpp @@ -132,7 +132,7 @@ nsSVGPolyElement::ConstructPath(gfxContext *aCtx) } TemporaryRef -nsSVGPolyElement::BuildPath() +nsSVGPolyElement::BuildPath(PathBuilder* aBuilder) { const SVGPointList &points = mPoints.GetAnimValue(); @@ -140,7 +140,7 @@ nsSVGPolyElement::BuildPath() return nullptr; } - RefPtr pathBuilder = CreatePathBuilder(); + RefPtr pathBuilder = aBuilder ? aBuilder : CreatePathBuilder(); pathBuilder->MoveTo(points[0]); for (uint32_t i = 1; i < points.Length(); ++i) { diff --git a/content/svg/content/src/nsSVGPolyElement.h b/content/svg/content/src/nsSVGPolyElement.h index 4213937803ba..53c031f7555a 100644 --- a/content/svg/content/src/nsSVGPolyElement.h +++ b/content/svg/content/src/nsSVGPolyElement.h @@ -46,7 +46,7 @@ public: virtual bool IsMarkable() MOZ_OVERRIDE { return true; } virtual void GetMarkPoints(nsTArray *aMarks) MOZ_OVERRIDE; virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE; - virtual mozilla::TemporaryRef BuildPath() MOZ_OVERRIDE; + virtual mozilla::TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE; // WebIDL already_AddRefed Points(); diff --git a/content/svg/content/test/bounds-helper.svg b/content/svg/content/test/bounds-helper.svg index 1fe00b9d1a56..6e08ba8f6f87 100644 --- a/content/svg/content/test/bounds-helper.svg +++ b/content/svg/content/test/bounds-helper.svg @@ -6,6 +6,13 @@ text { font: 20px monospace; } + + + + + + + abc abc diff --git a/content/svg/content/test/test_bounds.html b/content/svg/content/test/test_bounds.html index fcd43ef36a44..d74c2e5d12d9 100644 --- a/content/svg/content/test/test_bounds.html +++ b/content/svg/content/test/test_bounds.html @@ -44,6 +44,24 @@ function runTest() { var doc = $("svg").contentWindow.document; + var svg1Bounds = doc.getElementById("svg1").getBoundingClientRect(); + is(svg1Bounds.left, 10, "svg1.getBoundingClientRect().left"); + is(svg1Bounds.top, 10, "svg1.getBoundingClientRect().top"); + is(svg1Bounds.width, 25, "svg1.getBoundingClientRect().width"); + is(svg1Bounds.height, 30, "svg1.getBoundingClientRect().height"); + + var svg2Bounds = doc.getElementById("svg2").getBoundingClientRect(); + is(svg2Bounds.left, 0, "svg2.getBoundingClientRect().left"); + is(svg2Bounds.top, 0, "svg2.getBoundingClientRect().top"); + is(svg2Bounds.width, 2, "svg2.getBoundingClientRect().width"); + is(svg2Bounds.height, 2, "svg2.getBoundingClientRect().height"); + + var svg3Bounds = doc.getElementById("svg3").getBoundingClientRect(); + is(svg3Bounds.left, 0, "svg3.getBoundingClientRect().left"); + is(svg3Bounds.top, 0, "svg3.getBoundingClientRect().top"); + is(svg3Bounds.width, 1, "svg3.getBoundingClientRect().width"); + is(svg3Bounds.height, 1, "svg3.getBoundingClientRect().height"); + var text1 = doc.getElementById("text1"); var text1Bounds = text1.getBoundingClientRect(); diff --git a/content/svg/content/test/test_pointer-events-3.xhtml b/content/svg/content/test/test_pointer-events-3.xhtml index 78e428e70f8d..7981002237fb 100644 --- a/content/svg/content/test/test_pointer-events-3.xhtml +++ b/content/svg/content/test/test_pointer-events-3.xhtml @@ -22,7 +22,7 @@ function run() var originY = div.offsetTop; var circle = document.getElementById("circle"); - var elementFromPoint = document.elementFromPoint(originX + 150, originY + 51); + var elementFromPoint = document.elementFromPoint(originX + 150, originY + 52); is(elementFromPoint, circle, "Top of circle should hit"); var elementFromPoint = document.elementFromPoint(originX + 249, originY + 150); @@ -44,10 +44,10 @@ function run()
-
+
diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm
index 55c37a2ee41f..216fef131e59 100755
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -2135,7 +2135,7 @@ this.DOMApplicationRegistry = {
       if (xhr.status == 200) {
         if (!AppsUtils.checkManifestContentType(app.installOrigin, app.origin,
                                                 xhr.getResponseHeader("content-type"))) {
-          sendError("INVALID_MANIFEST");
+          sendError("INVALID_MANIFEST_CONTENT_TYPE");
           return;
         }
 
@@ -2235,7 +2235,7 @@ this.DOMApplicationRegistry = {
       if (xhr.status == 200) {
         if (!AppsUtils.checkManifestContentType(app.installOrigin, app.origin,
                                                 xhr.getResponseHeader("content-type"))) {
-          sendError("INVALID_MANIFEST");
+          sendError("INVALID_MANIFEST_CONTENT_TYPE");
           return;
         }
 
diff --git a/dom/apps/tests/test_packaged_app_install.html b/dom/apps/tests/test_packaged_app_install.html
index 1eb8fb132202..e3f40b7967f1 100644
--- a/dom/apps/tests/test_packaged_app_install.html
+++ b/dom/apps/tests/test_packaged_app_install.html
@@ -110,7 +110,7 @@ var steps = [
     var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&noManifestContentType=true";
-    checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
+    checkAppInstallError(miniManifestURL, "INVALID_MANIFEST_CONTENT_TYPE");
   },
   function() {
     // Test mini-manifest 'size' value is not number. Bug 839435.
diff --git a/dom/datastore/DataStoreDB.cpp b/dom/datastore/DataStoreDB.cpp
index 743dfc2ecc71..40255757549d 100644
--- a/dom/datastore/DataStoreDB.cpp
+++ b/dom/datastore/DataStoreDB.cpp
@@ -68,6 +68,8 @@ public:
 
 private:
   IDBDatabase* mDatabase;
+
+  ~VersionChangeListener() {}
 };
 
 NS_IMPL_ISUPPORTS(VersionChangeListener, nsIDOMEventListener)
diff --git a/dom/tests/mochitest/general/test_offsets.xul b/dom/tests/mochitest/general/test_offsets.xul
index 329389064b9d..ff054dbca2a4 100644
--- a/dom/tests/mochitest/general/test_offsets.xul
+++ b/dom/tests/mochitest/general/test_offsets.xul
@@ -32,9 +32,12 @@
   
 
 
+
+
+
diff --git a/dom/tests/mochitest/webapps/test_install_errors.xul b/dom/tests/mochitest/webapps/test_install_errors.xul index fadf97e614af..f5b9db73456e 100644 --- a/dom/tests/mochitest/webapps/test_install_errors.xul +++ b/dom/tests/mochitest/webapps/test_install_errors.xul @@ -91,7 +91,7 @@ function invalidContent(next) { var request = navigator.mozApps.install(url, null); request.onerror = function onInstallError() { - is(this.error.name, "INVALID_MANIFEST", "manifest with bad content type"); + is(this.error.name, "INVALID_MANIFEST_CONTENT_TYPE", "manifest with bad content type"); next(); }; diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index 1e40cd7d8f3e..47c021f008a9 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -213,6 +213,9 @@ class ServiceWorkerUpdateInstance MOZ_FINAL : public nsISupports nsCOMPtr mWindow; bool mAborted; + + ~ServiceWorkerUpdateInstance() {} + public: NS_DECL_ISUPPORTS diff --git a/dom/xml/crashtests/994740-1.xhtml b/dom/xml/crashtests/994740-1.xhtml deleted file mode 100644 index 4d71cef27f6c..000000000000 --- a/dom/xml/crashtests/994740-1.xhtml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - diff --git a/embedding/components/printingui/src/mac/nsPrintProgress.h b/embedding/components/printingui/src/mac/nsPrintProgress.h index d8d490dac096..d9a709b9ef16 100644 --- a/embedding/components/printingui/src/mac/nsPrintProgress.h +++ b/embedding/components/printingui/src/mac/nsPrintProgress.h @@ -17,14 +17,16 @@ class nsPrintProgress : public nsIPrintProgress, public nsIPrintStatusFeedback { -public: +public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIPRINTPROGRESS NS_DECL_NSIWEBPROGRESSLISTENER NS_DECL_NSIPRINTSTATUSFEEDBACK - nsPrintProgress(); - virtual ~nsPrintProgress(); + nsPrintProgress(); + +protected: + virtual ~nsPrintProgress(); private: nsresult ReleaseListeners(); diff --git a/embedding/components/printingui/src/mac/nsPrintProgressParams.h b/embedding/components/printingui/src/mac/nsPrintProgressParams.h index b041aae8a721..65c00d98f08f 100644 --- a/embedding/components/printingui/src/mac/nsPrintProgressParams.h +++ b/embedding/components/printingui/src/mac/nsPrintProgressParams.h @@ -11,12 +11,14 @@ class nsPrintProgressParams : public nsIPrintProgressParams { -public: - NS_DECL_ISUPPORTS +public: + NS_DECL_ISUPPORTS NS_DECL_NSIPRINTPROGRESSPARAMS - nsPrintProgressParams(); - virtual ~nsPrintProgressParams(); + nsPrintProgressParams(); + +protected: + virtual ~nsPrintProgressParams(); private: nsString mDocTitle; diff --git a/embedding/components/printingui/src/mac/nsPrintingPromptService.h b/embedding/components/printingui/src/mac/nsPrintingPromptService.h index 01228a216e42..469f762e38b6 100644 --- a/embedding/components/printingui/src/mac/nsPrintingPromptService.h +++ b/embedding/components/printingui/src/mac/nsPrintingPromptService.h @@ -30,7 +30,6 @@ class nsPrintingPromptService: public nsIPrintingPromptService, { public: nsPrintingPromptService(); - virtual ~nsPrintingPromptService(); nsresult Init(); @@ -38,6 +37,9 @@ public: NS_DECL_NSIWEBPROGRESSLISTENER NS_DECL_ISUPPORTS +protected: + virtual ~nsPrintingPromptService(); + private: nsCOMPtr mPrintProgress; }; diff --git a/gfx/layers/AtomicRefCountedWithFinalize.h b/gfx/layers/AtomicRefCountedWithFinalize.h index 2e77833c7836..277956948081 100644 --- a/gfx/layers/AtomicRefCountedWithFinalize.h +++ b/gfx/layers/AtomicRefCountedWithFinalize.h @@ -8,6 +8,10 @@ #include "mozilla/RefPtr.h" #include "mozilla/NullPtr.h" +#include "mozilla/Likely.h" +#include "MainThreadUtils.h" +#include "base/message_loop.h" +#include "base/task.h" namespace mozilla { @@ -18,10 +22,21 @@ class AtomicRefCountedWithFinalize AtomicRefCountedWithFinalize() : mRecycleCallback(nullptr) , mRefCount(0) + , mMessageLoopToPostDestructionTo(nullptr) {} ~AtomicRefCountedWithFinalize() {} + void SetMessageLoopToPostDestructionTo(MessageLoop* l) { + MOZ_ASSERT(NS_IsMainThread()); + mMessageLoopToPostDestructionTo = l; + } + + static void DestroyToBeCalledOnMainThread(T* ptr) { + MOZ_ASSERT(NS_IsMainThread()); + delete ptr; + } + public: void AddRef() { MOZ_ASSERT(mRefCount >= 0); @@ -43,7 +58,17 @@ class AtomicRefCountedWithFinalize #endif T* derived = static_cast(this); derived->Finalize(); - delete derived; + if (MOZ_LIKELY(!mMessageLoopToPostDestructionTo)) { + delete derived; + } else { + if (MOZ_LIKELY(NS_IsMainThread())) { + delete derived; + } else { + mMessageLoopToPostDestructionTo->PostTask( + FROM_HERE, + NewRunnableFunction(&DestroyToBeCalledOnMainThread, derived)); + } + } } else if (1 == currCount && recycleCallback) { T* derived = static_cast(this); recycleCallback(derived, mClosure); @@ -71,6 +96,7 @@ private: RecycleCallback mRecycleCallback; void *mClosure; Atomic mRefCount; + MessageLoop *mMessageLoopToPostDestructionTo; }; } diff --git a/gfx/layers/basic/BasicLayerManager.cpp b/gfx/layers/basic/BasicLayerManager.cpp index dd2919ad8f35..ff80ed964629 100644 --- a/gfx/layers/basic/BasicLayerManager.cpp +++ b/gfx/layers/basic/BasicLayerManager.cpp @@ -18,7 +18,6 @@ #include "basic/BasicLayers.h" // for BasicLayerManager, etc #include "gfx3DMatrix.h" // for gfx3DMatrix #include "gfxASurface.h" // for gfxASurface, etc -#include "gfxCachedTempSurface.h" // for gfxCachedTempSurface #include "gfxColor.h" // for gfxRGBA #include "gfxContext.h" // for gfxContext, etc #include "gfxImageSurface.h" // for gfxImageSurface @@ -98,7 +97,8 @@ BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer, // clipped precisely to the visible region. *aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1; MOZ_ASSERT(!aContext->IsCairo()); - result = PushGroupWithCachedSurface(aContext, gfxContentType::COLOR); + aContext->PushGroup(gfxContentType::COLOR); + result = aContext; } else { *aNeedsClipToVisibleRegion = false; result = aContext; @@ -235,7 +235,6 @@ BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) : mPhase(PHASE_NONE), mWidget(aWidget) , mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false) - , mCachedSurfaceInUse(false) , mTransactionIncomplete(false) , mCompositorMightResample(false) { @@ -247,7 +246,6 @@ BasicLayerManager::BasicLayerManager() : mPhase(PHASE_NONE), mWidget(nullptr) , mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false) - , mCachedSurfaceInUse(false) , mTransactionIncomplete(false) { MOZ_COUNT_CTOR(BasicLayerManager); @@ -286,53 +284,6 @@ BasicLayerManager::BeginTransaction() BeginTransactionWithTarget(mDefaultTarget); } -already_AddRefed -BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget, - gfxContentType aContent) -{ - nsRefPtr ctx; - // We can't cache Azure DrawTargets at this point. - if (!mCachedSurfaceInUse && aTarget->IsCairo()) { - gfxContextMatrixAutoSaveRestore saveMatrix(aTarget); - aTarget->IdentityMatrix(); - - nsRefPtr currentSurf = aTarget->CurrentSurface(); - gfxRect clip = aTarget->GetClipExtents(); - clip.RoundOut(); - - ctx = mCachedSurface.Get(aContent, clip, currentSurf); - - if (ctx) { - mCachedSurfaceInUse = true; - /* Align our buffer for the original surface */ - ctx->SetMatrix(saveMatrix.Matrix()); - return ctx.forget(); - } - } - - ctx = aTarget; - ctx->PushGroup(aContent); - return ctx.forget(); -} - -void -BasicLayerManager::PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed) -{ - if (!aTarget) - return; - if (aTarget->IsCairo()) { - nsRefPtr current = aPushed->CurrentSurface(); - if (mCachedSurface.IsSurface(current)) { - gfxContextMatrixAutoSaveRestore saveMatrix(aTarget); - aTarget->IdentityMatrix(); - aTarget->SetSource(current); - mCachedSurfaceInUse = false; - return; - } - } - aTarget->PopGroupToSource(); -} - void BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget) { @@ -924,7 +875,7 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, nsRefPtr groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(), &needsClipToVisibleRegion); PaintSelfOrChildren(paintLayerContext, groupTarget); - PopGroupToSourceWithCachedSurface(aTarget, groupTarget); + aTarget->PopGroupToSource(); FlushGroup(paintLayerContext, needsClipToVisibleRegion); } else { PaintSelfOrChildren(paintLayerContext, aTarget); @@ -988,7 +939,6 @@ BasicLayerManager::ClearCachedResources(Layer* aSubtree) } else if (mRoot) { ClearLayer(mRoot); } - mCachedSurface.Expire(); } void BasicLayerManager::ClearLayer(Layer* aLayer) diff --git a/gfx/layers/basic/BasicLayers.h b/gfx/layers/basic/BasicLayers.h index b2d789cbb45c..293a4e46edc3 100644 --- a/gfx/layers/basic/BasicLayers.h +++ b/gfx/layers/basic/BasicLayers.h @@ -9,7 +9,6 @@ #include // for INT32_MAX, int32_t #include "Layers.h" // for Layer (ptr only), etc #include "gfxTypes.h" -#include "gfxCachedTempSurface.h" // for gfxCachedTempSurface #include "gfxContext.h" // for gfxContext #include "mozilla/Attributes.h" // for MOZ_OVERRIDE #include "mozilla/WidgetUtils.h" // for ScreenRotation @@ -136,9 +135,6 @@ public: already_AddRefed PushGroupForLayer(gfxContext* aContext, Layer* aLayer, const nsIntRegion& aRegion, bool* aNeedsClipToVisibleRegion); - already_AddRefed PushGroupWithCachedSurface(gfxContext *aTarget, - gfxContentType aContent); - void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed); virtual bool IsCompositingCheap() { return false; } virtual int32_t GetMaxTextureSize() const { return INT32_MAX; } @@ -186,12 +182,8 @@ protected: // Image factory we use. nsRefPtr mFactory; - // Cached surface for double buffering - gfxCachedTempSurface mCachedSurface; - BufferMode mDoubleBuffering; bool mUsingDefaultTarget; - bool mCachedSurfaceInUse; bool mTransactionIncomplete; bool mCompositorMightResample; }; diff --git a/gfx/layers/basic/BasicThebesLayer.cpp b/gfx/layers/basic/BasicThebesLayer.cpp index f766a3d7fe4a..ec05c9193289 100644 --- a/gfx/layers/basic/BasicThebesLayer.cpp +++ b/gfx/layers/basic/BasicThebesLayer.cpp @@ -93,7 +93,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, SetAntialiasingFlags(this, groupContext); aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData); if (needsGroup) { - BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext); + aContext->PopGroupToSource(); if (needsClipToVisibleRegion) { gfxUtils::ClipToRegion(aContext, toDraw); } diff --git a/gfx/layers/d3d9/ThebesLayerD3D9.cpp b/gfx/layers/d3d9/ThebesLayerD3D9.cpp index 0c0ec9674b06..b657aae9d12b 100644 --- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp +++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp @@ -471,11 +471,12 @@ static void FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion, const nsIntPoint& aOffset, const gfxRGBA& aColor) { - nsRefPtr ctx = new gfxContext(aSurface); - ctx->Translate(-gfxPoint(aOffset.x, aOffset.y)); - gfxUtils::ClipToRegion(ctx, aRegion); - ctx->SetColor(aColor); - ctx->Paint(); + nsIntRegionRectIterator iter(aRegion); + const nsIntRect* r; + while ((r = iter.Next()) != nullptr) { + nsIntRect rect = *r + aOffset; + gfxUtils::ClearThebesSurface(aSurface, &rect, aColor); + } } void @@ -526,17 +527,13 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, if (!destinationSurface) return; - nsRefPtr context; - if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) { - RefPtr dt = - gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface, - IntSize(destinationSurface->GetSize().width, - destinationSurface->GetSize().height)); + MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)); + RefPtr dt = + gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface, + IntSize(destinationSurface->GetSize().width, + destinationSurface->GetSize().height)); - context = new gfxContext(dt); - } else { - context = new gfxContext(destinationSurface); - } + nsRefPtr context = new gfxContext(dt); context->Translate(gfxPoint(-bounds.x, -bounds.y)); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); diff --git a/gfx/layers/ipc/CompositorChild.h b/gfx/layers/ipc/CompositorChild.h index f59e21a316c1..50af4d4f071e 100644 --- a/gfx/layers/ipc/CompositorChild.h +++ b/gfx/layers/ipc/CompositorChild.h @@ -17,6 +17,7 @@ #include "nsCOMPtr.h" // for nsCOMPtr #include "nsHashKeys.h" // for nsUint64HashKey #include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING +#include "ThreadSafeRefcountingWithMainThreadDestruction.h" class nsIObserver; @@ -29,7 +30,8 @@ struct FrameMetrics; class CompositorChild MOZ_FINAL : public PCompositorChild { - NS_INLINE_DECL_REFCOUNTING(CompositorChild) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorChild) + public: CompositorChild(ClientLayerManager *aLayerManager); diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 11b8435c4065..7581fd192e01 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -53,6 +53,7 @@ #include "mozilla/unused.h" #include "mozilla/Hal.h" #include "mozilla/HalTypes.h" +#include "mozilla/StaticPtr.h" namespace mozilla { namespace layers { @@ -73,64 +74,65 @@ CompositorParent::LayerTreeState::LayerTreeState() typedef map LayerTreeMap; static LayerTreeMap sIndirectLayerTrees; -// FIXME/bug 774386: we're assuming that there's only one -// CompositorParent, but that's not always true. This assumption only -// affects CrossProcessCompositorParent below. -static Thread* sCompositorThread = nullptr; -// manual reference count of the compositor thread. -static int sCompositorThreadRefCount = 0; -static MessageLoop* sMainLoop = nullptr; +/** + * A global map referencing each compositor by ID. + * + * This map is used by the ImageBridge protocol to trigger + * compositions without having to keep references to the + * compositor + */ +typedef map CompositorMap; +static CompositorMap* sCompositorMap; + +static void CreateCompositorMap() +{ + MOZ_ASSERT(!sCompositorMap); + sCompositorMap = new CompositorMap; +} + +static void DestroyCompositorMap() +{ + MOZ_ASSERT(sCompositorMap); + MOZ_ASSERT(sCompositorMap->empty()); + delete sCompositorMap; + sCompositorMap = nullptr; +} // See ImageBridgeChild.cpp void ReleaseImageBridgeParentSingleton(); -static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie) +CompositorThreadHolder::CompositorThreadHolder() + : mCompositorThread(CreateCompositorThread()) { - aNowReadyToDie->Release(); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_COUNT_CTOR(CompositorThreadHolder); } -static void DeleteCompositorThread() +CompositorThreadHolder::~CompositorThreadHolder() { - if (NS_IsMainThread()){ - ReleaseImageBridgeParentSingleton(); - delete sCompositorThread; - sCompositorThread = nullptr; - } else { - sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&DeleteCompositorThread)); - } + MOZ_ASSERT(NS_IsMainThread()); + + MOZ_COUNT_DTOR(CompositorThreadHolder); + + DestroyCompositorThread(mCompositorThread); } -static void ReleaseCompositorThread() +static StaticRefPtr sCompositorThreadHolder; +static bool sFinishedCompositorShutDown = false; + +CompositorThreadHolder* GetCompositorThreadHolder() { - if(--sCompositorThreadRefCount == 0) { - DeleteCompositorThread(); - } + return sCompositorThreadHolder; } -static void SetThreadPriority() +/* static */ Thread* +CompositorThreadHolder::CreateCompositorThread() { - hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR); -} + MOZ_ASSERT(NS_IsMainThread()); -void CompositorParent::StartUp() -{ - CreateCompositorMap(); - CreateThread(); - sMainLoop = MessageLoop::current(); -} + MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); -void CompositorParent::ShutDown() -{ - DestroyThread(); - DestroyCompositorMap(); -} - -bool CompositorParent::CreateThread() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); - MOZ_ASSERT(!sCompositorThread); - sCompositorThreadRefCount = 1; - sCompositorThread = new Thread("Compositor"); + Thread* compositorThread = new Thread("Compositor"); Thread::Options options; /* Timeout values are powers-of-two to enable us get better data. @@ -141,24 +143,64 @@ bool CompositorParent::CreateThread() than the default hang timeout on major platforms (about 5 seconds). */ options.permanent_hang_timeout = 8192; // milliseconds - if (!sCompositorThread->StartWithOptions(options)) { - delete sCompositorThread; - sCompositorThread = nullptr; - return false; + if (!compositorThread->StartWithOptions(options)) { + delete compositorThread; + return nullptr; } - return true; + CreateCompositorMap(); + + return compositorThread; } -void CompositorParent::DestroyThread() +/* static */ void +CompositorThreadHolder::DestroyCompositorThread(Thread* aCompositorThread) { - NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); - ReleaseCompositorThread(); + MOZ_ASSERT(NS_IsMainThread()); + + MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet."); + + DestroyCompositorMap(); + delete aCompositorThread; + sFinishedCompositorShutDown = true; +} + +static Thread* CompositorThread() { + return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr; +} + +static void SetThreadPriority() +{ + hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR); +} + +void CompositorParent::StartUp() +{ + MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); + + sCompositorThreadHolder = new CompositorThreadHolder(); +} + +void CompositorParent::ShutDown() +{ + MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!"); + + ReleaseImageBridgeParentSingleton(); + + sCompositorThreadHolder = nullptr; + + // No locking is needed around sFinishedCompositorShutDown because it is only + // ever accessed on the main thread. + while (!sFinishedCompositorShutDown) { + NS_ProcessNextEvent(nullptr, true); + } } MessageLoop* CompositorParent::CompositorLoop() { - return sCompositorThread ? sCompositorThread->message_loop() : nullptr; + return CompositorThread() ? CompositorThread()->message_loop() : nullptr; } CompositorParent::CompositorParent(nsIWidget* aWidget, @@ -175,9 +217,11 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, , mResumeCompositionMonitor("ResumeCompositionMonitor") , mOverrideComposeReadiness(false) , mForceCompositionTask(nullptr) + , mCompositorThreadHolder(sCompositorThreadHolder) { - MOZ_ASSERT(sCompositorThread != nullptr, - "The compositor thread must be Initialized before instanciating a CmpositorParent."); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(CompositorThread(), + "The compositor thread must be Initialized before instanciating a CompositorParent."); MOZ_COUNT_CTOR(CompositorParent); mCompositorID = 0; // FIXME: This holds on the the fact that right now the only thing that @@ -192,13 +236,12 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, sIndirectLayerTrees[mRootLayerTreeID].mParent = this; mApzcTreeManager = new APZCTreeManager(); - ++sCompositorThreadRefCount; } bool CompositorParent::IsInCompositorThread() { - return sCompositorThread && sCompositorThread->thread_id() == PlatformThread::CurrentId(); + return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId(); } uint64_t @@ -209,9 +252,8 @@ CompositorParent::RootLayerTreeId() CompositorParent::~CompositorParent() { + MOZ_ASSERT(NS_IsMainThread()); MOZ_COUNT_DTOR(CompositorParent); - - ReleaseCompositorThread(); } void @@ -264,6 +306,13 @@ CompositorParent::RecvWillStop() return true; } +void CompositorParent::DeferredDestroy() +{ + MOZ_ASSERT(!NS_IsMainThread()); + mCompositorThreadHolder = nullptr; + Release(); +} + bool CompositorParent::RecvStop() { @@ -273,10 +322,9 @@ CompositorParent::RecvStop() // this thread. // We must keep the compositor parent alive untill the code handling message // reception is finished on this thread. - this->AddRef(); // Corresponds to DeferredDeleteCompositorParent's Release - CompositorLoop()->PostTask(FROM_HERE, - NewRunnableFunction(&DeferredDeleteCompositorParent, - this)); + this->AddRef(); // Corresponds to DeferredDestroy's Release + MessageLoop::current()->PostTask(FROM_HERE, + NewRunnableMethod(this,&CompositorParent::DeferredDestroy)); return true; } @@ -921,27 +969,6 @@ CompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor) return true; } - -typedef map CompositorMap; -static CompositorMap* sCompositorMap; - -void CompositorParent::CreateCompositorMap() -{ - if (sCompositorMap == nullptr) { - sCompositorMap = new CompositorMap; - } -} - -void CompositorParent::DestroyCompositorMap() -{ - if (sCompositorMap != nullptr) { - NS_ASSERTION(sCompositorMap->empty(), - "The Compositor map should be empty when destroyed>"); - delete sCompositorMap; - sCompositorMap = nullptr; - } -} - CompositorParent* CompositorParent::GetCompositor(uint64_t id) { CompositorMap::iterator it = sCompositorMap->find(id); @@ -1077,12 +1104,15 @@ class CrossProcessCompositorParent MOZ_FINAL : public PCompositorParent, { friend class CompositorParent; - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CrossProcessCompositorParent) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorParent) public: CrossProcessCompositorParent(Transport* aTransport, ProcessId aOtherProcess) : mTransport(aTransport) , mChildProcessId(aOtherProcess) - {} + , mCompositorThreadHolder(sCompositorThreadHolder) + { + MOZ_ASSERT(NS_IsMainThread()); + } // IToplevelProtocol::CloneToplevel() virtual IToplevelProtocol* @@ -1145,6 +1175,8 @@ private: Transport* mTransport; // Child side's process Id. base::ProcessId mChildProcessId; + + nsRefPtr mCompositorThreadHolder; }; void @@ -1176,6 +1208,8 @@ OpenCompositor(CrossProcessCompositorParent* aCompositor, /*static*/ PCompositorParent* CompositorParent::Create(Transport* aTransport, ProcessId aOtherProcess) { + gfxPlatform::InitLayersIPC(); + nsRefPtr cpcp = new CrossProcessCompositorParent(aTransport, aOtherProcess); ProcessHandle handle; @@ -1404,16 +1438,14 @@ CrossProcessCompositorParent::GetCompositionManager(LayerTransactionParent* aLay void CrossProcessCompositorParent::DeferredDestroy() { - CrossProcessCompositorParent* self; - mSelfRef.forget(&self); - - nsCOMPtr runnable = - NS_NewNonOwningRunnableMethod(self, &CrossProcessCompositorParent::Release); - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); + mCompositorThreadHolder = nullptr; + mSelfRef = nullptr; } CrossProcessCompositorParent::~CrossProcessCompositorParent() { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetIOMessageLoop()); XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(mTransport)); } diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index de41299ef887..5b96a1b225e6 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -20,6 +20,7 @@ #include "ShadowLayersManager.h" // for ShadowLayersManager #include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS #include "base/platform_thread.h" // for PlatformThreadId +#include "base/thread.h" // for Thread #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 #include "mozilla/Attributes.h" // for MOZ_OVERRIDE #include "mozilla/Monitor.h" // for Monitor @@ -33,6 +34,7 @@ #include "nsAutoPtr.h" // for nsRefPtr #include "nsISupportsImpl.h" #include "nsSize.h" // for nsIntSize +#include "ThreadSafeRefcountingWithMainThreadDestruction.h" class CancelableTask; class MessageLoop; @@ -63,10 +65,32 @@ private: uint64_t mLayersId; }; +class CompositorThreadHolder MOZ_FINAL +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder) + +public: + CompositorThreadHolder(); + + base::Thread* GetCompositorThread() const { + return mCompositorThread; + } + +private: + ~CompositorThreadHolder(); + + base::Thread* const mCompositorThread; + + static base::Thread* CreateCompositorThread(); + static void DestroyCompositorThread(base::Thread* aCompositorThread); + + friend class CompositorParent; +}; + class CompositorParent : public PCompositorParent, public ShadowLayersManager { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorParent) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent) public: CompositorParent(nsIWidget* aWidget, @@ -166,7 +190,10 @@ public: static void StartUp(); /** - * Destroys the compositor thread and the global compositor map. + * Waits for all [CrossProcess]CompositorParent's to be gone, + * and destroys the compositor thread and global compositor map. + * + * Does not return until all of that has completed. */ static void ShutDown(); @@ -239,6 +266,8 @@ protected: // Protected destructor, to discourage deletion outside of Release(): virtual ~CompositorParent(); + void DeferredDestroy(); + virtual PLayerTransactionParent* AllocPLayerTransactionParent(const nsTArray& aBackendHints, const uint64_t& aId, @@ -259,36 +288,6 @@ protected: void ForceComposition(); void CancelCurrentCompositeTask(); - /** - * Creates a global map referencing each compositor by ID. - * - * This map is used by the ImageBridge protocol to trigger - * compositions without having to keep references to the - * compositor - */ - static void CreateCompositorMap(); - static void DestroyCompositorMap(); - - /** - * Creates the compositor thread. - * - * All compositors live on the same thread. - * The thread is not lazily created on first access to avoid dealing with - * thread safety. Therefore it's best to create and destroy the thread when - * we know we areb't using it (So creating/destroying along with gfxPlatform - * looks like a good place). - */ - static bool CreateThread(); - - /** - * Destroys the compositor thread. - * - * It is safe to call this fucntion more than once, although the second call - * will have no effect. - * This function is not thread-safe. - */ - static void DestroyThread(); - /** * Add a compositor to the global compositor map. */ @@ -336,6 +335,8 @@ protected: nsRefPtr mApzcTreeManager; + nsRefPtr mCompositorThreadHolder; + DISALLOW_EVIL_CONSTRUCTORS(CompositorParent); }; diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index c8abcff401ad..f8cbe127d116 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -221,7 +221,6 @@ static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone) sImageBridgeChildSingleton->SendStop(); - sImageBridgeChildSingleton = nullptr; *aDone = true; aBarrier->NotifyAll(); } @@ -248,10 +247,14 @@ static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * par ImageBridgeChild::ImageBridgeChild() : mShuttingDown(false) { + MOZ_ASSERT(NS_IsMainThread()); + mTxn = new CompositableTransaction(); } ImageBridgeChild::~ImageBridgeChild() { + MOZ_ASSERT(NS_IsMainThread()); + delete mTxn; } @@ -547,7 +550,7 @@ PImageBridgeChild* ImageBridgeChild::StartUpInChildProcess(Transport* aTransport, ProcessId aOtherProcess) { - NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(NS_IsMainThread()); gfxPlatform::GetPlatform(); @@ -572,7 +575,7 @@ ImageBridgeChild::StartUpInChildProcess(Transport* aTransport, void ImageBridgeChild::ShutDown() { - MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(NS_IsMainThread()); if (ImageBridgeChild::IsCreated()) { MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); @@ -600,6 +603,8 @@ void ImageBridgeChild::ShutDown() } } + sImageBridgeChildSingleton = nullptr; + delete sImageBridgeChildThread; sImageBridgeChildThread = nullptr; } diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index 124c9f773c4f..214bd19dfa0d 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -17,6 +17,7 @@ #include "mozilla/layers/PImageBridgeChild.h" #include "nsDebug.h" // for NS_RUNTIMEABORT #include "nsRegion.h" // for nsIntRegion + class MessageLoop; struct nsIntPoint; struct nsIntRect; diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp index 40920d559c23..362988e88411 100644 --- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -44,13 +44,25 @@ using namespace mozilla::gfx; std::map ImageBridgeParent::sImageBridges; +MessageLoop* ImageBridgeParent::sMainLoop = nullptr; + +// defined in CompositorParent.cpp +CompositorThreadHolder* GetCompositorThreadHolder(); + ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport, ProcessId aChildProcessId) : mMessageLoop(aLoop) , mTransport(aTransport) , mChildProcessId(aChildProcessId) + , mCompositorThreadHolder(GetCompositorThreadHolder()) { + MOZ_ASSERT(NS_IsMainThread()); + sMainLoop = MessageLoop::current(); + + // top-level actors must be destroyed on the main thread. + SetMessageLoopToPostDestructionTo(sMainLoop); + // creates the map only if it has not been created already, so it is safe // with several bridges CompositableMap::Create(); @@ -59,10 +71,14 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop, ImageBridgeParent::~ImageBridgeParent() { + MOZ_ASSERT(NS_IsMainThread()); + if (mTransport) { + MOZ_ASSERT(XRE_GetIOMessageLoop()); XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(mTransport)); } + sImageBridges.erase(mChildProcessId); } @@ -160,10 +176,25 @@ bool ImageBridgeParent::RecvWillStop() return true; } +static void +ReleaseImageBridgeParent(ImageBridgeParent* aImageBridgeParent) +{ + aImageBridgeParent->Release(); +} + bool ImageBridgeParent::RecvStop() { - // Nothing to do. This message just serves as synchronization between the + // This message just serves as synchronization between the // child and parent threads during shutdown. + + // There is one thing that we need to do here: temporarily addref, so that + // the handling of this sync message can't race with the destruction of + // the ImageBridgeParent, which would trigger the dreaded "mismatched CxxStackFrames" + // assertion of MessageChannel. + AddRef(); + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableFunction(&ReleaseImageBridgeParent, this)); return true; } @@ -265,32 +296,11 @@ MessageLoop * ImageBridgeParent::GetMessageLoop() const { return mMessageLoop; } -class ReleaseRunnable : public nsRunnable -{ -public: - ReleaseRunnable(ImageBridgeParent* aRef) - : mRef(aRef) - { - } - - NS_IMETHOD Run() - { - mRef->Release(); - return NS_OK; - } - -private: - ImageBridgeParent* mRef; -}; - void ImageBridgeParent::DeferredDestroy() { - ImageBridgeParent* self; - mSelfRef.forget(&self); - - nsCOMPtr runnable = new ReleaseRunnable(self); - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); + mCompositorThreadHolder = nullptr; + mSelfRef = nullptr; } ImageBridgeParent* diff --git a/gfx/layers/ipc/ImageBridgeParent.h b/gfx/layers/ipc/ImageBridgeParent.h index a356d9096cb4..ed483aea70b9 100644 --- a/gfx/layers/ipc/ImageBridgeParent.h +++ b/gfx/layers/ipc/ImageBridgeParent.h @@ -9,6 +9,7 @@ #include // for size_t #include // for uint32_t, uint64_t #include "CompositableTransactionParent.h" +#include "CompositorParent.h" #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 #include "mozilla/Attributes.h" // for MOZ_OVERRIDE #include "mozilla/ipc/ProtocolUtils.h" @@ -151,6 +152,10 @@ private: * Map of all living ImageBridgeParent instances */ static std::map sImageBridges; + + static MessageLoop* sMainLoop; + + nsRefPtr mCompositorThreadHolder; }; } // layers diff --git a/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h new file mode 100644 index 000000000000..0d5f39235d22 --- /dev/null +++ b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h @@ -0,0 +1,83 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_ +#define THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_ + +#include "MainThreadUtils.h" +#include "base/message_loop.h" +#include "base/task.h" + +namespace mozilla { +namespace layers { + +inline MessageLoop* GetMainLoopAssertingMainThread() +{ + MOZ_ASSERT(NS_IsMainThread()); + return MessageLoop::current(); +} + +inline MessageLoop* GetMainLoop() +{ + static MessageLoop* sMainLoop = GetMainLoopAssertingMainThread(); + return sMainLoop; +} + +struct HelperForMainThreadDestruction +{ + HelperForMainThreadDestruction() + { + MOZ_ASSERT(NS_IsMainThread()); + GetMainLoop(); + } + + ~HelperForMainThreadDestruction() + { + MOZ_ASSERT(NS_IsMainThread()); + } +}; + +} // namespace layers +} // namespace mozilla + +#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(_class) \ +public: \ + NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ + MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \ + MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ + nsrefcnt count = ++mRefCnt; \ + NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ + return (nsrefcnt) count; \ + } \ + static void DestroyToBeCalledOnMainThread(_class* ptr) { \ + MOZ_ASSERT(NS_IsMainThread()); \ + NS_LOG_RELEASE(ptr, 0, #_class); \ + delete ptr; \ + } \ + NS_METHOD_(MozExternalRefCountType) Release(void) { \ + MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ + nsrefcnt count = --mRefCnt; \ + if (count == 0) { \ + if (NS_IsMainThread()) { \ + NS_LOG_RELEASE(this, 0, #_class); \ + delete this; \ + } else { \ + /* no NS_LOG_RELEASE here, will be in the runnable */ \ + MessageLoop *l = ::mozilla::layers::GetMainLoop(); \ + l->PostTask(FROM_HERE, \ + NewRunnableFunction(&DestroyToBeCalledOnMainThread, \ + this)); \ + } \ + } else { \ + NS_LOG_RELEASE(this, count, #_class); \ + } \ + return count; \ + } \ +protected: \ + ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \ +private: \ + ::mozilla::layers::HelperForMainThreadDestruction mHelperForMainThreadDestruction; \ +public: + +#endif \ No newline at end of file diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index eb7123dea675..8d021197ad2c 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -27,6 +27,7 @@ EXPORTS += [ 'ipc/CompositorChild.h', 'ipc/CompositorParent.h', 'ipc/ShadowLayersManager.h', + 'ipc/ThreadSafeRefcountingWithMainThreadDestruction.h', 'Layers.h', 'LayerScope.h', 'LayersLogging.h', diff --git a/gfx/tests/crashtests/1034403-1.html b/gfx/tests/crashtests/1034403-1.html new file mode 100644 index 000000000000..714994d3e304 --- /dev/null +++ b/gfx/tests/crashtests/1034403-1.html @@ -0,0 +1,8 @@ + + + + + +
x󠄱
+ + diff --git a/gfx/tests/crashtests/crashtests.list b/gfx/tests/crashtests/crashtests.list index e7a8e2f0d758..0a50b00f9029 100644 --- a/gfx/tests/crashtests/crashtests.list +++ b/gfx/tests/crashtests/crashtests.list @@ -108,3 +108,4 @@ load 893572-1.html load 893572-2.html load 893572-3.html load 893572-4.html +load 1034403-1.html diff --git a/gfx/thebes/gfxCachedTempSurface.cpp b/gfx/thebes/gfxCachedTempSurface.cpp deleted file mode 100644 index 9d0b0d48b847..000000000000 --- a/gfx/thebes/gfxCachedTempSurface.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "gfxCachedTempSurface.h" -#include "gfxContext.h" -#include "mozilla/Attributes.h" - -class CachedSurfaceExpirationTracker MOZ_FINAL : - public nsExpirationTracker { - -public: - // With K = 2, this means that surfaces will be released when they are not - // used for 1-2 seconds. - enum { TIMEOUT_MS = 1000 }; - CachedSurfaceExpirationTracker() - : nsExpirationTracker(TIMEOUT_MS) {} - - ~CachedSurfaceExpirationTracker() { - AgeAllGenerations(); - } - - virtual void NotifyExpired(gfxCachedTempSurface* aSurface) { - RemoveObject(aSurface); - aSurface->Expire(); - } - - static void MarkSurfaceUsed(gfxCachedTempSurface* aSurface) - { - if (aSurface->GetExpirationState()->IsTracked()) { - sExpirationTracker->MarkUsed(aSurface); - return; - } - - if (!sExpirationTracker) { - sExpirationTracker = new CachedSurfaceExpirationTracker(); - } - sExpirationTracker->AddObject(aSurface); - } - - static void RemoveSurface(gfxCachedTempSurface* aSurface) - { - if (!sExpirationTracker) - return; - - if (aSurface->GetExpirationState()->IsTracked()) { - sExpirationTracker->RemoveObject(aSurface); - } - if (sExpirationTracker->IsEmpty()) { - delete sExpirationTracker; - sExpirationTracker = nullptr; - } - } - -private: - static CachedSurfaceExpirationTracker* sExpirationTracker; -}; - -CachedSurfaceExpirationTracker* -CachedSurfaceExpirationTracker::sExpirationTracker = nullptr; - -gfxCachedTempSurface::~gfxCachedTempSurface() -{ - CachedSurfaceExpirationTracker::RemoveSurface(this); -} - -already_AddRefed -gfxCachedTempSurface::Get(gfxContentType aContentType, - const gfxRect& aRect, - gfxASurface* aSimilarTo) -{ - if (mSurface) { - /* Verify the current buffer is valid for this purpose */ - if (mSize.width < aRect.width || mSize.height < aRect.height - || mSurface->GetContentType() != aContentType - || mType != aSimilarTo->GetType()) { - mSurface = nullptr; - } - } - - bool cleared = false; - if (!mSurface) { - mSize = gfxIntSize(int32_t(ceil(aRect.width)), int32_t(ceil(aRect.height))); - mSurface = aSimilarTo->CreateSimilarSurface(aContentType, mSize); - if (!mSurface) - return nullptr; - - cleared = true; - mType = aSimilarTo->GetType(); - } - mSurface->SetDeviceOffset(-aRect.TopLeft()); - - nsRefPtr ctx = new gfxContext(mSurface); - ctx->Rectangle(aRect); - ctx->Clip(); - if (!cleared && aContentType != gfxContentType::COLOR) { - ctx->SetOperator(gfxContext::OPERATOR_CLEAR); - ctx->Paint(); - ctx->SetOperator(gfxContext::OPERATOR_OVER); - } - - CachedSurfaceExpirationTracker::MarkSurfaceUsed(this); - - return ctx.forget(); -} diff --git a/gfx/thebes/gfxCachedTempSurface.h b/gfx/thebes/gfxCachedTempSurface.h deleted file mode 100644 index 3a69f00b6093..000000000000 --- a/gfx/thebes/gfxCachedTempSurface.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GFX_CACHED_TEMP_SURFACE_H -#define GFX_CACHED_TEMP_SURFACE_H - -#include "gfxASurface.h" -#include "nsExpirationTracker.h" -#include "nsSize.h" - -class gfxContext; - -/** - * This class can be used to cache double-buffering back surfaces. - * - * Large resource allocations may have an overhead that can be avoided by - * caching. Caching also alows the system to use history in deciding whether - * to manage the surfaces in video or system memory. - * - * However, because we don't want to set aside megabytes of unused resources - * unncessarily, these surfaces are released on a timer. - */ - -class gfxCachedTempSurface { -public: - /** - * Returns a context for a surface that can be efficiently copied to - * |aSimilarTo|. - * - * When |aContentType| has an alpha component, the surface will be cleared. - * For opaque surfaces, the initial surface contents are undefined. - * When |aContentType| differs in different invocations this is handled - * appropriately, creating a new surface if necessary. - * - * Because the cached surface may have been created during a previous - * invocation, this will not be efficient if the new |aSimilarTo| has a - * different format, size, or gfxSurfaceType. - */ - already_AddRefed Get(gfxContentType aContentType, - const gfxRect& aRect, - gfxASurface* aSimilarTo); - - void Expire() { mSurface = nullptr; } - nsExpirationState* GetExpirationState() { return &mExpirationState; } - ~gfxCachedTempSurface(); - - bool IsSurface(gfxASurface* aSurface) { return mSurface == aSurface; } - -private: - nsRefPtr mSurface; - gfxIntSize mSize; - nsExpirationState mExpirationState; - gfxSurfaceType mType; -}; - -#endif /* GFX_CACHED_TEMP_SURFACE_H */ diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index a9e96c595d42..6d1509c7d211 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -5764,6 +5764,9 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, uint32_t runStart = 0; for (uint32_t i = 0; i <= aLength; ++i) { + uint32_t extraCodeUnits = 0; // Will be set to 1 if we need to consume + // a trailing surrogate as well as the + // current code unit. RunCaseAction chAction = kNoChange; // Unless we're at the end, figure out what treatment the current // character will need. @@ -5772,6 +5775,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, if (NS_IS_HIGH_SURROGATE(ch) && i < aLength - 1 && NS_IS_LOW_SURROGATE(aText[i + 1])) { ch = SURROGATE_TO_UCS4(ch, aText[i + 1]); + extraCodeUnits = 1; } // Characters that aren't the start of a cluster are ignored here. // They get added to whatever lowercase/non-lowercase run we're in. @@ -5885,6 +5889,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, runStart = i; } + i += extraCodeUnits; if (i < aLength) { runAction = chAction; } diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 7e45e7a61288..06f163be43e1 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -1005,7 +1005,9 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData, } } -/* static */ void gfxUtils::ClearThebesSurface(gfxASurface* aSurface) +/* static */ void gfxUtils::ClearThebesSurface(gfxASurface* aSurface, + nsIntRect* aRect, + const gfxRGBA& aColor) { if (aSurface->CairoStatus()) { return; @@ -1015,8 +1017,16 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData, return; } cairo_t* ctx = cairo_create(surf); - cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR); - cairo_paint_with_alpha(ctx, 1.0); + cairo_set_source_rgba(ctx, aColor.r, aColor.g, aColor.b, aColor.a); + cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE); + nsIntRect bounds; + if (aRect) { + bounds = *aRect; + } else { + bounds = nsIntRect(nsIntPoint(0, 0), aSurface->GetSize()); + } + cairo_rectangle(ctx, bounds.x, bounds.y, bounds.width, bounds.height); + cairo_fill(ctx); cairo_destroy(ctx); } diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 8b823bb84dc5..c42a1294d151 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -6,6 +6,7 @@ #ifndef GFX_UTILS_H #define GFX_UTILS_H +#include "gfxColor.h" #include "gfxTypes.h" #include "GraphicsFilter.h" #include "imgIContainer.h" @@ -171,9 +172,11 @@ public: int32_t aStride); /** - * Clears surface to transparent black. + * Clears surface to aColor (which defaults to transparent black). */ - static void ClearThebesSurface(gfxASurface* aSurface); + static void ClearThebesSurface(gfxASurface* aSurface, + nsIntRect* aRect = nullptr, + const gfxRGBA& aColor = gfxRGBA(0.0, 0.0, 0.0, 0.0)); /** * Creates a copy of aSurface, but having the SurfaceFormat aFormat. diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index e04933a44491..3cbf66487484 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -12,7 +12,6 @@ EXPORTS += [ 'gfxASurface.h', 'gfxBaseSharedMemorySurface.h', 'gfxBlur.h', - 'gfxCachedTempSurface.h', 'gfxColor.h', 'gfxContext.h', 'gfxDrawable.h', @@ -223,7 +222,6 @@ UNIFIED_SOURCES += [ 'gfxAlphaRecovery.cpp', 'gfxBaseSharedMemorySurface.cpp', 'gfxBlur.cpp', - 'gfxCachedTempSurface.cpp', 'gfxContext.cpp', 'gfxFontFeatures.cpp', 'gfxFontInfoLoader.cpp', diff --git a/hal/cocoa/CocoaBattery.cpp b/hal/cocoa/CocoaBattery.cpp index ebdfc4e06d1a..749bbecad2fa 100644 --- a/hal/cocoa/CocoaBattery.cpp +++ b/hal/cocoa/CocoaBattery.cpp @@ -115,6 +115,9 @@ struct SingletonDestroyer MOZ_FINAL : public nsIObserver { NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER + +private: + ~SingletonDestroyer() {} }; NS_IMPL_ISUPPORTS(SingletonDestroyer, nsIObserver) diff --git a/image/decoders/icon/mac/nsIconChannel.h b/image/decoders/icon/mac/nsIconChannel.h index ba35e43a7d7e..77e891097163 100644 --- a/image/decoders/icon/mac/nsIconChannel.h +++ b/image/decoders/icon/mac/nsIconChannel.h @@ -31,11 +31,12 @@ public: NS_DECL_NSISTREAMLISTENER nsIconChannel(); - virtual ~nsIconChannel(); nsresult Init(nsIURI* uri); protected: + virtual ~nsIconChannel(); + nsCOMPtr mUrl; nsCOMPtr mOriginalURI; int64_t mContentLength; diff --git a/intl/locale/src/mac/nsCollationMacUC.h b/intl/locale/src/mac/nsCollationMacUC.h index cf0469f4e2b1..8283044bd98c 100644 --- a/intl/locale/src/mac/nsCollationMacUC.h +++ b/intl/locale/src/mac/nsCollationMacUC.h @@ -22,7 +22,6 @@ class nsCollationMacUC MOZ_FINAL : public nsICollation { public: nsCollationMacUC(); - ~nsCollationMacUC(); // nsISupports interface NS_DECL_ISUPPORTS @@ -31,6 +30,8 @@ public: NS_DECL_NSICOLLATION protected: + ~nsCollationMacUC(); + nsresult ConvertLocale(nsILocale* aNSLocale, LocaleRef* aMacLocale); nsresult StrengthToOptions(const int32_t aStrength, UCCollateOptions* aOptions); diff --git a/intl/locale/src/mac/nsDateTimeFormatMac.h b/intl/locale/src/mac/nsDateTimeFormatMac.h index 12132d5d9e55..5b82719289d6 100644 --- a/intl/locale/src/mac/nsDateTimeFormatMac.h +++ b/intl/locale/src/mac/nsDateTimeFormatMac.h @@ -45,9 +45,10 @@ public: nsAString& stringOut); nsDateTimeFormatMac() {} - + +protected: virtual ~nsDateTimeFormatMac() {} - + private: // init this interface to a specified locale NS_IMETHOD Initialize(nsILocale* locale); diff --git a/ipc/glue/ProtocolUtils.cpp b/ipc/glue/ProtocolUtils.cpp index ff059ae84fbb..70374428394d 100644 --- a/ipc/glue/ProtocolUtils.cpp +++ b/ipc/glue/ProtocolUtils.cpp @@ -19,11 +19,14 @@ namespace ipc { IToplevelProtocol::~IToplevelProtocol() { + MOZ_ASSERT(NS_IsMainThread()); mOpenActors.clear(); } void IToplevelProtocol::AddOpenedActor(IToplevelProtocol* aActor) { + MOZ_ASSERT(NS_IsMainThread()); + #ifdef DEBUG for (const IToplevelProtocol* actor = mOpenActors.getFirst(); actor; diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index 48c2b75c545b..1d37a2cb59e9 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -21,6 +21,7 @@ #include "mozilla/ipc/Transport.h" #include "mozilla/ipc/MessageLink.h" #include "mozilla/LinkedList.h" +#include "MainThreadUtils.h" #if defined(ANDROID) && defined(DEBUG) #include @@ -187,6 +188,7 @@ protected: : mProtocolId(aProtoId) , mTrans(nullptr) { + MOZ_ASSERT(NS_IsMainThread()); } ~IToplevelProtocol(); @@ -212,10 +214,12 @@ public: */ IToplevelProtocol* GetFirstOpenedActors() { + MOZ_ASSERT(NS_IsMainThread()); return mOpenActors.getFirst(); } const IToplevelProtocol* GetFirstOpenedActors() const { + MOZ_ASSERT(NS_IsMainThread()); return mOpenActors.getFirst(); } diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index e9fba9493dbd..3ea8ef7b6918 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -303,9 +303,11 @@ AssertMarkedOrAllocated(const EdgeValue &edge) if (!edge.thing || IsMarkedOrAllocated(static_cast(edge.thing))) return; - // Permanent atoms aren't marked during graph traversal. + // Permanent atoms and well-known symbols aren't marked during graph traversal. if (edge.kind == JSTRACE_STRING && static_cast(edge.thing)->isPermanentAtom()) return; + if (edge.kind == JSTRACE_SYMBOL && static_cast(edge.thing)->isWellKnownSymbol()) + return; char msgbuf[1024]; const char *label = edge.label; diff --git a/js/src/jit-test/tests/gc/bug-1032206.js b/js/src/jit-test/tests/gc/bug-1032206.js new file mode 100644 index 000000000000..c58cc53a8d3d --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1032206.js @@ -0,0 +1,3 @@ +gczeal(4); +var symbols = [Symbol(), Symbol("comet"), Symbol.for("moon"), Symbol.iterator, 0]; +for (var a of symbols) {} diff --git a/js/src/jit-test/tests/symbol/typed-arrays.js b/js/src/jit-test/tests/symbol/typed-arrays.js new file mode 100644 index 000000000000..d154a4776a13 --- /dev/null +++ b/js/src/jit-test/tests/symbol/typed-arrays.js @@ -0,0 +1,29 @@ +var tests = [ + {T: Uint8Array, result: 0}, + {T: Uint8ClampedArray, result: 0}, + {T: Int16Array, result: 0}, + {T: Float32Array, result: NaN} +]; + +var LENGTH = 1024, SYMBOL_INDEX = 999; + +var big = []; +for (var i = 0; i < LENGTH; i++) + big[i] = (i === SYMBOL_INDEX ? Symbol.for("comet") : i); + +function copy(arr, big) { + for (var i = 0; i < LENGTH; i++) + arr[i] = big[i]; +} + +for (var {T, result} of tests) { + // Typed array constructors convert symbols to NaN or 0. + arr = new T(big); + assertEq(arr[SYMBOL_INDEX], result); + + // Element assignment does the same. + for (var k = 0; k < 3; k++) { + copy(arr, big); + assertEq(arr[SYMBOL_INDEX], result); + } +} diff --git a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp index 2dc982d2bdad..6aa4dced04a1 100644 --- a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp +++ b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp @@ -27,6 +27,13 @@ BEGIN_TEST(testGCHeapPostBarriers) return true; } +MOZ_NEVER_INLINE bool +Passthrough(bool value) +{ + /* Work around a Win64 optimization bug in VS2010. (Bug 1033146) */ + return value; +} + template bool TestHeapPostBarriers(T initialObj) @@ -37,7 +44,7 @@ TestHeapPostBarriers(T initialObj) /* Construct Heap<> wrapper. */ JS::Heap *heapData = new JS::Heap(); CHECK(heapData); - CHECK(heapData->get() == nullptr); + CHECK(Passthrough(heapData->get() == nullptr)); heapData->set(initialObj); /* Store the pointer as an integer so that the hazard analysis will miss it. */ diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 8d3b46f95ac7..fb986b9f468f 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -5769,7 +5769,7 @@ DumpProperty(JSObject *obj, Shape &shape) jsid id = shape.propid(); uint8_t attrs = shape.attributes(); - fprintf(stderr, " ((JSShape *) %p) ", (void *) &shape); + fprintf(stderr, " ((js::Shape *) %p) ", (void *) &shape); if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate "); if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly "); if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent "); @@ -5785,10 +5785,8 @@ DumpProperty(JSObject *obj, Shape &shape) else if (!shape.hasDefaultSetter()) fprintf(stderr, "setterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.setterOp())); - if (JSID_IS_ATOM(id)) - JSID_TO_STRING(id)->dump(); - else if (JSID_IS_INT(id)) - fprintf(stderr, "%d", (int) JSID_TO_INT(id)); + if (JSID_IS_ATOM(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id)) + dumpValue(js::IdToValue(id)); else fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id)); diff --git a/js/src/json.cpp b/js/src/json.cpp index 44306ae3412f..0b1fde5669f1 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -292,7 +292,7 @@ PreprocessValue(JSContext *cx, HandleObject holder, KeyType key, MutableHandleVa static inline bool IsFilteredValue(const Value &v) { - return v.isUndefined() || IsCallable(v); + return v.isUndefined() || v.isSymbol() || IsCallable(v); } /* ES5 15.12.3 JO. */ diff --git a/js/src/tests/ecma_6/Symbol/json-stringify-keys.js b/js/src/tests/ecma_6/Symbol/json-stringify-keys.js new file mode 100644 index 000000000000..3818cbb339b5 --- /dev/null +++ b/js/src/tests/ecma_6/Symbol/json-stringify-keys.js @@ -0,0 +1,19 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// JSON.stringify ignores symbol-keyed properties, even enumerable ones. + +var obj = {a: 1}; +obj[Symbol.for("ponies")] = {toJSON: function () { throw "fit"; }}; +obj[Symbol.iterator] = {toJSON: function () { throw "fit"; }}; +assertEq(JSON.stringify(obj), '{"a":1}'); + +var replacer = function (k, v) { + if (typeof k === "symbol") + throw "fit"; + return v; +}; +assertEq(JSON.stringify(obj, replacer), '{"a":1}'); + +if (typeof reportCompare === 'function') + reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/ecma_6/Symbol/json-stringify-values.js b/js/src/tests/ecma_6/Symbol/json-stringify-values.js new file mode 100644 index 000000000000..0fe32eee5451 --- /dev/null +++ b/js/src/tests/ecma_6/Symbol/json-stringify-values.js @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// To JSON.stringify, symbols are the same as undefined. + +var symbols = [ + Symbol(), + Symbol.for("ponies"), + Symbol.iterator +]; + +for (var sym of symbols) { + assertEq(JSON.stringify(sym), undefined); + assertEq(JSON.stringify([sym]), "[null]"); + + // JSON.stringify skips symbol-valued properties! + assertEq(JSON.stringify({x: sym}), '{}'); + + // However such properties are passed to the replacerFunction if any. + var replacer = function (key, val) { + assertEq(typeof this, "object"); + if (typeof val === "symbol") { + assertEq(val, sym); + return "ding"; + } + return val; + }; + assertEq(JSON.stringify(sym, replacer), '"ding"'); + assertEq(JSON.stringify({x: sym}, replacer), '{"x":"ding"}'); +} + +if (typeof reportCompare === 'function') + reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/ecma_6/Symbol/typed-arrays.js b/js/src/tests/ecma_6/Symbol/typed-arrays.js new file mode 100644 index 000000000000..e13011ea8743 --- /dev/null +++ b/js/src/tests/ecma_6/Symbol/typed-arrays.js @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Symbol-to-number type conversions involving typed arrays. + +var tests = [ + {T: Uint8Array, result: 0}, + {T: Uint8ClampedArray, result: 0}, + {T: Int16Array, result: 0}, + {T: Float32Array, result: NaN} +]; + +for (var {T, result} of tests) { + // Typed array constructors convert symbols to NaN or 0. + var arr = new T([Symbol("a")]); + assertEq(arr.length, 1); + assertEq(arr[0], result); + + // Assignment also converts symbols to NaN or 0. + arr[0] = 0; + assertEq(arr[0] = Symbol.iterator, Symbol.iterator); + assertEq(arr[0], result); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/lib/jittests.py b/js/src/tests/lib/jittests.py index 852ae63d2fc2..9e93b60cb64e 100755 --- a/js/src/tests/lib/jittests.py +++ b/js/src/tests/lib/jittests.py @@ -84,6 +84,7 @@ class Test: self.jitflags = [] # jit flags to enable self.slow = False # True means the test is slow-running self.allow_oom = False # True means that OOM is not considered a failure + self.allow_unhandlable_oom = False # True means CrashAtUnhandlableOOM is not considered a failure self.allow_overrecursed = False # True means that hitting recursion the # limits is not considered a failure. self.valgrind = False # True means run under valgrind @@ -96,6 +97,7 @@ class Test: t.jitflags = self.jitflags[:] t.slow = self.slow t.allow_oom = self.allow_oom + t.allow_unhandlable_oom = self.allow_unhandlable_oom t.allow_overrecursed = self.allow_overrecursed t.valgrind = self.valgrind t.tz_pacific = self.tz_pacific @@ -141,6 +143,8 @@ class Test: test.slow = True elif name == 'allow-oom': test.allow_oom = True + elif name == 'allow-unhandlable-oom': + test.allow_unhandlable_oom = True elif name == 'allow-overrecursed': test.allow_overrecursed = True elif name == 'valgrind': @@ -390,6 +394,11 @@ def check_output(out, err, rc, timed_out, test): if test.allow_oom and 'out of memory' in err and 'Assertion failure' not in err: return True + # Allow a non-zero exit code if we want to allow unhandlable OOM, but + # only if we actually got unhandlable OOM. + if test.allow_unhandlable_oom and 'Assertion failure: [unhandlable oom]' in err: + return True + # Allow a non-zero exit code if we want to all too-much-recursion and # the test actually over-recursed. if test.allow_overrecursed and 'too much recursion' in err and 'Assertion failure' not in err: diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 23f2d71789f0..91822392ca67 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -883,7 +883,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject static bool canConvertInfallibly(const Value &v) { - return v.isNumber() || v.isBoolean() || v.isNull() || v.isUndefined(); + return v.isNumber() || v.isBoolean() || v.isNull() || v.isUndefined() || v.isSymbol(); } static NativeType @@ -898,7 +898,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject if (v.isNull()) return NativeType(0); - MOZ_ASSERT(v.isUndefined()); + MOZ_ASSERT(v.isUndefined() || v.isSymbol()); return ArrayTypeIsFloatingPoint() ? NativeType(GenericNaN()) : NativeType(0); } diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp index 9ca533209aac..3ef660657977 100644 --- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -249,16 +249,6 @@ nsDisplayCanvasBackgroundColor::WriteDebugInfo(nsACString& aTo) } #endif -static void BlitSurface(gfxContext* aDest, const gfxRect& aRect, gfxASurface* aSource) -{ - aDest->Translate(gfxPoint(aRect.x, aRect.y)); - aDest->SetSource(aSource); - aDest->NewPath(); - aDest->Rectangle(gfxRect(0, 0, aRect.width, aRect.height)); - aDest->Fill(); - aDest->Translate(-gfxPoint(aRect.x, aRect.y)); -} - static void BlitSurface(DrawTarget* aDest, const gfxRect& aRect, DrawTarget* aSource) { RefPtr source = aSource->Snapshot(); @@ -277,9 +267,7 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, nsRefPtr context; nsRefPtr dest = aCtx->ThebesContext(); - nsRefPtr surf; RefPtr dt; - nsRefPtr ctx; gfxRect destRect; #ifndef MOZ_GFX_OPTIMIZE_MOBILE if (IsSingleFixedPositionImage(aBuilder, bgClipRect, &destRect) && @@ -288,31 +276,15 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, // Snap image rectangle to nearest pixel boundaries. This is the right way // to snap for this context, because we checked HasNonIntegerTranslation above. destRect.Round(); - if (dest->IsCairo()) { - surf = static_cast(Frame()->Properties().Get(nsIFrame::CachedBackgroundImage())); - nsRefPtr destSurf = dest->CurrentSurface(); - if (surf && surf->GetType() == destSurf->GetType()) { - BlitSurface(dest, destRect, surf); - return; - } - surf = destSurf->CreateSimilarSurface( - gfxContentType::COLOR_ALPHA, - gfxIntSize(ceil(destRect.width), ceil(destRect.height))); - } else { - dt = static_cast(Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT())); - DrawTarget* destDT = dest->GetDrawTarget(); - if (dt) { - BlitSurface(destDT, destRect, dt); - return; - } - dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width), ceil(destRect.height)), SurfaceFormat::B8G8R8A8); + dt = static_cast(Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT())); + DrawTarget* destDT = dest->GetDrawTarget(); + if (dt) { + BlitSurface(destDT, destRect, dt); + return; } - if (surf || dt) { - if (surf) { - ctx = new gfxContext(surf); - } else { - ctx = new gfxContext(dt); - } + dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width), ceil(destRect.height)), SurfaceFormat::B8G8R8A8); + if (dt) { + nsRefPtr ctx = new gfxContext(dt); ctx->Translate(-gfxPoint(destRect.x, destRect.y)); context = new nsRenderingContext(); context->Init(aCtx->DeviceContext(), ctx); @@ -321,15 +293,10 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, #endif PaintInternal(aBuilder, - (surf || dt) ? context.get() : aCtx, - (surf || dt) ? bgClipRect: mVisibleRect, + dt ? context.get() : aCtx, + dt ? bgClipRect: mVisibleRect, &bgClipRect); - if (surf) { - BlitSurface(dest, destRect, surf); - frame->Properties().Set(nsIFrame::CachedBackgroundImage(), - surf.forget().take()); - } if (dt) { BlitSurface(dest->GetDrawTarget(), destRect, dt); frame->Properties().Set(nsIFrame::CachedBackgroundImageDT(), dt.forget().drop()); diff --git a/layout/svg/nsFilterInstance.cpp b/layout/svg/nsFilterInstance.cpp index 53f9e34b2d0c..bed18301edb5 100644 --- a/layout/svg/nsFilterInstance.cpp +++ b/layout/svg/nsFilterInstance.cpp @@ -298,30 +298,18 @@ nsFilterInstance::ComputeNeededBoxes() nsresult nsFilterInstance::BuildSourcePaint(SourceInfo *aSource, - gfxASurface* aTargetSurface, DrawTarget* aTargetDT) { nsIntRect neededRect = aSource->mNeededBounds; - RefPtr offscreenDT; - nsRefPtr offscreenSurface; - nsRefPtr ctx; - if (aTargetSurface) { - offscreenSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface( - neededRect.Size().ToIntSize(), gfxContentType::COLOR_ALPHA); - if (!offscreenSurface || offscreenSurface->CairoStatus()) { - return NS_ERROR_OUT_OF_MEMORY; - } - ctx = new gfxContext(offscreenSurface); - } else { - offscreenDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( + RefPtr offscreenDT = + gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( ToIntSize(neededRect.Size()), SurfaceFormat::B8G8R8A8); - if (!offscreenDT) { - return NS_ERROR_OUT_OF_MEMORY; - } - ctx = new gfxContext(offscreenDT); + if (!offscreenDT) { + return NS_ERROR_OUT_OF_MEMORY; } + nsRefPtr ctx = new gfxContext(offscreenDT); ctx->Translate(-neededRect.TopLeft()); nsRefPtr tmpCtx(new nsRenderingContext()); @@ -348,63 +336,46 @@ nsFilterInstance::BuildSourcePaint(SourceInfo *aSource, } gfx->Restore(); - if (offscreenSurface) { - aSource->mSourceSurface = - gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTargetDT, offscreenSurface); - } else { - aSource->mSourceSurface = offscreenDT->Snapshot(); - } + + aSource->mSourceSurface = offscreenDT->Snapshot(); aSource->mSurfaceRect = ToIntRect(neededRect); return NS_OK; } nsresult -nsFilterInstance::BuildSourcePaints(gfxASurface* aTargetSurface, - DrawTarget* aTargetDT) +nsFilterInstance::BuildSourcePaints(DrawTarget* aTargetDT) { nsresult rv = NS_OK; if (!mFillPaint.mNeededBounds.IsEmpty()) { - rv = BuildSourcePaint(&mFillPaint, aTargetSurface, aTargetDT); + rv = BuildSourcePaint(&mFillPaint, aTargetDT); NS_ENSURE_SUCCESS(rv, rv); } if (!mStrokePaint.mNeededBounds.IsEmpty()) { - rv = BuildSourcePaint(&mStrokePaint, aTargetSurface, aTargetDT); + rv = BuildSourcePaint(&mStrokePaint, aTargetDT); NS_ENSURE_SUCCESS(rv, rv); } return rv; } nsresult -nsFilterInstance::BuildSourceImage(gfxASurface* aTargetSurface, - DrawTarget* aTargetDT) +nsFilterInstance::BuildSourceImage(DrawTarget* aTargetDT) { nsIntRect neededRect = mSourceGraphic.mNeededBounds; if (neededRect.IsEmpty()) { return NS_OK; } - RefPtr offscreenDT; - nsRefPtr offscreenSurface; - nsRefPtr ctx; - if (aTargetSurface) { - offscreenSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface( - neededRect.Size().ToIntSize(), gfxContentType::COLOR_ALPHA); - if (!offscreenSurface || offscreenSurface->CairoStatus()) { - return NS_ERROR_OUT_OF_MEMORY; - } - ctx = new gfxContext(offscreenSurface); - } else { - offscreenDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( + RefPtr offscreenDT = + gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( ToIntSize(neededRect.Size()), SurfaceFormat::B8G8R8A8); - if (!offscreenDT) { - return NS_ERROR_OUT_OF_MEMORY; - } - ctx = new gfxContext(offscreenDT); + if (!offscreenDT) { + return NS_ERROR_OUT_OF_MEMORY; } + nsRefPtr ctx = new gfxContext(offscreenDT); ctx->Translate(-neededRect.TopLeft()); nsRefPtr tmpCtx(new nsRenderingContext()); @@ -431,16 +402,7 @@ nsFilterInstance::BuildSourceImage(gfxASurface* aTargetSurface, tmpCtx->ThebesContext()->Multiply(deviceToFilterSpace); mPaintCallback->Paint(tmpCtx, mTargetFrame, &dirty, mTransformRoot); - RefPtr sourceGraphicSource; - - if (offscreenSurface) { - sourceGraphicSource = - gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTargetDT, offscreenSurface); - } else { - sourceGraphicSource = offscreenDT->Snapshot(); - } - - mSourceGraphic.mSourceSurface = sourceGraphicSource; + mSourceGraphic.mSourceSurface = offscreenDT->Snapshot(); mSourceGraphic.mSurfaceRect = ToIntRect(neededRect); return NS_OK; @@ -457,34 +419,18 @@ nsFilterInstance::Render(gfxContext* aContext) } Matrix oldDTMatrix; - nsRefPtr resultImage; - RefPtr dt; - if (aContext->IsCairo()) { - resultImage = - gfxPlatform::GetPlatform()->CreateOffscreenSurface(filterRect.Size().ToIntSize(), - gfxContentType::COLOR_ALPHA); - if (!resultImage || resultImage->CairoStatus()) - return NS_ERROR_OUT_OF_MEMORY; - - // Create a Cairo DrawTarget around resultImage. - dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface( - resultImage, ToIntSize(filterRect.Size())); - } else { - // When we have a DrawTarget-backed context, we can call DrawFilter - // directly on the target DrawTarget and don't need a temporary DT. - dt = aContext->GetDrawTarget(); - oldDTMatrix = dt->GetTransform(); - Matrix matrix = ToMatrix(ctm); - matrix.Translate(filterRect.x, filterRect.y); - dt->SetTransform(matrix * oldDTMatrix); - } + RefPtr dt = aContext->GetDrawTarget(); + oldDTMatrix = dt->GetTransform(); + Matrix matrix = ToMatrix(ctm); + matrix.Translate(filterRect.x, filterRect.y); + dt->SetTransform(matrix * oldDTMatrix); ComputeNeededBoxes(); - nsresult rv = BuildSourceImage(resultImage, dt); + nsresult rv = BuildSourceImage(dt); if (NS_FAILED(rv)) return rv; - rv = BuildSourcePaints(resultImage, dt); + rv = BuildSourcePaints(dt); if (NS_FAILED(rv)) return rv; @@ -498,16 +444,7 @@ nsFilterInstance::Render(gfxContext* aContext) mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect, mInputImages); - if (resultImage) { - aContext->Save(); - aContext->Multiply(ctm); - aContext->Translate(filterRect.TopLeft()); - aContext->SetSource(resultImage); - aContext->Paint(); - aContext->Restore(); - } else { - dt->SetTransform(oldDTMatrix); - } + dt->SetTransform(oldDTMatrix); return NS_OK; } diff --git a/layout/svg/nsFilterInstance.h b/layout/svg/nsFilterInstance.h index bf5679f79789..2932908f7f55 100644 --- a/layout/svg/nsFilterInstance.h +++ b/layout/svg/nsFilterInstance.h @@ -183,7 +183,6 @@ private: * nodes */ nsresult BuildSourcePaint(SourceInfo *aPrimitive, - gfxASurface* aTargetSurface, DrawTarget* aTargetDT); /** @@ -191,15 +190,13 @@ private: * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and * mStrokePaint.mSourceSurface respectively. */ - nsresult BuildSourcePaints(gfxASurface* aTargetSurface, - DrawTarget* aTargetDT); + nsresult BuildSourcePaints(DrawTarget* aTargetDT); /** * Creates the SourceSurface for the SourceGraphic graph node, paints its * contents, and assigns it to mSourceGraphic.mSourceSurface. */ - nsresult BuildSourceImage(gfxASurface* aTargetSurface, - DrawTarget* aTargetDT); + nsresult BuildSourceImage(DrawTarget* aTargetDT); /** * Build the list of FilterPrimitiveDescriptions that describes the filter's diff --git a/layout/svg/nsSVGInnerSVGFrame.cpp b/layout/svg/nsSVGInnerSVGFrame.cpp index 457b7f4e369b..3fcdf31dad75 100644 --- a/layout/svg/nsSVGInnerSVGFrame.cpp +++ b/layout/svg/nsSVGInnerSVGFrame.cpp @@ -91,6 +91,25 @@ nsSVGInnerSVGFrame::PaintSVG(nsRenderingContext *aContext, return nsSVGInnerSVGFrameBase::PaintSVG(aContext, aDirtyRect); } +nsRect +nsSVGInnerSVGFrame::GetCoveredRegion() +{ + float x, y, w, h; + static_cast(mContent)-> + GetAnimatedLengthValues(&x, &y, &w, &h, nullptr); + if (w < 0.0f) w = 0.0f; + if (h < 0.0f) h = 0.0f; + // GetCanvasTM includes the x,y translation + nsRect bounds = nsSVGUtils::ToCanvasBounds(gfxRect(0.0, 0.0, w, h), + GetCanvasTM(FOR_OUTERSVG_TM), + PresContext()); + + if (!StyleDisplay()->IsScrollableOverflow()) { + bounds.UnionRect(bounds, nsSVGUtils::GetCoveredRegion(mFrames)); + } + return bounds; +} + void nsSVGInnerSVGFrame::ReflowSVG() { diff --git a/layout/svg/nsSVGInnerSVGFrame.h b/layout/svg/nsSVGInnerSVGFrame.h index 6056f63fa301..678f4e46ce8a 100644 --- a/layout/svg/nsSVGInnerSVGFrame.h +++ b/layout/svg/nsSVGInnerSVGFrame.h @@ -56,6 +56,7 @@ public: virtual nsresult PaintSVG(nsRenderingContext *aContext, const nsIntRect *aDirtyRect, nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE; + virtual nsRect GetCoveredRegion() MOZ_OVERRIDE; virtual void ReflowSVG() MOZ_OVERRIDE; virtual void NotifySVGChanged(uint32_t aFlags) MOZ_OVERRIDE; virtual nsIFrame* GetFrameForPoint(const nsPoint &aPoint) MOZ_OVERRIDE; diff --git a/layout/svg/nsSVGOuterSVGFrame.h b/layout/svg/nsSVGOuterSVGFrame.h index 37c77d2357dd..e8f0eea71940 100644 --- a/layout/svg/nsSVGOuterSVGFrame.h +++ b/layout/svg/nsSVGOuterSVGFrame.h @@ -112,7 +112,6 @@ public: virtual nsresult PaintSVG(nsRenderingContext* aContext, const nsIntRect *aDirtyRect, nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE; - virtual SVGBBox GetBBoxContribution(const Matrix &aToBBoxUserspace, uint32_t aFlags) MOZ_OVERRIDE; diff --git a/layout/svg/nsSVGPathGeometryFrame.cpp b/layout/svg/nsSVGPathGeometryFrame.cpp index 80ea47d41b64..90162ce2cd6b 100644 --- a/layout/svg/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/nsSVGPathGeometryFrame.cpp @@ -7,9 +7,12 @@ #include "nsSVGPathGeometryFrame.h" // Keep others in (case-insensitive) order: +#include "gfx2DGlue.h" #include "gfxContext.h" #include "gfxPlatform.h" #include "gfxSVGGlyphs.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/RefPtr.h" #include "nsDisplayList.h" #include "nsGkAtoms.h" #include "nsRenderingContext.h" @@ -20,6 +23,7 @@ #include "nsSVGUtils.h" #include "mozilla/ArrayUtils.h" #include "SVGAnimatedTransformList.h" +#include "SVGContentUtils.h" #include "SVGGraphicsElement.h" using namespace mozilla; @@ -234,48 +238,77 @@ nsSVGPathGeometryFrame::PaintSVG(nsRenderingContext *aContext, nsIFrame* nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) { - gfxMatrix canvasTM = GetCanvasTM(FOR_HIT_TESTING); - if (canvasTM.IsSingular()) { + gfxMatrix hitTestingTM = GetCanvasTM(FOR_HIT_TESTING); + if (hitTestingTM.IsSingular()) { return nullptr; } - uint16_t fillRule, hitTestFlags; + FillRule fillRule; + uint16_t hitTestFlags; if (GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) { hitTestFlags = SVG_HIT_TEST_FILL; - fillRule = StyleSVG()->mClipRule; + fillRule = StyleSVG()->mClipRule == NS_STYLE_FILL_RULE_NONZERO + ? FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD; } else { hitTestFlags = GetHitTestFlags(); nsPoint point = - nsSVGUtils::TransformOuterSVGPointToChildFrame(aPoint, canvasTM, PresContext()); + nsSVGUtils::TransformOuterSVGPointToChildFrame(aPoint, hitTestingTM, PresContext()); if (!hitTestFlags || ((hitTestFlags & SVG_HIT_TEST_CHECK_MRECT) && - !mRect.Contains(point))) + !mRect.Contains(point))) { return nullptr; - fillRule = StyleSVG()->mFillRule; + } + fillRule = StyleSVG()->mFillRule == NS_STYLE_FILL_RULE_NONZERO + ? FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD; } bool isHit = false; - nsRefPtr tmpCtx = - new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface()); + nsSVGPathGeometryElement* content = + static_cast(mContent); - GeneratePath(tmpCtx, ToMatrix(canvasTM)); - gfxPoint userSpacePoint = - tmpCtx->DeviceToUser(gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerCSSPixel()); + // Using ScreenReferenceDrawTarget() opens us to Moz2D backend specific hit- + // testing bugs. Maybe we should use a BackendType::CAIRO DT for hit-testing + // so that we get more consistent/backwards compatible results? + RefPtr drawTarget = + gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); + RefPtr builder = + drawTarget->CreatePathBuilder(fillRule); + RefPtr path = content->BuildPath(builder); + if (!path) { + return nullptr; // no path, so we don't paint anything that can be hit + } - if (fillRule == NS_STYLE_FILL_RULE_EVENODD) - tmpCtx->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD); - else - tmpCtx->SetFillRule(gfxContext::FILL_RULE_WINDING); + if (!hitTestingTM.IsIdentity()) { + // We'll only get here if we don't have a nsDisplayItem that has called us + // (for example, if we're a NS_FRAME_IS_NONDISPLAY frame under a clipPath). + RefPtr builder = + path->TransformedCopyToBuilder(ToMatrix(hitTestingTM), fillRule); + path = builder->Finish(); + } - if (hitTestFlags & SVG_HIT_TEST_FILL) - isHit = tmpCtx->PointInFill(userSpacePoint); + int32_t appUnitsPerCSSPx = PresContext()->AppUnitsPerCSSPixel(); + Point userSpacePoint = Point(Float(aPoint.x) / appUnitsPerCSSPx, + Float(aPoint.y) / appUnitsPerCSSPx); + + if (hitTestFlags & SVG_HIT_TEST_FILL) { + isHit = path->ContainsPoint(userSpacePoint, Matrix()); + } if (!isHit && (hitTestFlags & SVG_HIT_TEST_STROKE)) { - nsSVGUtils::SetupCairoStrokeGeometry(this, tmpCtx); - // tmpCtx's matrix may have transformed by SetupCairoStrokeGeometry - // if there is a non-scaling stroke. We need to transform userSpacePoint - // so that everything is using the same co-ordinate system. - userSpacePoint = - nsSVGUtils::GetStrokeTransform(this).Invert().Transform(userSpacePoint); - isHit = tmpCtx->PointInStroke(userSpacePoint); + SVGContentUtils::AutoStrokeOptions stroke; + SVGContentUtils::GetStrokeOptions(&stroke, content, StyleContext(), nullptr); + Matrix nonScalingStrokeMatrix = + ToMatrix(nsSVGUtils::GetStrokeTransform(this)); + if (!nonScalingStrokeMatrix.IsIdentity()) { + // We need to transform the path back into the appropriate ancestor + // coordinate system in order for non-scaled stroke to be correct. + // Naturally we also need to transform the point into the same + // coordinate system in order to hit-test against the path. + nonScalingStrokeMatrix.Invert(); + userSpacePoint = ToMatrix(hitTestingTM) * nonScalingStrokeMatrix * userSpacePoint; + RefPtr builder = + path->TransformedCopyToBuilder(nonScalingStrokeMatrix, fillRule); + path = builder->Finish(); + } + isHit = path->StrokeContainsPoint(stroke, userSpacePoint, Matrix()); } if (isHit && nsSVGUtils::HitTestClip(this, aPoint)) @@ -416,8 +449,21 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace, return bbox; } - nsRefPtr tmpCtx = - new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface()); + RefPtr tmpDT; +#ifdef XP_WIN + // Unfortunately D2D backed DrawTarget produces bounds with rounding errors + // when whole number results are expected, even in the case of trivial + // calculations. To avoid that and meet the expectations of web content we + // have to use a CAIRO DrawTarget. The most efficient way to do that is to + // wrap the cached cairo_surface_t from ScreenReferenceSurface(): + nsRefPtr refSurf = + gfxPlatform::GetPlatform()->ScreenReferenceSurface(); + tmpDT = gfxPlatform::GetPlatform()-> + CreateDrawTargetForSurface(refSurf, IntSize(1, 1)); +#else + tmpDT = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); +#endif + nsRefPtr tmpCtx = new gfxContext(tmpDT); GeneratePath(tmpCtx, aToBBoxUserspace); tmpCtx->IdentityMatrix(); diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 7c10c393367e..e9decb6dcaa3 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -356,9 +356,13 @@ nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame, nsRect* aRect) nsISVGChildFrame* svg = do_QueryFrame(aFrame); if (!svg) return nullptr; + nsSVGOuterSVGFrame* outer = GetOuterSVGFrame(aFrame); + if (outer == svg) { + return nullptr; + } *aRect = (aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) ? nsRect(0, 0, 0, 0) : svg->GetCoveredRegion(); - return GetOuterSVGFrame(aFrame); + return outer; } gfxMatrix diff --git a/netwerk/system/mac/nsNetworkLinkService.h b/netwerk/system/mac/nsNetworkLinkService.h index 964c30600c67..caaf416883bc 100644 --- a/netwerk/system/mac/nsNetworkLinkService.h +++ b/netwerk/system/mac/nsNetworkLinkService.h @@ -19,11 +19,13 @@ public: NS_DECL_NSIOBSERVER nsNetworkLinkService(); - virtual ~nsNetworkLinkService(); nsresult Init(); nsresult Shutdown(); +protected: + virtual ~nsNetworkLinkService(); + private: bool mLinkUp; bool mStatusKnown; diff --git a/toolkit/components/startup/nsUserInfoMac.h b/toolkit/components/startup/nsUserInfoMac.h index a42382cc36c2..822e0edd5dd5 100644 --- a/toolkit/components/startup/nsUserInfoMac.h +++ b/toolkit/components/startup/nsUserInfoMac.h @@ -12,12 +12,14 @@ class nsUserInfo: public nsIUserInfo { public: nsUserInfo(); - virtual ~nsUserInfo() {} NS_DECL_ISUPPORTS NS_DECL_NSIUSERINFO - + nsresult GetPrimaryEmailAddress(nsCString &aEmailAddress); + +protected: + virtual ~nsUserInfo() {} }; #endif /* __nsUserInfo_h */ diff --git a/widget/cocoa/OSXNotificationCenter.h b/widget/cocoa/OSXNotificationCenter.h index 2eba27e02b35..836758cca40d 100644 --- a/widget/cocoa/OSXNotificationCenter.h +++ b/widget/cocoa/OSXNotificationCenter.h @@ -30,13 +30,15 @@ public: NS_DECL_NSITIMERCALLBACK OSXNotificationCenter(); - virtual ~OSXNotificationCenter(); nsresult Init(); void CloseAlertCocoaString(NSString *aAlertName); void OnClick(NSString *aAlertName); void ShowPendingNotification(OSXNotificationInfo *osxni); +protected: + virtual ~OSXNotificationCenter(); + private: mozNotificationCenterDelegate *mDelegate; nsTArray > mActiveAlerts; diff --git a/widget/cocoa/nsAppShell.mm b/widget/cocoa/nsAppShell.mm index 30a5f1ec1426..bf46110d958a 100644 --- a/widget/cocoa/nsAppShell.mm +++ b/widget/cocoa/nsAppShell.mm @@ -49,6 +49,8 @@ public: NS_DECL_ISUPPORTS; private: + ~MacWakeLockListener() {} + IOPMAssertionID mAssertionID = kIOPMNullAssertionID; NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) { diff --git a/widget/cocoa/nsBidiKeyboard.h b/widget/cocoa/nsBidiKeyboard.h index dbe03390a0ea..e7e7ac872276 100644 --- a/widget/cocoa/nsBidiKeyboard.h +++ b/widget/cocoa/nsBidiKeyboard.h @@ -16,6 +16,8 @@ public: NS_DECL_NSIBIDIKEYBOARD nsBidiKeyboard(); + +protected: virtual ~nsBidiKeyboard(); }; diff --git a/widget/cocoa/nsColorPicker.h b/widget/cocoa/nsColorPicker.h index 597b97a9725d..7583c3412b86 100644 --- a/widget/cocoa/nsColorPicker.h +++ b/widget/cocoa/nsColorPicker.h @@ -35,6 +35,8 @@ public: void Done(); private: + ~nsColorPicker(); + static NSColor* GetNSColorFromHexString(const nsAString& aColor); static void GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult); diff --git a/widget/cocoa/nsColorPicker.mm b/widget/cocoa/nsColorPicker.mm index b27191d5774f..3bfa42cfd3c1 100644 --- a/widget/cocoa/nsColorPicker.mm +++ b/widget/cocoa/nsColorPicker.mm @@ -97,6 +97,10 @@ NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker) NSColorPanelWrapper* nsColorPicker::sColorPanelWrapper = nullptr; +nsColorPicker::~nsColorPicker() +{ +} + NS_IMETHODIMP nsColorPicker::Init(nsIDOMWindow* aParent, const nsAString& aTitle, const nsAString& aInitialColor) diff --git a/widget/cocoa/nsFilePicker.h b/widget/cocoa/nsFilePicker.h index 463ae17bb1c3..4f58897aee2a 100644 --- a/widget/cocoa/nsFilePicker.h +++ b/widget/cocoa/nsFilePicker.h @@ -21,7 +21,6 @@ class nsFilePicker : public nsBaseFilePicker { public: nsFilePicker(); - virtual ~nsFilePicker(); NS_DECL_ISUPPORTS @@ -46,6 +45,7 @@ public: NSArray* GetFilterList(); protected: + virtual ~nsFilePicker(); virtual void InitNative(nsIWidget *aParent, const nsAString& aTitle); diff --git a/widget/cocoa/nsMacDockSupport.h b/widget/cocoa/nsMacDockSupport.h index 7b5428704146..ffe454ecde41 100644 --- a/widget/cocoa/nsMacDockSupport.h +++ b/widget/cocoa/nsMacDockSupport.h @@ -15,13 +15,14 @@ class nsMacDockSupport : public nsIMacDockSupport, public nsITaskbarProgress { public: nsMacDockSupport(); - virtual ~nsMacDockSupport(); NS_DECL_ISUPPORTS NS_DECL_NSIMACDOCKSUPPORT NS_DECL_NSITASKBARPROGRESS protected: + virtual ~nsMacDockSupport(); + nsCOMPtr mDockMenu; nsString mBadgeText; diff --git a/widget/cocoa/nsMacWebAppUtils.h b/widget/cocoa/nsMacWebAppUtils.h index 9d34df3d2c0a..98ef235615db 100644 --- a/widget/cocoa/nsMacWebAppUtils.h +++ b/widget/cocoa/nsMacWebAppUtils.h @@ -11,10 +11,12 @@ class nsMacWebAppUtils : public nsIMacWebAppUtils { public: nsMacWebAppUtils() {} - virtual ~nsMacWebAppUtils() {} - + NS_DECL_ISUPPORTS NS_DECL_NSIMACWEBAPPUTILS + +protected: + virtual ~nsMacWebAppUtils() {} }; #endif //_MAC_WEB_APP_UTILS_H_ diff --git a/widget/cocoa/nsMenuBarX.h b/widget/cocoa/nsMenuBarX.h index f1563f3023b5..6fc2d818886e 100644 --- a/widget/cocoa/nsMenuBarX.h +++ b/widget/cocoa/nsMenuBarX.h @@ -28,9 +28,11 @@ public: NS_DECL_ISUPPORTS nsNativeMenuServiceX() {} - virtual ~nsNativeMenuServiceX() {} NS_IMETHOD CreateNativeMenuBar(nsIWidget* aParent, nsIContent* aMenuBarNode); + +protected: + virtual ~nsNativeMenuServiceX() {} }; @interface NSMenu (Undocumented) diff --git a/widget/cocoa/nsMenuGroupOwnerX.h b/widget/cocoa/nsMenuGroupOwnerX.h index cfba9c56fed7..8408a582f92d 100644 --- a/widget/cocoa/nsMenuGroupOwnerX.h +++ b/widget/cocoa/nsMenuGroupOwnerX.h @@ -27,7 +27,6 @@ class nsMenuGroupOwnerX : public nsMenuObjectX, public nsIMutationObserver { public: nsMenuGroupOwnerX(); - virtual ~nsMenuGroupOwnerX(); nsresult Create(nsIContent * aContent); @@ -42,6 +41,8 @@ public: NS_DECL_NSIMUTATIONOBSERVER protected: + virtual ~nsMenuGroupOwnerX(); + nsChangeObserver* LookupContentChangeObserver(nsIContent* aContent); uint32_t mCurrentCommandID; // unique command id (per menu-bar) to diff --git a/widget/cocoa/nsPrintDialogX.h b/widget/cocoa/nsPrintDialogX.h index de0d0252d183..7a4540cefbfa 100644 --- a/widget/cocoa/nsPrintDialogX.h +++ b/widget/cocoa/nsPrintDialogX.h @@ -19,7 +19,6 @@ class nsPrintDialogServiceX : public nsIPrintDialogService { public: nsPrintDialogServiceX(); - virtual ~nsPrintDialogServiceX(); NS_DECL_ISUPPORTS @@ -28,6 +27,9 @@ public: nsIWebBrowserPrint *aWebBrowserPrint); NS_IMETHODIMP ShowPageSetup(nsIDOMWindow *aParent, nsIPrintSettings *aSettings); + +protected: + virtual ~nsPrintDialogServiceX(); }; @interface PrintPanelAccessoryView : NSView diff --git a/widget/cocoa/nsScreenManagerCocoa.h b/widget/cocoa/nsScreenManagerCocoa.h index 8836b946d173..75f571bd3853 100644 --- a/widget/cocoa/nsScreenManagerCocoa.h +++ b/widget/cocoa/nsScreenManagerCocoa.h @@ -17,11 +17,13 @@ class nsScreenManagerCocoa : public nsIScreenManager { public: nsScreenManagerCocoa(); - virtual ~nsScreenManagerCocoa(); NS_DECL_ISUPPORTS NS_DECL_NSISCREENMANAGER +protected: + virtual ~nsScreenManagerCocoa(); + private: nsScreenCocoa *ScreenForCocoaScreen(NSScreen *screen); diff --git a/widget/cocoa/nsSound.h b/widget/cocoa/nsSound.h index a38b8ecbed4c..0e0293ae282d 100644 --- a/widget/cocoa/nsSound.h +++ b/widget/cocoa/nsSound.h @@ -15,11 +15,13 @@ class nsSound : public nsISound, { public: nsSound(); - virtual ~nsSound(); NS_DECL_ISUPPORTS NS_DECL_NSISOUND NS_DECL_NSISTREAMLOADEROBSERVER + +protected: + virtual ~nsSound(); }; #endif // nsSound_h_ diff --git a/widget/cocoa/nsStandaloneNativeMenu.h b/widget/cocoa/nsStandaloneNativeMenu.h index 9c4ac80409c0..1bc886bca607 100644 --- a/widget/cocoa/nsStandaloneNativeMenu.h +++ b/widget/cocoa/nsStandaloneNativeMenu.h @@ -14,7 +14,6 @@ class nsStandaloneNativeMenu : public nsMenuGroupOwnerX, public nsIStandaloneNat { public: nsStandaloneNativeMenu(); - virtual ~nsStandaloneNativeMenu(); NS_DECL_ISUPPORTS NS_DECL_NSISTANDALONENATIVEMENU @@ -26,6 +25,8 @@ public: nsMenuX * GetMenuXObject() { return mMenu; } protected: + virtual ~nsStandaloneNativeMenu(); + nsMenuX * mMenu; }; diff --git a/widget/xpwidgets/nsBaseClipboard.h b/widget/xpwidgets/nsBaseClipboard.h index d3db91702c91..c45f02840d82 100644 --- a/widget/xpwidgets/nsBaseClipboard.h +++ b/widget/xpwidgets/nsBaseClipboard.h @@ -25,7 +25,6 @@ class nsBaseClipboard : public nsIClipboard public: nsBaseClipboard(); - virtual ~nsBaseClipboard(); //nsISupports NS_DECL_ISUPPORTS @@ -34,6 +33,7 @@ public: NS_DECL_NSICLIPBOARD protected: + virtual ~nsBaseClipboard(); NS_IMETHOD SetNativeClipboardData ( int32_t aWhichClipboard ) = 0; NS_IMETHOD GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard ) = 0; diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index a6a7480d48c5..16341e973fce 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -890,6 +890,9 @@ public: return NS_OK; } + +private: + ~DMDReporter() {} }; NS_IMPL_ISUPPORTS(DMDReporter, nsIMemoryReporter) @@ -2009,6 +2012,9 @@ public: // Do nothing; the reporter has already reported to DMD. return NS_OK; } + +private: + ~DoNothingCallback() {} }; NS_IMPL_ISUPPORTS(DoNothingCallback, nsIHandleReportCallback) diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index efab931019f3..c53bb94a7499 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -811,17 +811,17 @@ ShutdownXPCOM(nsIServiceManager* servMgr) } } + // This must happen after the shutdown of media and widgets, which + // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. NS_ProcessPendingEvents(thread); + gfxPlatform::ShutdownLayersIPC(); + mozilla::scache::StartupCache::DeleteSingleton(); if (observerService) (void) observerService-> NotifyObservers(nullptr, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, nullptr); - // This must happen after the shutdown of media and widgets, which - // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. - gfxPlatform::ShutdownLayersIPC(); - gXPCOMThreadsShutDown = true; NS_ProcessPendingEvents(thread);