From e7535dc94b5e664225fcbcded5bb0bf5c5e194bb Mon Sep 17 00:00:00 2001 From: roytam1 Date: Fri, 20 May 2022 09:45:08 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1187401 (Part 1) - Simplify the condition that determines whether we set RasterImage::mHasBeenDecoded. r=tn (69be36e7ef) - Bug 1187401 (Part 2) - Eliminate the nsresult return value from RasterImage::SetMetadata, since it's not used anymore. r=tn (dc521c4b9f) - Bug 1187401 (Part 3) - For consistency, call DoError if SetMetadata sees a negative size. r=tn (d9ca8ec91b) - Bug 1207183 - micro-optimize removing work items from DecodePool's queues; r=seth (6bd2717e3a) - No bug - Fix out-of-date comment in Decoder.cpp. r=me (54fdbbd444) - Bug 1181324 - Eliminate the duplicate mRefCnt member in MultipartImage. r=seth (c4512a443e) - Bug 1180105 - Do not leak the SourceSurface returned from imgIContainer::GetFrame in BlockUntilDecodedAndFinishObserving; r=seth (1cadbffc53) - Bug 1181909 - Fix potential null dereference in NextPartObserver. r=tn (cfd8ad0119) - Bug 108603 - Remove NS_IMPL_QUERY_INTERFACE_INHERITED0. r=mccr8, r=froydnj (4bfa6771fc) - Bug 1159502 - Don't block onload for multipart images. r=tn (8b50eadf39) - Bug 1200413 - Part 1: Re-write RefCountedInsideLambdaChecker to use captures instead of checking for DeclRef instances, r=ehsan (80ef99efe2) - Bug 1200413 - Part 2: Make lambdas in ProgressTracker.cpp capture strong references, r=seth (9e4d96dffa) - Bug 1194557 - Ensure that if the image was locked before RecoverFromLossOfFrames() was called, it's still locked afterwards. r=tn (ea4dc6ea9f) - code style (ad3773ba42) - Bug 1167590 - Mark imgRequestProxy::mListener as MOZ_UNSAFE_REF. r=seth (946ffaed8a) - Bug 1148397 - Fix data race on imgRequest::mHadInsecureRedirect. r=tanvi (e73d0664f3) - No bug - Tweak formatting of logging statement in imgRequest. r=me (cab2bcb014) - Bug 1180126 - Read content disposition regardless of content type in imgRequest::PrepareForNewPart. r=tn (2934597743) - Bug 1139225 - Followup - Remove duplicate multiPartChannel variable. (7f7f555a0b) - Bug 1141398 - Do not always revalidate image cache entries for file URIs. r=tn (31d73cb508) - Bug 1183563 - Fix incorrect mixed content warning after internal redirects. r=tanvi, r=seth (12a6c8a15f) - Bug 1150127 - Stop leaking windows via imgCacheValidator. r=baku (a7809c5fa7) - bits of Bug 1102048 (Part 20, imgLoader) (b2098c8a5a) - (No bug) - Correct blatantly lying comment in imgLoader.cpp. r=me DONTBUILD (64c42a5b09) - Bug 1160592 - Report image source size again in about:memory. r=dholbert (4e04cf3c3e) - Add an assertion for the first argument of NewImageChannel, no bug (4c8f087a8f) - Bug 1127534 - Remove assertion before creating a channel (r=sicking) (988692dc91) - Bug 1175371 - Make VectorImage wait to deliver LOAD_COMPLETE until its size is available. r=dholbert (3c81e0daff) - Bug 1181323 - Move nsSVGRenderingObserver's isupports/refcounting decl to subclasses, since one subclass (nsSVGFilterReference) already has its own redundant copy of the decl. r=dholbert (6171171c2c) - Bug 1161722 - If we're shutting down, don't warn about untracked unlocked surfaces. r=dholbert (f7e18ce481) - Bug 1170877 - Track how many times the SurfaceCache has overflowed and report it in about:memory. r=dholbert (884176cb1d) - Bug 1161743 - Upgrade 'WARNING: Not expiration-tracking an unlocked surface' to an assertion. r=dholbert (9900169e7b) - Bug 1167557 - Crash when a null surface is passed to SurfaceCache::Insert. r=dholbert (b3c4cf60aa) - remove bypass cache not fonud either in FF nor TF (3ed4056a27) - Missing bit Bug 1102048 (Part 25, header guards) - Make image/src files comply (cb8ed2428f) - No bug - Remove obsolete comment in SourceBuffer.h. r=me (6e9c233448) - coding style (94b7269690) - Bug 1157065 - GFX: 2D: Add Loongson3 MMI helpers. r=jrmuizel (ebce946c91) - reverto to FF52 and TFF settings (e147a8c7b5) - Bug 1134599 - Fix rpi build target. r=jrmuizel, r=shuang (b9722f860c) - Bug 1129147 - Part 1. Take CanvasPath into a separate file, to avoid circular dependency. r=roc (859bcad807) - Bug 1129147 - Part 2. Path option to addHitRegion. r=ehsan r=gw280 (b2ab08a8a1) - Bug 1206076: Use a specialized PersistentBufferProvider for Canvas2D when using a SkiaGL DrawTarget. r=jrmuizel (859589caf8) - Bug 1188752 - Addendum: Make PersistentBufferProviderBasic constructor explicit. r=bustage on a CLOSED TREE (a27a4dc974) - style (72a65dcb26) - Bug 1198574 - Remove unnecessary argument for PersistentBufferProvider. r=bas (dca718bba8) - Bug 1163124 - The initial value of the canvas filter property should be "none". r=roc (59df6a01d8) --- b2g/app/b2g.js | 2 +- build/clang-plugin/clang-plugin.cpp | 24 ++- .../tests/TestNoRefcountedInsideLambdas.cpp | 8 +- dom/bindings/Bindings.conf | 2 +- dom/canvas/CanvasPath.h | 91 ++++++++ dom/canvas/CanvasRenderingContext2D.cpp | 30 +-- dom/canvas/CanvasRenderingContext2D.h | 68 +----- dom/canvas/moz.build | 1 + dom/canvas/test/test_hitregion_event.html | 18 +- dom/system/gonk/AudioManager.cpp | 6 + dom/webidl/CanvasRenderingContext2D.webidl | 1 + gfx/2d/MMIHelpers.h | 196 ++++++++++++++++++ gfx/2d/SourceSurfaceSkia.cpp | 2 + gfx/2d/image_operations.cpp | 16 +- gfx/layers/Layers.cpp | 4 +- gfx/layers/PersistentBufferProvider.cpp | 4 +- gfx/layers/PersistentBufferProvider.h | 12 +- gfx/thebes/gfxPlatform.cpp | 2 +- image/DecodePool.cpp | 2 +- image/Decoder.cpp | 5 +- image/Decoder.h | 5 - image/MultipartImage.cpp | 35 +++- image/MultipartImage.h | 2 +- image/Orientation.h | 4 +- image/ProgressTracker.cpp | 12 +- image/RasterImage.cpp | 36 ++-- image/RasterImage.h | 10 +- image/SVGDocumentWrapper.h | 4 +- image/SourceBuffer.h | 9 +- image/SurfaceCache.cpp | 20 +- image/VectorImage.cpp | 86 ++++---- image/VectorImage.h | 8 +- image/imgLoader.cpp | 68 ++++-- image/imgRequest.cpp | 50 +++-- image/imgRequest.h | 10 +- image/imgRequestProxy.h | 5 +- image/moz.build | 2 - image/test/mochitest/bug1180105-waiter.sjs | 24 +++ image/test/mochitest/bug1180105.sjs | 63 ++++++ image/test/mochitest/mochitest.ini | 3 + image/test/mochitest/test_bug1180105.html | 46 ++++ layout/svg/nsSVGEffects.cpp | 5 +- layout/svg/nsSVGEffects.h | 7 +- modules/libpref/init/all.js | 4 +- xpcom/glue/nsISupportsImpl.h | 8 +- 45 files changed, 747 insertions(+), 273 deletions(-) create mode 100644 dom/canvas/CanvasPath.h create mode 100644 gfx/2d/MMIHelpers.h create mode 100644 image/test/mochitest/bug1180105-waiter.sjs create mode 100644 image/test/mochitest/bug1180105.sjs create mode 100644 image/test/mochitest/test_bug1180105.html diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 909d5a43f2..fde9582102 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -904,7 +904,7 @@ pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket"); // falling back to Skia/software for smaller canvases #ifdef MOZ_WIDGET_GONK pref("gfx.canvas.azure.backends", "skia"); -pref("gfx.canvas.azure.accelerated", true); +pref("gfx.canvas.azure.accelerated", false); #endif // Turn on dynamic cache size for Skia diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index 29e2ddd448..a2d64924f6 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -951,13 +951,7 @@ DiagnosticsMatcher::DiagnosticsMatcher() { // lambda, where the declaration they reference is not inside the lambda. // This excludes arguments and local variables, leaving only captured // variables. - astMatcher.addMatcher( - lambdaExpr(hasDescendant( - declRefExpr(hasType(pointerType(pointee(isRefCounted()))), - to(decl().bind("decl"))) - .bind("declref")), - unless(hasDescendant(decl(equalsBoundNode("decl"))))), - &refCountedInsideLambdaChecker); + astMatcher.addMatcher(lambdaExpr().bind("lambda"), &refCountedInsideLambdaChecker); // Older clang versions such as the ones used on the infra recognize these // conversions as 'operator _Bool', but newer clang versions recognize these @@ -1241,11 +1235,19 @@ void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run( "Refcounted variable %0 of type %1 cannot be captured by a lambda"); unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "Please consider using a smart pointer"); - const DeclRefExpr *declref = Result.Nodes.getNodeAs("declref"); + const LambdaExpr *Lambda = Result.Nodes.getNodeAs("lambda"); - Diag.Report(declref->getLocStart(), errorID) - << declref->getFoundDecl() << declref->getType()->getPointeeType(); - Diag.Report(declref->getLocStart(), noteID); + for (const LambdaCapture Capture : Lambda->captures()) { + if (Capture.capturesVariable()) { + QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType(); + + if (!Pointee.isNull() && isClassRefCounted(Pointee)) { + Diag.Report(Capture.getLocation(), errorID) + << Capture.getCapturedVar() << Pointee; + Diag.Report(Capture.getLocation(), noteID); + } + } + } } void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run( diff --git a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp index 20486bbcae..35aac9dd60 100644 --- a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp +++ b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp @@ -67,9 +67,9 @@ void foo() { take(argsp); take(localsp); }); - take([ptr](R* argptr) { + take([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} R* localptr; - ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + ptr->method(); argptr->method(); localptr->method(); }); @@ -79,9 +79,9 @@ void foo() { argsp->method(); localsp->method(); }); - take([ptr](R* argptr) { + take([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} R* localptr; - take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(ptr); take(argptr); take(localptr); }); diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 8e091627dd..5fab24455c 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -900,7 +900,7 @@ DOMInterfaces = { 'Path2D': { 'nativeType': 'mozilla::dom::CanvasPath', - 'headerFile': 'CanvasRenderingContext2D.h' + 'headerFile': 'CanvasPath.h' }, 'PeerConnectionImpl': { diff --git a/dom/canvas/CanvasPath.h b/dom/canvas/CanvasPath.h new file mode 100644 index 0000000000..e31b375cc3 --- /dev/null +++ b/dom/canvas/CanvasPath.h @@ -0,0 +1,91 @@ +/* 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 CanvasPath_h +#define CanvasPath_h + +#include "mozilla/Attributes.h" +#include "mozilla/RefPtr.h" +#include "nsWrapperCache.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/ErrorResult.h" + +namespace mozilla { +namespace dom { + +enum class CanvasWindingRule : uint32_t; +class SVGMatrix; + +class CanvasPath final : + public nsWrapperCache +{ +public: + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CanvasPath) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CanvasPath) + + nsCOMPtr GetParentObject() { return mParent; } + + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + static already_AddRefed Constructor(const GlobalObject& aGlobal, + ErrorResult& rv); + static already_AddRefed Constructor(const GlobalObject& aGlobal, + CanvasPath& aCanvasPath, + ErrorResult& rv); + static already_AddRefed Constructor(const GlobalObject& aGlobal, + const nsAString& aPathString, + ErrorResult& rv); + + void ClosePath(); + void MoveTo(double x, double y); + void LineTo(double x, double y); + void QuadraticCurveTo(double cpx, double cpy, double x, double y); + void BezierCurveTo(double cp1x, double cp1y, + double cp2x, double cp2y, + double x, double y); + void ArcTo(double x1, double y1, double x2, double y2, double radius, + ErrorResult& error); + void Rect(double x, double y, double w, double h); + void Arc(double x, double y, double radius, + double startAngle, double endAngle, bool anticlockwise, + ErrorResult& error); + void Ellipse(double x, double y, double radiusX, double radiusY, + double rotation, double startAngle, double endAngle, + bool anticlockwise, ErrorResult& error); + + void LineTo(const gfx::Point& aPoint); + void BezierTo(const gfx::Point& aCP1, + const gfx::Point& aCP2, + const gfx::Point& aCP3); + + already_AddRefed GetPath(const CanvasWindingRule& aWinding, + const gfx::DrawTarget* aTarget) const; + + explicit CanvasPath(nsISupports* aParent); + // already_AddRefed arg because the return value from Path::CopyToBuilder() + // is passed directly and we can't drop the only ref to have a raw pointer. + CanvasPath(nsISupports* aParent, + already_AddRefed aPathBuilder); + + void AddPath(CanvasPath& aCanvasPath, + const Optional>& aMatrix); + +private: + virtual ~CanvasPath() {} + + nsCOMPtr mParent; + static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); } + + mutable RefPtr mPath; + mutable RefPtr mPathBuilder; + + void EnsurePathBuilder() const; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* CanvasPath_h */ + diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index e1cc382ba5..046c29772a 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -101,6 +101,7 @@ #include "nsCCUncollectableMarker.h" #include "nsWrapperCacheInlines.h" #include "mozilla/dom/CanvasRenderingContext2DBinding.h" +#include "mozilla/dom/CanvasPath.h" #include "mozilla/dom/HTMLImageElement.h" #include "mozilla/dom/HTMLVideoElement.h" #include "mozilla/dom/SVGMatrix.h" @@ -1402,13 +1403,14 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode) DemoteOldestContextIfNecessary(); mBufferProvider = nullptr; +#if USE_SKIA_GPU SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); -#if USE_SKIA_GPU if (glue && glue->GetGrContext() && glue->GetGLContext()) { mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format); if (mTarget) { AddDemotableContext(this); + mBufferProvider = new PersistentBufferProviderBasic(mTarget); } else { printf_stderr("Failed to create a SkiaGL DrawTarget, falling back to software\n"); mode = RenderingMode::SoftwareBackendMode; @@ -3360,15 +3362,24 @@ CanvasRenderingContext2D::MeasureText(const nsAString& rawText, void CanvasRenderingContext2D::AddHitRegion(const HitRegionOptions& options, ErrorResult& error) { - // check if the path is valid - EnsureUserSpacePath(CanvasWindingRule::Nonzero); - if(!mPath) { + RefPtr path; + if (options.mPath) { + path = options.mPath->GetPath(CanvasWindingRule::Nonzero, mTarget); + } + + if (!path) { + // check if the path is valid + EnsureUserSpacePath(CanvasWindingRule::Nonzero); + path = mPath; + } + + if(!path) { error.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return; } // get the bounds of the current path. They are relative to the canvas - mgfx::Rect bounds(mPath->GetBounds(mTarget->GetTransform())); + mgfx::Rect bounds(path->GetBounds(mTarget->GetTransform())); if ((bounds.width == 0) || (bounds.height == 0) || !bounds.IsFinite()) { // The specified region has no pixels. error.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); @@ -3397,7 +3408,7 @@ CanvasRenderingContext2D::AddHitRegion(const HitRegionOptions& options, ErrorRes RegionInfo info; info.mId = options.mId; info.mElement = options.mControl; - RefPtr pathBuilder = mPath->TransformedCopyToBuilder(mTarget->GetTransform()); + RefPtr pathBuilder = path->TransformedCopyToBuilder(mTarget->GetTransform()); info.mPath = pathBuilder->Finish(); mHitRegionsOptions.InsertElementAt(0, info); @@ -5598,12 +5609,7 @@ CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager) return nullptr; } - mBufferProvider = aManager->CreatePersistentBufferProvider(mTarget->GetSize(), mTarget->GetFormat()); - - RefPtr surf = mTarget->Snapshot(); - - mTarget = mBufferProvider->GetDT(IntRect(IntPoint(), mTarget->GetSize())); - mTarget->CopySurface(surf, IntRect(IntPoint(), mTarget->GetSize()), IntPoint()); + mBufferProvider = new PersistentBufferProviderBasic(mTarget); return mBufferProvider; } diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index dee05fd671..311086a6f3 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -44,77 +44,12 @@ class StringOrCanvasGradientOrCanvasPattern; class OwningStringOrCanvasGradientOrCanvasPattern; class TextMetrics; class CanvasFilterChainObserver; +class CanvasPath; extern const mozilla::gfx::Float SIGMA_MAX; template class Optional; -class CanvasPath final : - public nsWrapperCache -{ -public: - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CanvasPath) - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CanvasPath) - - nsCOMPtr GetParentObject() { return mParent; } - - JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto); - - static already_AddRefed Constructor(const GlobalObject& aGlobal, - ErrorResult& rv); - static already_AddRefed Constructor(const GlobalObject& aGlobal, - CanvasPath& aCanvasPath, - ErrorResult& rv); - static already_AddRefed Constructor(const GlobalObject& aGlobal, - const nsAString& aPathString, - ErrorResult& rv); - - void ClosePath(); - void MoveTo(double x, double y); - void LineTo(double x, double y); - void QuadraticCurveTo(double cpx, double cpy, double x, double y); - void BezierCurveTo(double cp1x, double cp1y, - double cp2x, double cp2y, - double x, double y); - void ArcTo(double x1, double y1, double x2, double y2, double radius, - ErrorResult& error); - void Rect(double x, double y, double w, double h); - void Arc(double x, double y, double radius, - double startAngle, double endAngle, bool anticlockwise, - ErrorResult& error); - void Ellipse(double x, double y, double radiusX, double radiusY, - double rotation, double startAngle, double endAngle, - bool anticlockwise, ErrorResult& error); - - void LineTo(const gfx::Point& aPoint); - void BezierTo(const gfx::Point& aCP1, - const gfx::Point& aCP2, - const gfx::Point& aCP3); - - already_AddRefed GetPath(const CanvasWindingRule& aWinding, - const gfx::DrawTarget* aTarget) const; - - explicit CanvasPath(nsISupports* aParent); - // already_AddRefed arg because the return value from Path::CopyToBuilder() - // is passed directly and we can't drop the only ref to have a raw pointer. - CanvasPath(nsISupports* aParent, - already_AddRefed aPathBuilder); - - void AddPath(CanvasPath& aCanvasPath, - const Optional>& aMatrix); - -private: - virtual ~CanvasPath() {} - - nsCOMPtr mParent; - static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); } - - mutable RefPtr mPath; - mutable RefPtr mPathBuilder; - - void EnsurePathBuilder() const; -}; - struct CanvasBidiProcessor; class CanvasRenderingContext2DUserData; class CanvasDrawObserver; @@ -977,6 +912,7 @@ protected: fillRule(mozilla::gfx::FillRule::FILL_WINDING), lineCap(mozilla::gfx::CapStyle::BUTT), lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL), + filterString(MOZ_UTF16("none")), imageSmoothingEnabled(true), fontExplicitLanguage(false) { } diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 117eb3c795..07d5b27507 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -28,6 +28,7 @@ EXPORTS.mozilla.ipc += [ EXPORTS.mozilla.dom += [ 'CanvasGradient.h', + 'CanvasPath.h', 'CanvasPattern.h', 'CanvasRenderingContext2D.h', 'CanvasUtils.h', diff --git a/dom/canvas/test/test_hitregion_event.html b/dom/canvas/test/test_hitregion_event.html index 69df682cf7..4f74d82007 100644 --- a/dom/canvas/test/test_hitregion_event.html +++ b/dom/canvas/test/test_hitregion_event.html @@ -32,16 +32,29 @@ SpecialPowers.pushPrefEnv({"set": [["canvas.hitregions.enabled", true]]}, functi ctx.rect(20, 20, 100, 75); ctx.fill(); ctx.addHitRegion({id: "a"}); + ctx.beginPath(); ctx.fillStyle = "red"; ctx.rect(60, 40, 100, 75); ctx.fill(); ctx.addHitRegion({id: "b"}); + + var mypath = new Path2D(); + mypath.rect(80, 60, 10, 10); + ctx.beginPath(); ctx.fillStyle = "yellow"; ctx.rect(80, 60, 10, 10); ctx.fill(); - ctx.addHitRegion({id: "c"}); + ctx.addHitRegion({id: "c", path: mypath}); + + ctx.beginPath(); + ctx.fillStyle = "green"; + ctx.rect(60, 60, 10, 10); // This region is on purpose not the hit region + ctx.fill(); + var mypath = new Path2D(); + mypath.rect(70, 30, 10, 10); + ctx.addHitRegion({id: "d", path: mypath}); synthesizeMouse(input, 25,25, {type: "mousedown"}); is(regionId, "a", "Hit region a", ". Found: " + regionId); @@ -55,6 +68,9 @@ SpecialPowers.pushPrefEnv({"set": [["canvas.hitregions.enabled", true]]}, functi synthesizeMouse(input, 85,65, {type: "mousedown"}); is(regionId, "c", "Hit region c", ". Found: " + regionId); + synthesizeMouse(input, 75,35, {type: "mousedown"}); + is(regionId, "d", "Hit region d", ". Found: " + regionId); + ctx.removeHitRegion("c"); synthesizeMouse(input, 85,65, {type: "mousedown"}); is(regionId, "b", "Hit region b", ". Found: " + regionId); diff --git a/dom/system/gonk/AudioManager.cpp b/dom/system/gonk/AudioManager.cpp index 949a320760..4df3951c56 100644 --- a/dom/system/gonk/AudioManager.cpp +++ b/dom/system/gonk/AudioManager.cpp @@ -81,10 +81,14 @@ static int sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = { }; // A bitwise variable for recording what kind of headset is attached. static int sHeadsetState; +#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17 static bool sBluetoothA2dpEnabled; +#endif static const int kBtSampleRate = 8000; static bool sSwitchDone = true; +#ifdef MOZ_B2G_BT static bool sA2dpSwitchDone = true; +#endif namespace mozilla { namespace dom { @@ -216,6 +220,7 @@ static void ProcessDelayedAudioRoute(SwitchState aState) sSwitchDone = true; } +#ifdef MOZ_B2G_BT static void ProcessDelayedA2dpRoute(audio_policy_dev_state_t aState, const nsCString aAddress) { if (sA2dpSwitchDone) @@ -228,6 +233,7 @@ static void ProcessDelayedA2dpRoute(audio_policy_dev_state_t aState, const nsCSt AudioSystem::setParameters(0, cmd); sA2dpSwitchDone = true; } +#endif NS_IMPL_ISUPPORTS(AudioManager, nsIAudioManager, nsIObserver) diff --git a/dom/webidl/CanvasRenderingContext2D.webidl b/dom/webidl/CanvasRenderingContext2D.webidl index 8b64a7e87a..dd758b2e1d 100644 --- a/dom/webidl/CanvasRenderingContext2D.webidl +++ b/dom/webidl/CanvasRenderingContext2D.webidl @@ -21,6 +21,7 @@ dictionary ContextAttributes2D { }; dictionary HitRegionOptions { + Path2D? path = null; DOMString id = ""; Element? control = null; }; diff --git a/gfx/2d/MMIHelpers.h b/gfx/2d/MMIHelpers.h new file mode 100644 index 0000000000..2a9b16a9d2 --- /dev/null +++ b/gfx/2d/MMIHelpers.h @@ -0,0 +1,196 @@ +/* + ============================================================================ + Name : MMIHelpers.h + Author : Heiher + Version : 0.0.1 + Copyright : Copyright (c) 2015 everyone. + Description : The helpers for x86 SSE to Loongson MMI. + ============================================================================ + */ + +#ifndef __MMI_HELPERS_H__ +#define __MMI_HELPERS_H__ + +#define __mm_packxxxx(_f, _D, _d, _s, _t) \ + #_f" %["#_t"], %["#_d"h], %["#_s"h] \n\t" \ + #_f" %["#_D"l], %["#_d"l], %["#_s"l] \n\t" \ + "punpckhwd %["#_D"h], %["#_D"l], %["#_t"] \n\t" \ + "punpcklwd %["#_D"l], %["#_D"l], %["#_t"] \n\t" + +#define _mm_or(_D, _d, _s) \ + "or %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "or %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +#define _mm_xor(_D, _d, _s) \ + "xor %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "xor %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +#define _mm_and(_D, _d, _s) \ + "and %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "and %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: pandn */ +#define _mm_pandn(_D, _d, _s) \ + "pandn %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "pandn %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: pshuflw */ +#define _mm_pshuflh(_D, _d, _s) \ + "mov.d %["#_D"h], %["#_d"h] \n\t" \ + "pshufh %["#_D"l], %["#_d"l], %["#_s"] \n\t" + +/* SSE: psllw (bits) */ +#define _mm_psllh(_D, _d, _s) \ + "psllh %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "psllh %["#_D"l], %["#_d"l], %["#_s"] \n\t" + +/* SSE: pslld (bits) */ +#define _mm_psllw(_D, _d, _s) \ + "psllw %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "psllw %["#_D"l], %["#_d"l], %["#_s"] \n\t" + +/* SSE: psllq (bits) */ +#define _mm_pslld(_D, _d, _s) \ + "dsll %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "dsll %["#_D"l], %["#_d"l], %["#_s"] \n\t" + +/* SSE: pslldq (bytes) */ +#define _mm_psllq(_D, _d, _s, _s64, _tf) \ + "subu %["#_tf"], %["#_s64"], %["#_s"] \n\t" \ + "dsrl %["#_tf"], %["#_d"l], %["#_tf"] \n\t" \ + "dsll %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "dsll %["#_D"l], %["#_d"l], %["#_s"] \n\t" \ + "or %["#_D"h], %["#_D"h], %["#_tf"] \n\t" + +/* SSE: psrlw (bits) */ +#define _mm_psrlh(_D, _d, _s) \ + "psrlh %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "psrlh %["#_D"l], %["#_d"l], %["#_s"] \n\t" + +/* SSE: psrld (bits) */ +#define _mm_psrlw(_D, _d, _s) \ + "psrlw %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "psrlw %["#_D"l], %["#_d"l], %["#_s"] \n\t" + +/* SSE: psrlq (bits) */ +#define _mm_psrld(_D, _d, _s) \ + "dsrl %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "dsrl %["#_D"l], %["#_d"l], %["#_s"] \n\t" + +/* SSE: psrldq (bytes) */ +#define _mm_psrlq(_D, _d, _s, _s64, _tf) \ + "subu %["#_tf"], %["#_s64"], %["#_s"] \n\t" \ + "dsll %["#_tf"], %["#_d"h], %["#_tf"] \n\t" \ + "dsrl %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "dsrl %["#_D"l], %["#_d"l], %["#_s"] \n\t" \ + "or %["#_D"l], %["#_D"l], %["#_tf"] \n\t" + +/* SSE: psrad */ +#define _mm_psraw(_D, _d, _s) \ + "psraw %["#_D"h], %["#_d"h], %["#_s"] \n\t" \ + "psraw %["#_D"l], %["#_d"l], %["#_s"] \n\t" + +/* SSE: paddb */ +#define _mm_paddb(_D, _d, _s) \ + "paddb %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "paddb %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: paddw */ +#define _mm_paddh(_D, _d, _s) \ + "paddh %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "paddh %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: paddd */ +#define _mm_paddw(_D, _d, _s) \ + "paddw %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "paddw %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: paddq */ +#define _mm_paddd(_D, _d, _s) \ + "dadd %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "dadd %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: psubw */ +#define _mm_psubh(_D, _d, _s) \ + "psubh %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "psubh %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: psubd */ +#define _mm_psubw(_D, _d, _s) \ + "psubw %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "psubw %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: pmaxub */ +#define _mm_pmaxub(_D, _d, _s) \ + "pmaxub %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "pmaxub %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: pmullw */ +#define _mm_pmullh(_D, _d, _s) \ + "pmullh %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "pmullh %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: pmulhw */ +#define _mm_pmulhh(_D, _d, _s) \ + "pmulhh %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "pmulhh %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: pmuludq */ +#define _mm_pmuluw(_D, _d, _s) \ + "pmuluw %["#_D"h], %["#_d"h], %["#_s"h] \n\t" \ + "pmuluw %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: packsswb */ +#define _mm_packsshb(_D, _d, _s, _t) \ + __mm_packxxxx(packsshb, _D, _d, _s, _t) + +/* SSE: packssdw */ +#define _mm_packsswh(_D, _d, _s, _t) \ + __mm_packxxxx(packsswh, _D, _d, _s, _t) + +/* SSE: packuswb */ +#define _mm_packushb(_D, _d, _s, _t) \ + __mm_packxxxx(packushb, _D, _d, _s, _t) + +/* SSE: punpcklbw */ +#define _mm_punpcklbh(_D, _d, _s) \ + "punpckhbh %["#_D"h], %["#_d"l], %["#_s"l] \n\t" \ + "punpcklbh %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: punpcklwd */ +#define _mm_punpcklhw(_D, _d, _s) \ + "punpckhhw %["#_D"h], %["#_d"l], %["#_s"l] \n\t" \ + "punpcklhw %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: punpckldq */ +#define _mm_punpcklwd(_D, _d, _s) \ + "punpckhwd %["#_D"h], %["#_d"l], %["#_s"l] \n\t" \ + "punpcklwd %["#_D"l], %["#_d"l], %["#_s"l] \n\t" + +/* SSE: punpcklqdq */ +#define _mm_punpckldq(_D, _d, _s) \ + "mov.d %["#_D"h], %["#_s"l] \n\t" \ + "mov.d %["#_D"l], %["#_d"l] \n\t" + +/* SSE: punpckhbw */ +#define _mm_punpckhbh(_D, _d, _s) \ + "punpcklbh %["#_D"l], %["#_d"h], %["#_s"h] \n\t" \ + "punpckhbh %["#_D"h], %["#_d"h], %["#_s"h] \n\t" + +/* SSE: punpckhwd */ +#define _mm_punpckhhw(_D, _d, _s) \ + "punpcklhw %["#_D"l], %["#_d"h], %["#_s"h] \n\t" \ + "punpckhhw %["#_D"h], %["#_d"h], %["#_s"h] \n\t" + +/* SSE: punpckhdq */ +#define _mm_punpckhwd(_D, _d, _s) \ + "punpcklwd %["#_D"l], %["#_d"h], %["#_s"h] \n\t" \ + "punpckhwd %["#_D"h], %["#_d"h], %["#_s"h] \n\t" + +/* SSE: punpckhqdq */ +#define _mm_punpckhdq(_D, _d, _s) \ + "mov.d %["#_D"l], %["#_d"h] \n\t" \ + "mov.d %["#_D"h], %["#_s"h] \n\t" + +#endif /* __MMI_HELPERS_H__ */ + diff --git a/gfx/2d/SourceSurfaceSkia.cpp b/gfx/2d/SourceSurfaceSkia.cpp index e55b01b556..2de51f681c 100644 --- a/gfx/2d/SourceSurfaceSkia.cpp +++ b/gfx/2d/SourceSurfaceSkia.cpp @@ -101,6 +101,7 @@ SourceSurfaceSkia::InitFromTexture(DrawTargetSkia* aOwner, SurfaceFormat aFormat) { MOZ_ASSERT(aOwner, "null GrContext"); +#ifdef USE_SKIA_GPU GrBackendTextureDesc skiaTexGlue; mSize.width = skiaTexGlue.fWidth = aSize.width; mSize.height = skiaTexGlue.fHeight = aSize.height; @@ -117,6 +118,7 @@ SourceSurfaceSkia::InitFromTexture(DrawTargetSkia* aOwner, mBitmap.setPixelRef(texRef); mFormat = aFormat; mStride = mBitmap.rowBytes(); +#endif mDrawTarget = aOwner; return true; diff --git a/gfx/2d/image_operations.cpp b/gfx/2d/image_operations.cpp index fc6eabc1b2..7d9b44da04 100644 --- a/gfx/2d/image_operations.cpp +++ b/gfx/2d/image_operations.cpp @@ -168,15 +168,19 @@ ImageOperations::ResizeMethod ResizeMethodToAlgorithmMethod( // GPU-acceleration in the cases where it is possible. So now we just // pick the appropriate software method for each resize quality. switch (method) { + // Users of RESIZE_GOOD are willing to trade a lot of quality to + // get speed, allowing the use of linear resampling to get hardware + // acceleration (SRB). Hence any of our "good" software filters + // will be acceptable, and we use the fastest one, Hamming-1. case ImageOperations::RESIZE_GOOD: - // In visual tests we see that Hamming-1 is not as good as - // Lanczos-2, however it is about 40% faster, and Lanczos-2 itself is + // Users of RESIZE_BETTER are willing to trade some quality in order + // to improve performance, but are guaranteed not to devolve to a linear + // resampling. In visual tests we see that Hamming-1 is not as good as + // Lanczos-2, however it is about 40% faster and Lanczos-2 itself is // about 30% faster than Lanczos-3. The use of Hamming-1 has been deemed - // an unacceptable trade-off between quality and speed due to the limited - // pixel space it operates in (<50%) before switching to HQ scaling - // becomes necessary to retain the fidelity of images. + // an acceptable trade-off between quality and speed. case ImageOperations::RESIZE_BETTER: - return ImageOperations::RESIZE_LANCZOS2; + return ImageOperations::RESIZE_HAMMING1; default: return ImageOperations::RESIZE_LANCZOS3; } diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 6aab327c4d..4af02ce4f1 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -165,12 +165,12 @@ LayerManager::CreatePersistentBufferProvider(const mozilla::gfx::IntSize &aSize, mozilla::gfx::SurfaceFormat aFormat) { RefPtr bufferProvider = - new PersistentBufferProviderBasic(this, aSize, aFormat, + new PersistentBufferProviderBasic(aSize, aFormat, gfxPlatform::GetPlatform()->GetPreferredCanvasBackend()); if (!bufferProvider->IsValid()) { bufferProvider = - new PersistentBufferProviderBasic(this, aSize, aFormat, + new PersistentBufferProviderBasic(aSize, aFormat, gfxPlatform::GetPlatform()->GetFallbackCanvasBackend()); } diff --git a/gfx/layers/PersistentBufferProvider.cpp b/gfx/layers/PersistentBufferProvider.cpp index 9e7fe379e2..a0ddd17cee 100644 --- a/gfx/layers/PersistentBufferProvider.cpp +++ b/gfx/layers/PersistentBufferProvider.cpp @@ -16,8 +16,8 @@ using namespace gfx; namespace layers { -PersistentBufferProviderBasic::PersistentBufferProviderBasic(LayerManager* aManager, gfx::IntSize aSize, - gfx::SurfaceFormat aFormat, gfx::BackendType aBackend) +PersistentBufferProviderBasic::PersistentBufferProviderBasic(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, + gfx::BackendType aBackend) { mDrawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(aBackend, aSize, aFormat); } diff --git a/gfx/layers/PersistentBufferProvider.h b/gfx/layers/PersistentBufferProvider.h index 3a48755c70..35835b7e94 100644 --- a/gfx/layers/PersistentBufferProvider.h +++ b/gfx/layers/PersistentBufferProvider.h @@ -7,7 +7,7 @@ #define MOZILLA_GFX_PersistentBUFFERPROVIDER_H #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc -#include "mozilla/RefPtr.h" // for RefPtr, TemporaryRef, etc +#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed, etc #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/CompositableForwarder.h" #include "mozilla/gfx/Types.h" @@ -57,8 +57,9 @@ class PersistentBufferProviderBasic : public PersistentBufferProvider public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProviderBasic) - PersistentBufferProviderBasic(LayerManager* aManager, gfx::IntSize aSize, - gfx::SurfaceFormat aFormat, gfx::BackendType aBackend); + PersistentBufferProviderBasic(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, + gfx::BackendType aBackend); + explicit PersistentBufferProviderBasic(gfx::DrawTarget* aTarget) : mDrawTarget(aTarget) {} bool IsValid() { return !!mDrawTarget; } virtual LayersBackend GetType() { return LayersBackend::LAYERS_BASIC; } @@ -69,6 +70,7 @@ private: RefPtr mDrawTarget; }; -} -} +} // namespace layers +} // namespace mozilla + #endif diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 83ed6e6aaf..48179f941b 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -1104,6 +1104,7 @@ void gfxPlatform::InitializeSkiaCacheLimits() { if (UseAcceleratedSkiaCanvas()) { +#ifdef USE_SKIA_GPU bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache(); int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems(); int cacheSizeLimit = gfxPrefs::CanvasSkiaGLCacheSize(); @@ -1125,7 +1126,6 @@ gfxPlatform::InitializeSkiaCacheLimits() printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit); #endif -#ifdef USE_SKIA_GPU mSkiaGlue->GetGrContext()->setResourceCacheLimits(cacheItemLimit, cacheSizeLimit); #endif } diff --git a/image/DecodePool.cpp b/image/DecodePool.cpp index bfd7eb373f..52dbe20255 100644 --- a/image/DecodePool.cpp +++ b/image/DecodePool.cpp @@ -246,7 +246,7 @@ private: { Work work; work.mType = Work::Type::DECODE; - work.mDecoder = aQueue.LastElement(); + work.mDecoder = aQueue.LastElement().forget(); aQueue.RemoveElementAt(aQueue.Length() - 1); return work; diff --git a/image/Decoder.cpp b/image/Decoder.cpp index 21c35044aa..437672b1fd 100644 --- a/image/Decoder.cpp +++ b/image/Decoder.cpp @@ -431,9 +431,10 @@ Decoder::PostIsAnimated(int32_t aFirstFrameTimeout) } void -Decoder::PostFrameStop(Opacity aFrameOpacity /* = Opacity::TRANSPARENT */, +Decoder::PostFrameStop(Opacity aFrameOpacity + /* = Opacity::SOME_TRANSPARENCY */, DisposalMethod aDisposalMethod - /* = DisposalMethod::KEEP */, + /* = DisposalMethod::KEEP */, int32_t aTimeout /* = 0 */, BlendMethod aBlendMethod /* = BlendMethod::OVER */) { diff --git a/image/Decoder.h b/image/Decoder.h index ccd3c4e004..c9b68d24ec 100644 --- a/image/Decoder.h +++ b/image/Decoder.h @@ -196,7 +196,6 @@ public: bool HasDecoderError() const { return NS_FAILED(mFailCode); } bool ShouldReportError() const { return mShouldReportError; } nsresult GetDecoderError() const { return mFailCode; } - void PostResizeError() { PostDataError(); } /// Did we finish decoding enough that calling Decode() again would be useless? bool GetDecodeDone() const @@ -205,10 +204,6 @@ public: HasError() || mDataDone; } - /// Did we finish decoding enough to set |RasterImage::mHasBeenDecoded|? - // XXX(seth): This will be removed in bug 1187401. - bool GetDecodeTotallyDone() const { return mDecodeDone && !IsMetadataDecode(); } - /// Are we in the middle of a frame right now? Used for assertions only. bool InFrame() const { return mInFrame; } diff --git a/image/MultipartImage.cpp b/image/MultipartImage.cpp index b849d2afe9..1778e629f0 100644 --- a/image/MultipartImage.cpp +++ b/image/MultipartImage.cpp @@ -38,10 +38,16 @@ public: void BlockUntilDecodedAndFinishObserving() { // Use GetFrame() to block until our image finishes decoding. - mImage->GetFrame(imgIContainer::FRAME_CURRENT, - imgIContainer::FLAG_SYNC_DECODE); + nsRefPtr surface = + mImage->GetFrame(imgIContainer::FRAME_CURRENT, + imgIContainer::FLAG_SYNC_DECODE); - FinishObserving(); + // GetFrame() should've sent synchronous notifications that would have + // caused us to call FinishObserving() (and null out mImage) already. If for + // some reason it didn't, we should do so here. + if (mImage) { + FinishObserving(); + } } virtual void Notify(int32_t aType, @@ -129,9 +135,7 @@ MultipartImage::~MultipartImage() mTracker->ResetImage(); } -NS_IMPL_QUERY_INTERFACE_INHERITED0(MultipartImage, ImageWrapper) -NS_IMPL_ADDREF(MultipartImage) -NS_IMPL_RELEASE(MultipartImage) +NS_IMPL_ISUPPORTS_INHERITED0(MultipartImage, ImageWrapper) void MultipartImage::BeginTransitionToPart(Image* aNextPart) @@ -154,7 +158,16 @@ MultipartImage::BeginTransitionToPart(Image* aNextPart) mNextPart->IncrementAnimationConsumers(); } -void MultipartImage::FinishTransition() +static Progress +FilterProgress(Progress aProgress) +{ + // Filter out onload blocking notifications, since we don't want to block + // onload for multipart images. + return aProgress & ~(FLAG_ONLOAD_BLOCKED | FLAG_ONLOAD_UNBLOCKED); +} + +void +MultipartImage::FinishTransition() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mNextPart, "Should have a next part here"); @@ -169,7 +182,8 @@ void MultipartImage::FinishTransition() mTracker->ResetForNewRequest(); nsRefPtr currentPartTracker = InnerImage()->GetProgressTracker(); - mTracker->SyncNotifyProgress(currentPartTracker->GetProgress()); + mTracker + ->SyncNotifyProgress(FilterProgress(currentPartTracker->GetProgress())); return; } @@ -189,8 +203,9 @@ void MultipartImage::FinishTransition() // Finally, send all the notifications for the new current part and send a // FRAME_UPDATE notification so that observers know to redraw. - mTracker->SyncNotifyProgress(newCurrentPartTracker->GetProgress(), - GetMaxSizedIntRect()); + mTracker + ->SyncNotifyProgress(FilterProgress(newCurrentPartTracker->GetProgress()), + GetMaxSizedIntRect()); } already_AddRefed diff --git a/image/MultipartImage.h b/image/MultipartImage.h index 95fce0ce0a..b041e72135 100644 --- a/image/MultipartImage.h +++ b/image/MultipartImage.h @@ -25,7 +25,7 @@ class MultipartImage { public: MOZ_DECLARE_REFCOUNTED_TYPENAME(MultipartImage) - NS_DECL_ISUPPORTS + NS_DECL_ISUPPORTS_INHERITED void BeginTransitionToPart(Image* aNextPart); diff --git a/image/Orientation.h b/image/Orientation.h index f18ced8542..a0f2e1b75a 100644 --- a/image/Orientation.h +++ b/image/Orientation.h @@ -56,7 +56,7 @@ struct Orientation Flip flip; }; -} -} +} // namespace image +} // namespace mozilla #endif // mozilla_image_Orientation_h diff --git a/image/ProgressTracker.cpp b/image/ProgressTracker.cpp index b0a76a762e..65e8d39435 100644 --- a/image/ProgressTracker.cpp +++ b/image/ProgressTracker.cpp @@ -441,13 +441,14 @@ void ProgressTracker::AddObserver(IProgressObserver* aObserver) { MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr observer = aObserver; mObservers.Write([=](ObserverTable* aTable) { - MOZ_ASSERT(!aTable->Get(aObserver, nullptr), + MOZ_ASSERT(!aTable->Get(observer, nullptr), "Adding duplicate entry for image observer"); - WeakPtr weakPtr = aObserver; - aTable->Put(aObserver, weakPtr); + WeakPtr weakPtr = observer.get(); + aTable->Put(observer, weakPtr); }); } @@ -455,11 +456,12 @@ bool ProgressTracker::RemoveObserver(IProgressObserver* aObserver) { MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr observer = aObserver; // Remove the observer from the list. bool removed = mObservers.Write([=](ObserverTable* aTable) { - bool removed = aTable->Get(aObserver, nullptr); - aTable->Remove(aObserver); + bool removed = aTable->Get(observer, nullptr); + aTable->Remove(observer); return removed; }); diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index b056ad0302..ce84fe0698 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -819,20 +819,22 @@ RasterImage::OnAddedFrame(uint32_t aNewFrameCount, } } -nsresult +void RasterImage::SetMetadata(const ImageMetadata& aMetadata, bool aFromMetadataDecode) { MOZ_ASSERT(NS_IsMainThread()); if (mError) { - return NS_ERROR_FAILURE; + return; } if (aMetadata.HasSize()) { IntSize size = aMetadata.GetSize(); if (size.width < 0 || size.height < 0) { - return NS_ERROR_INVALID_ARG; + NS_WARNING("Image has negative intrinsic size"); + DoError(); + return; } MOZ_ASSERT(aMetadata.HasOrientation()); @@ -843,7 +845,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata, NS_WARNING("Image changed size or orientation on redecode! " "This should not happen!"); DoError(); - return NS_ERROR_UNEXPECTED; + return; } // Set the size and flag that we have it. @@ -887,8 +889,6 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata, Set("hotspotX", intwrapx); Set("hotspotY", intwrapy); } - - return NS_OK; } NS_IMETHODIMP @@ -1074,7 +1074,7 @@ RasterImage::NotifyForLoadEvent(Progress aProgress) if (mError) { aProgress |= FLAG_HAS_ERROR; } - + // Notify our listeners, which will fire this image's load event. NotifyProgress(aProgress); } @@ -1374,6 +1374,11 @@ RasterImage::RecoverFromInvalidFrames(const IntSize& aSize, uint32_t aFlags) // Discard all existing frames, since they're probably all now invalid. SurfaceCache::RemoveImage(ImageKey(this)); + // Relock the image if it's supposed to be locked. + if (mLockCount > 0) { + SurfaceCache::LockImage(ImageKey(this)); + } + // Animated images require some special handling, because we normally require // that they never be discarded. if (mAnim) { @@ -1707,22 +1712,20 @@ RasterImage::FinalizeDecoder(Decoder* aDecoder) MOZ_ASSERT(aDecoder->HasError() || !aDecoder->InFrame(), "Finalizing a decoder in the middle of a frame"); + bool wasMetadata = aDecoder->IsMetadataDecode(); + bool done = aDecoder->GetDecodeDone(); + // If the decoder detected an error, log it to the error console. if (aDecoder->ShouldReportError() && !aDecoder->WasAborted()) { ReportDecoderError(aDecoder); } // Record all the metadata the decoder gathered about this image. - nsresult rv = SetMetadata(aDecoder->GetImageMetadata(), - aDecoder->IsMetadataDecode()); - if (NS_FAILED(rv)) { - aDecoder->PostResizeError(); - } - + SetMetadata(aDecoder->GetImageMetadata(), wasMetadata); MOZ_ASSERT(mError || mHasSize || !aDecoder->HasSize(), - "Should have handed off size by now"); + "SetMetadata should've gotten a size"); - if (aDecoder->GetDecodeTotallyDone() && !mError) { + if (!wasMetadata && aDecoder->GetDecodeDone() && !aDecoder->WasAborted()) { // Flag that we've been decoded before. mHasBeenDecoded = true; if (mAnim) { @@ -1735,9 +1738,6 @@ RasterImage::FinalizeDecoder(Decoder* aDecoder) aDecoder->TakeInvalidRect(), aDecoder->GetSurfaceFlags()); - bool wasMetadata = aDecoder->IsMetadataDecode(); - bool done = aDecoder->GetDecodeDone(); - if (!wasMetadata && aDecoder->ChunkCount()) { /*Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, aDecoder->ChunkCount());*/ diff --git a/image/RasterImage.h b/image/RasterImage.h index 4aad6e72eb..c962cf69c8 100644 --- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -325,7 +325,7 @@ private: * @param aFromMetadataDecode True if this metadata came from a metadata * decode; false if it came from a full decode. */ - nsresult SetMetadata(const ImageMetadata& aMetadata, bool aFromMetadataDecode); + void SetMetadata(const ImageMetadata& aMetadata, bool aFromMetadataDecode); /** * In catastrophic circumstances like a GPU driver crash, the contents of our @@ -347,10 +347,10 @@ private: // data /// If this has a value, we're waiting for SetSize() to send the load event. Maybe mLoadProgress; - nsCOMPtr mProperties; + nsCOMPtr mProperties; /// If this image is animated, a FrameAnimator which manages its animation. - UniquePtr mAnim; + UniquePtr mAnim; // Image locking. uint32_t mLockCount; @@ -360,7 +360,7 @@ private: // data // How many times we've decoded this image. // This is currently only used for statistics - int32_t mDecodeCount; + int32_t mDecodeCount; // If the image contains multiple resolutions, a hint as to which one // should be used @@ -378,7 +378,7 @@ private: // data DrawResult mLastImageContainerDrawResult; #ifdef DEBUG - uint32_t mFramesNotified; + uint32_t mFramesNotified; #endif // The source data for this image. diff --git a/image/SVGDocumentWrapper.h b/image/SVGDocumentWrapper.h index dec656004d..7d7586ae37 100644 --- a/image/SVGDocumentWrapper.h +++ b/image/SVGDocumentWrapper.h @@ -35,8 +35,8 @@ class SVGSVGElement; namespace image { class SVGDocumentWrapper final : public nsIStreamListener, - public nsIObserver, - nsSupportsWeakReference + public nsIObserver, + nsSupportsWeakReference { public: SVGDocumentWrapper(); diff --git a/image/SourceBuffer.h b/image/SourceBuffer.h index b87ea6f029..e0cdd926c8 100644 --- a/image/SourceBuffer.h +++ b/image/SourceBuffer.h @@ -120,7 +120,8 @@ public: /// If at the end, returns the status passed to SourceBuffer::Complete(). nsresult CompletionStatus() const { - MOZ_ASSERT(mState == COMPLETE, "Calling CompletionStatus() in the wrong state"); + MOZ_ASSERT(mState == COMPLETE, + "Calling CompletionStatus() in the wrong state"); return mState == COMPLETE ? mData.mAtEnd.mStatus : NS_OK; } @@ -209,12 +210,6 @@ private: * keep a list of consumers which are waiting for new data, and to resume them * when the producer appends more. All consumers must implement the IResumable * interface to make this possible. - * - * XXX(seth): We should add support for compacting a SourceBuffer. To do this, - * we need to have SourceBuffer keep track of how many live - * SourceBufferIterator's point to it. When the SourceBuffer is complete and no - * live SourceBufferIterator's for it remain, we can compact its contents into a - * single chunk. */ class SourceBuffer final { diff --git a/image/SurfaceCache.cpp b/image/SurfaceCache.cpp index 3a9c49e9cb..6ffc76b3bf 100644 --- a/image/SurfaceCache.cpp +++ b/image/SurfaceCache.cpp @@ -35,6 +35,7 @@ #include "nsSize.h" #include "nsTArray.h" #include "prsystem.h" +#include "ShutdownTracker.h" #include "SVGImageContext.h" using std::max; @@ -436,6 +437,7 @@ public: , mMaxCost(aSurfaceCacheSize) , mAvailableCost(aSurfaceCacheSize) , mLockedCost(0) + , mOverflowCount(0) { nsCOMPtr os = services::GetObserverService(); if (os) { @@ -483,6 +485,7 @@ public: // If this is bigger than we can hold after discarding everything we can, // refuse to cache it. if (MOZ_UNLIKELY(!CanHoldAfterDiscarding(aCost))) { + mOverflowCount++; return InsertOutcome::FAILURE; } @@ -582,7 +585,8 @@ public: } else { // Our call to AddObject must have failed in StartTracking; most likely // we're in XPCOM shutdown right now. - NS_WARNING("Not expiration-tracking an unlocked surface!"); + NS_ASSERTION(ShutdownTracker::ShutdownHasStarted(), + "Not expiration-tracking an unlocked surface!"); } DebugOnly foundInCosts = mCosts.RemoveElementSorted(costEntry); @@ -863,6 +867,14 @@ public: "imagelib surface cache."); NS_ENSURE_SUCCESS(rv, rv); + rv = MOZ_COLLECT_REPORT("imagelib-surface-cache-overflow-count", + KIND_OTHER, UNITS_COUNT, + mOverflowCount, + "Count of how many times the surface cache has hit " + "its capacity and been unable to insert a new " + "surface."); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; } @@ -962,6 +974,7 @@ private: const Cost mMaxCost; Cost mAvailableCost; Cost mLockedCost; + size_t mOverflowCount; }; NS_IMPL_ISUPPORTS(SurfaceCacheImpl, nsIMemoryReporter) @@ -1079,6 +1092,11 @@ SurfaceCache::Insert(imgFrame* aSurface, return InsertOutcome::FAILURE; } + // Refuse null surfaces. + if (!aSurface) { + MOZ_CRASH("Don't pass null surfaces to SurfaceCache::Insert"); + } + MutexAutoLock lock(sInstance->GetMutex()); Cost cost = ComputeCost(aSurface->GetSize(), aSurface->GetBytesPerPixel()); return sInstance->Insert(aSurface, cost, aImageKey, aSurfaceKey); diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index c9bcca1706..5ce1060bc6 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -9,7 +9,6 @@ #include "gfxContext.h" #include "gfxDrawable.h" #include "gfxPlatform.h" -#include "gfxPrefs.h" // for surface cache size #include "gfxUtils.h" #include "imgFrame.h" #include "mozilla/AutoRestore.h" @@ -49,6 +48,8 @@ namespace image { // Helper-class: SVGRootRenderingObserver class SVGRootRenderingObserver final : public nsSVGRenderingObserver { public: + NS_DECL_ISUPPORTS + SVGRootRenderingObserver(SVGDocumentWrapper* aDocWrapper, VectorImage* aVectorImage) : nsSVGRenderingObserver() @@ -67,10 +68,6 @@ public: mInObserverList = true; } - virtual ~SVGRootRenderingObserver() - { - StopListening(); - } void ResumeHonoringInvalidations() { @@ -78,6 +75,11 @@ public: } protected: + virtual ~SVGRootRenderingObserver() + { + StopListening(); + } + virtual Element* GetTarget() override { return mDocWrapper->GetRootSVGElem(); @@ -115,6 +117,8 @@ protected: bool mHonoringInvalidations; }; +NS_IMPL_ISUPPORTS(SVGRootRenderingObserver, nsIMutationObserver) + class SVGParseCompleteListener final : public nsStubDocumentObserver { public: NS_DECL_ISUPPORTS @@ -418,13 +422,18 @@ VectorImage::OnImageDataComplete(nsIRequest* aRequest, if (NS_FAILED(aStatus)) { finalStatus = aStatus; } + + Progress loadProgress = LoadCompleteProgress(aLastPart, mError, finalStatus); - // Actually fire OnStopRequest. - if (mProgressTracker) { - mProgressTracker->SyncNotifyProgress(LoadCompleteProgress(aLastPart, - mError, - finalStatus)); + if (mIsFullyLoaded || mError) { + // Our document is loaded, so we're ready to notify now. + mProgressTracker->SyncNotifyProgress(loadProgress); + } else { + // Record our progress so far; we'll actually send the notifications in + // OnSVGDocumentLoaded or OnSVGDocumentError. + mLoadProgress = Some(loadProgress); } + return finalStatus; } @@ -867,32 +876,12 @@ VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams) nsRefPtr svgDrawable = new gfxCallbackDrawable(cb, aParams.size); - // We take an early exit without using the surface cache if too large, - // because for vector images this can cause bad perf issues if large sizes - // are scaled repeatedly (a rather common scenario) that can quickly exhaust - // the cache. - // Similar to max image size calculations, this has a max cap and size check. - // max cap = 8000 (pixels); size check = 5% of cache - int32_t maxDimension = 8000; - int32_t maxCacheElemSize = (gfxPrefs::ImageMemSurfaceCacheMaxSizeKB() * 1024) / 20; - bool bypassCache = bool(aParams.flags & FLAG_BYPASS_SURFACE_CACHE) || // Refuse to cache animated images: // XXX(seth): We may remove this restriction in bug 922893. mHaveAnimations || // The image is too big to fit in the cache: - !SurfaceCache::CanHold(aParams.size) || - // Image x or y is larger than our cache cap: - aParams.size.width > maxDimension || - aParams.size.height > maxDimension; - if (!bypassCache) { - // This is separated out to make sure width and height are sane at this point - // and the result can't overflow. Note: keep maxDimension low enough so that - // (maxDimension)^2 x 4 < INT32_MAX. - // Assuming surface size for any rendered vector image is RGBA, so 4Bpp. - bypassCache = (aParams.size.width * aParams.size.height * 4) > maxCacheElemSize; - } - + !SurfaceCache::CanHold(aParams.size); if (bypassCache) { return Show(svgDrawable, aParams); } @@ -1193,12 +1182,19 @@ VectorImage::OnSVGDocumentLoaded() // Tell *our* observers that we're done loading. if (mProgressTracker) { - mProgressTracker->SyncNotifyProgress(FLAG_SIZE_AVAILABLE | - FLAG_HAS_TRANSPARENCY | - FLAG_FRAME_COMPLETE | - FLAG_DECODE_COMPLETE | - FLAG_ONLOAD_UNBLOCKED, - GetMaxSizedIntRect()); + Progress progress = FLAG_SIZE_AVAILABLE | + FLAG_HAS_TRANSPARENCY | + FLAG_FRAME_COMPLETE | + FLAG_DECODE_COMPLETE | + FLAG_ONLOAD_UNBLOCKED; + + // Merge in any saved progress from OnImageDataComplete. + if (mLoadProgress) { + progress |= *mLoadProgress; + mLoadProgress = Nothing(); + } + + mProgressTracker->SyncNotifyProgress(progress, GetMaxSizedIntRect()); } EvaluateAnimation(); @@ -1215,10 +1211,18 @@ VectorImage::OnSVGDocumentError() mError = true; if (mProgressTracker) { - // Unblock page load. - mProgressTracker->SyncNotifyProgress(FLAG_DECODE_COMPLETE | - FLAG_ONLOAD_UNBLOCKED | - FLAG_HAS_ERROR); + // Notify observers about the error and unblock page load. + Progress progress = FLAG_DECODE_COMPLETE | + FLAG_ONLOAD_UNBLOCKED | + FLAG_HAS_ERROR; + + // Merge in any saved progress from OnImageDataComplete. + if (mLoadProgress) { + progress |= *mLoadProgress; + mLoadProgress = Nothing(); + } + + mProgressTracker->SyncNotifyProgress(progress); } } diff --git a/image/VectorImage.h b/image/VectorImage.h index 9d8699b526..8d918f67a4 100644 --- a/image/VectorImage.h +++ b/image/VectorImage.h @@ -23,7 +23,7 @@ class SVGLoadEventListener; class SVGParseCompleteListener; class VectorImage final : public ImageResource, - public nsIStreamListener + public nsIStreamListener { public: NS_DECL_ISUPPORTS @@ -102,6 +102,12 @@ private: /// Count of locks on this image (roughly correlated to visible instances). uint32_t mLockCount; + // Stored result from the Necko load of the image, which we save in + // OnImageDataComplete if the underlying SVG document isn't loaded. If we save + // this, we actually notify this progress (and clear this value) in + // OnSVGDocumentLoaded or OnSVGDocumentError. + Maybe mLoadProgress; + bool mIsInitialized; // Have we been initialized? bool mDiscardable; // Are we discardable? bool mIsFullyLoaded; // Has the SVG document finished diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index 206f904a81..cd9d4c338a 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -219,6 +219,8 @@ private: const char* aPathPrefix, const ImageMemoryCounter& aCounter) { + nsresult rv; + nsAutoCString pathPrefix(NS_LITERAL_CSTRING("explicit/")); pathPrefix.Append(aPathPrefix); pathPrefix.Append(aCounter.Type() == imgIContainer::TYPE_RASTER @@ -239,7 +241,13 @@ private: pathPrefix.Append(")/"); - return ReportSurfaces(aHandleReport, aData, pathPrefix, aCounter); + rv = ReportSurfaces(aHandleReport, aData, pathPrefix, aCounter); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ReportSourceValue(aHandleReport, aData, pathPrefix, aCounter.Values()); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; } static nsresult ReportSurfaces(nsIHandleReportCallback* aHandleReport, @@ -344,10 +352,7 @@ private: { nsresult rv; - rv = ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix, - "source", - "Raster image source data and vector image documents.", - aCounter.Source()); + rv = ReportSourceValue(aHandleReport, aData, aPathPrefix, aCounter); NS_ENSURE_SUCCESS(rv, rv); rv = ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix, @@ -365,6 +370,21 @@ private: return NS_OK; } + static nsresult ReportSourceValue(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + const nsACString& aPathPrefix, + const MemoryCounter& aCounter) + { + nsresult rv; + + rv = ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix, + "source", + "Raster image source data and vector image documents.", + aCounter.Source()); + + return rv; + } + static nsresult ReportValue(nsIHandleReportCallback* aHandleReport, nsISupports* aData, int32_t aKind, @@ -706,6 +726,8 @@ NewImageChannel(nsIChannel** aResult, nsIPrincipal* aLoadingPrincipal, nsISupports* aRequestingContext) { + MOZ_ASSERT(aResult); + nsresult rv; nsCOMPtr newHttpChannel; @@ -768,7 +790,9 @@ NewImageChannel(nsIChannel** aResult, // we should always have a requestingNode, or we are loading something // outside a document, in which case the triggeringPrincipal // should always be the systemPrincipal. - MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(triggeringPrincipal)); + // However, there are two exceptions: one is Notifications and the + // other one is Favicons which create a channel in the parent prcoess + // in which case we can't get a requestingNode. rv = NS_NewChannel(aResult, aURI, triggeringPrincipal, @@ -1446,9 +1470,8 @@ imgLoader::PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* entry) LOG_STATIC_FUNC_WITH_PARAM(GetImgLog(), "imgLoader::PutIntoCache", "uri", aKey.Spec()); - // Check to see if this request already exists in the cache and is being - // loaded on a different thread. If so, don't allow this entry to be added to - // the cache. + // Check to see if this request already exists in the cache. If so, we'll + // replace the old version. nsRefPtr tmpCacheEntry; if (cache.Get(aKey, getter_AddRefs(tmpCacheEntry)) && tmpCacheEntry) { MOZ_LOG(GetImgLog(), LogLevel::Debug, @@ -1813,7 +1836,7 @@ imgLoader::ValidateEntry(imgCacheEntry* aEntry, // XXX: nullptr seems to be a 'special' key value that indicates that NO // validation is required. // - void *key = (void*)aCX; + void *key = (void*) aCX; if (request->LoadId() != key) { // If we would need to revalidate this entry, but we're being told to // bypass the cache, we don't allow this entry to be used. @@ -2976,6 +2999,9 @@ imgCacheValidator::RemoveProxy(imgRequestProxy* aProxy) NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt) { + // We may be holding on to a document, so ensure that it's released. + nsCOMPtr context = mContext.forget(); + // If for some reason we don't still have an existing request (probably // because OnStartRequest got delivered more than once), just bail. if (!mRequest) { @@ -3024,7 +3050,7 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt) // We don't need to load this any more. aRequest->Cancel(NS_BINDING_ABORTED); - mRequest->SetLoadId(mContext); + mRequest->SetLoadId(context); mRequest->SetValidator(nullptr); mRequest = nullptr; @@ -3067,7 +3093,7 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt) nsCOMPtr originalURI; channel->GetOriginalURI(getter_AddRefs(originalURI)); mNewRequest->Init(originalURI, uri, mHadInsecureRedirect, aRequest, channel, - mNewEntry, mContext, loadingPrincipal, corsmode, refpol); + mNewEntry, context, loadingPrincipal, corsmode, refpol); mDestListener = new ProxyListener(mNewRequest); @@ -3093,11 +3119,19 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt) return mDestListener->OnStartRequest(aRequest, ctxt); } -/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status); */ -NS_IMETHODIMP imgCacheValidator::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, nsresult status) +/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, + in nsresult status); */ +NS_IMETHODIMP +imgCacheValidator::OnStopRequest(nsIRequest* aRequest, + nsISupports* ctxt, + nsresult status) { - if (!mDestListener) + // Be sure we've released the document that we may have been holding on to. + mContext = nullptr; + + if (!mDestListener) { return NS_OK; + } return mDestListener->OnStopRequest(aRequest, ctxt, status); } @@ -3180,7 +3214,9 @@ imgCacheValidator:: if (NS_FAILED(oldChannel->GetURI(getter_AddRefs(oldURI))) || NS_FAILED(oldURI->SchemeIs("https", &isHttps)) || NS_FAILED(oldURI->SchemeIs("chrome", &isChrome)) || - NS_FAILED(NS_URIChainHasFlags(oldURI, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE , &schemeLocal)) || + NS_FAILED(NS_URIChainHasFlags(oldURI, + nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, + &schemeLocal)) || (!isHttps && !isChrome && !schemeLocal)) { mHadInsecureRedirect = true; } diff --git a/image/imgRequest.cpp b/image/imgRequest.cpp index e1606283af..273d9fc5e0 100644 --- a/image/imgRequest.cpp +++ b/image/imgRequest.cpp @@ -634,17 +634,6 @@ imgRequest::SetCacheValidation(imgCacheEntry* aCacheEntry, nsIRequest* aRequest) aCacheEntry->SetMustValidate(bMustRevalidate); } } - - // We always need to validate file URIs. - nsCOMPtr channel = do_QueryInterface(aRequest); - if (channel) { - nsCOMPtr uri; - channel->GetURI(getter_AddRefs(uri)); - bool isfile = false; - uri->SchemeIs("file", &isfile); - if (isfile) - aCacheEntry->SetMustValidate(isfile); - } } } @@ -718,6 +707,13 @@ imgRequest::GetMultipart() const return mIsMultiPartChannel; } +bool +imgRequest::HadInsecureRedirect() const +{ + MutexAutoLock lock(mMutex); + return mHadInsecureRedirect; +} + /** nsIRequestObserver methods **/ NS_IMETHODIMP @@ -737,7 +733,7 @@ imgRequest::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt) mIsMultiPartChannel = bool(multiPartChannel); } - // If we're not multipart, we shouldn't have an image yet + // If we're not multipart, we shouldn't have an image yet. if (image && !multiPartChannel) { MOZ_ASSERT_UNREACHABLE("Already have an image for a non-multipart request"); Cancel(NS_IMAGELIB_ERROR_FAILURE); @@ -752,7 +748,6 @@ imgRequest::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt) * https://bugzilla.mozilla.org/show_bug.cgi?id=339610 */ if (!mRequest) { - nsCOMPtr multiPartChannel = do_QueryInterface(aRequest); MOZ_ASSERT(multiPartChannel, "Should have mRequest unless we're multipart"); nsCOMPtr baseChannel; multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel)); @@ -950,20 +945,20 @@ PrepareForNewPart(nsIRequest* aRequest, nsIInputStream* aInStr, uint32_t aCount, nsCOMPtr chan(do_QueryInterface(aRequest)); if (result.mContentType.IsEmpty()) { - nsresult rv = NS_ERROR_FAILURE; - if (chan) { - rv = chan->GetContentType(result.mContentType); - chan->GetContentDispositionHeader(result.mContentDisposition); - } - + nsresult rv = chan ? chan->GetContentType(result.mContentType) + : NS_ERROR_FAILURE; if (NS_FAILED(rv)) { MOZ_LOG(GetImgLog(), - LogLevel::Error, ("imgRequest::PrepareForNewPart " - "-- Content type unavailable from the channel\n")); + LogLevel::Error, ("imgRequest::PrepareForNewPart -- " + "Content type unavailable from the channel\n")); return result; } } + if (chan) { + chan->GetContentDispositionHeader(result.mContentDisposition); + } + MOZ_LOG(GetImgLog(), LogLevel::Debug, ("imgRequest::PrepareForNewPart -- Got content type %s\n", result.mContentType.get())); @@ -1269,7 +1264,18 @@ imgRequest::OnRedirectVerifyCallback(nsresult result) nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &schemeLocal)) || (!isHttps && !isChrome && !schemeLocal)) { - mHadInsecureRedirect = true; + MutexAutoLock lock(mMutex); + + // The csp directive upgrade-insecure-requests performs an internal redirect + // to upgrade all requests from http to https before any data is fetched from + // the network. Do not pollute mHadInsecureRedirect in case of such an internal + // redirect. + nsCOMPtr loadInfo = mChannel->GetLoadInfo(); + bool upgradeInsecureRequests = loadInfo ? loadInfo->GetUpgradeInsecureRequests() + : false; + if (!upgradeInsecureRequests) { + mHadInsecureRedirect = true; + } } // Update the current URI. diff --git a/image/imgRequest.h b/image/imgRequest.h index 5361934f79..01cce77e21 100644 --- a/image/imgRequest.h +++ b/image/imgRequest.h @@ -44,10 +44,10 @@ class ProgressTracker; struct NewPartResult; class imgRequest final : public nsIStreamListener, - public nsIThreadRetargetableStreamListener, - public nsIChannelEventSink, - public nsIInterfaceRequestor, - public nsIAsyncVerifyRedirectCallback + public nsIThreadRetargetableStreamListener, + public nsIChannelEventSink, + public nsIInterfaceRequestor, + public nsIAsyncVerifyRedirectCallback { typedef mozilla::image::Image Image; typedef mozilla::image::ImageCacheKey ImageCacheKey; @@ -118,7 +118,7 @@ public: // Returns whether we went through an insecure (non-HTTPS) redirect at some // point during loading. This does not consider the current URI. - bool HadInsecureRedirect() const { return mHadInsecureRedirect; } + bool HadInsecureRedirect() const; // The CORS mode for which we loaded this image. int32_t GetCORSMode() const { return mCORSMode; } diff --git a/image/imgRequestProxy.h b/image/imgRequestProxy.h index 84681f37ee..f63cafb3f5 100644 --- a/image/imgRequestProxy.h +++ b/image/imgRequestProxy.h @@ -203,7 +203,10 @@ private: // mListener is only promised to be a weak ref (see imgILoader.idl), // but we actually keep a strong ref to it until we've seen our // first OnStopRequest. - imgINotificationObserver* mListener; + imgINotificationObserver* MOZ_UNSAFE_REF("Observers must call Cancel() or " + "CancelAndForgetObserver() before " + "they are destroyed") mListener; + nsCOMPtr mLoadGroup; nsLoadFlags mLoadFlags; diff --git a/image/moz.build b/image/moz.build index 093276e66c..7d92a204c3 100644 --- a/image/moz.build +++ b/image/moz.build @@ -19,7 +19,6 @@ MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini'] XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini'] - XPIDL_SOURCES += [ 'imgICache.idl', 'imgIContainer.idl', @@ -36,7 +35,6 @@ XPIDL_SOURCES += [ XPIDL_MODULE = 'imglib2' - EXPORTS += [ 'ImageCacheKey.h', 'ImageLogging.h', diff --git a/image/test/mochitest/bug1180105-waiter.sjs b/image/test/mochitest/bug1180105-waiter.sjs new file mode 100644 index 0000000000..4e86ae2879 --- /dev/null +++ b/image/test/mochitest/bug1180105-waiter.sjs @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var timer = Components.classes["@mozilla.org/timer;1"]; +var waitTimer = timer.createInstance(Components.interfaces.nsITimer); + +function handleRequest(request, response) { + response.setHeader("Content-Type", "text/html", false); + response.setHeader("Cache-Control", "no-cache", false); + response.setStatusLine(request.httpVersion, 200, "OK"); + response.processAsync(); + waitForFinish(response); +} + +function waitForFinish(response) { + if (getSharedState("all-parts-done") === "1") { + response.write("done"); + response.finish(); + } else { + waitTimer.initWithCallback(function() {waitForFinish(response);}, 10, + Components.interfaces.nsITimer.TYPE_ONE_SHOT); + } +} diff --git a/image/test/mochitest/bug1180105.sjs b/image/test/mochitest/bug1180105.sjs new file mode 100644 index 0000000000..e138e548ee --- /dev/null +++ b/image/test/mochitest/bug1180105.sjs @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var counter = 100; +var timer = Components.classes["@mozilla.org/timer;1"]; +var partTimer = timer.createInstance(Components.interfaces.nsITimer); + +function getFileAsInputStream(aFilename) { + var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("CurWorkD", Components.interfaces.nsIFile); + + file.append("tests"); + file.append("image"); + file.append("test"); + file.append("mochitest"); + file.append(aFilename); + + var fileStream = Components.classes['@mozilla.org/network/file-input-stream;1'] + .createInstance(Components.interfaces.nsIFileInputStream); + fileStream.init(file, 1, 0, false); + return fileStream; +} + +function handleRequest(request, response) +{ + response.setHeader("Content-Type", + "multipart/x-mixed-replace;boundary=BOUNDARYOMG", false); + response.setHeader("Cache-Control", "no-cache", false); + response.setStatusLine(request.httpVersion, 200, "OK"); + // We're sending parts off in a delayed fashion, to let the tests occur. + response.processAsync(); + response.write("--BOUNDARYOMG\r\n"); + sendParts(response); +} + +function sendParts(response) { + if (counter-- == 0) { + sendClose(response); + setSharedState("all-parts-done", "1"); + return; + } + sendNextPart(response); + partTimer.initWithCallback(function() {sendParts(response);}, 1, + Components.interfaces.nsITimer.TYPE_ONE_SHOT); +} + +function sendClose(response) { + response.write("--BOUNDARYOMG--\r\n"); + response.finish(); +} + +function sendNextPart(response) { + var nextPartHead = "Content-Type: image/jpeg\r\n\r\n"; + var inputStream = getFileAsInputStream("damon.jpg"); + response.bodyOutputStream.write(nextPartHead, nextPartHead.length); + response.bodyOutputStream.writeFrom(inputStream, inputStream.available()); + inputStream.close(); + // Toss in the boundary, so the browser can know this part is complete + response.write("--BOUNDARYOMG\r\n"); +} + diff --git a/image/test/mochitest/mochitest.ini b/image/test/mochitest/mochitest.ini index aab6f2ce2c..3345fd6a3c 100644 --- a/image/test/mochitest/mochitest.ini +++ b/image/test/mochitest/mochitest.ini @@ -30,6 +30,8 @@ support-files = bug89419.sjs bug900200.png bug900200-ref.png + bug1180105.sjs + bug1180105-waiter.sjs clear.gif clear.png clear2.gif @@ -86,6 +88,7 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only skip-if = (toolkit == 'android' && processor == 'x86') #x86 only [test_bug89419-2.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only +[test_bug1180105.html] [test_animation_operators.html] [test_drawDiscardedImage.html] skip-if = toolkit == "gonk" #Bug 997034 - canvas.toDataURL() often causes lost connection to device. diff --git a/image/test/mochitest/test_bug1180105.html b/image/test/mochitest/test_bug1180105.html new file mode 100644 index 0000000000..1691b621c2 --- /dev/null +++ b/image/test/mochitest/test_bug1180105.html @@ -0,0 +1,46 @@ + + + + + Test for Bug 1180105 + + + + + +Mozilla Bug 1180105 +

+
+
+
+
> + +
+ + diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp index 95b188d272..ed4dffee4b 100644 --- a/layout/svg/nsSVGEffects.cpp +++ b/layout/svg/nsSVGEffects.cpp @@ -21,9 +21,6 @@ using namespace mozilla; using namespace mozilla::dom; -// nsSVGRenderingObserver impl -NS_IMPL_ISUPPORTS(nsSVGRenderingObserver, nsIMutationObserver) - void nsSVGRenderingObserver::StartListening() { @@ -220,6 +217,8 @@ nsSVGFrameReferenceFromProperty::Get() return mFrame; } +NS_IMPL_ISUPPORTS(nsSVGRenderingObserverProperty, nsIMutationObserver) + void nsSVGRenderingObserverProperty::DoUpdate() { diff --git a/layout/svg/nsSVGEffects.h b/layout/svg/nsSVGEffects.h index 8ebfcec66e..08d81da100 100644 --- a/layout/svg/nsSVGEffects.h +++ b/layout/svg/nsSVGEffects.h @@ -55,9 +55,6 @@ public: : mInObserverList(false) {} - // nsISupports - NS_DECL_ISUPPORTS - // nsIMutationObserver NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED @@ -174,6 +171,8 @@ private: class nsSVGRenderingObserverProperty : public nsSVGIDRenderingObserver { public: + NS_DECL_ISUPPORTS + nsSVGRenderingObserverProperty(nsIURI* aURI, nsIFrame *aFrame, bool aReferenceImage) : nsSVGIDRenderingObserver(aURI, aFrame->GetContent(), aReferenceImage) @@ -181,6 +180,8 @@ public: {} protected: + virtual ~nsSVGRenderingObserverProperty() {} + virtual void DoUpdate() override; nsSVGFrameReferenceFromProperty mFrameReference; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 0f70034197..4d0c5774c8 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -698,10 +698,10 @@ pref("gfx.canvas.azure.backends", "direct2d1.1,direct2d,skia,cairo"); pref("gfx.content.azure.backends", "direct2d1.1,direct2d,cairo"); #else #ifdef XP_MACOSX +pref("gfx.content.azure.backends", "cg"); pref("gfx.canvas.azure.backends", "skia,cg"); // Accelerated cg canvas where available (10.7+) -pref("gfx.canvas.azure.accelerated", true); -pref("gfx.content.azure.backends", "cg"); +pref("gfx.canvas.azure.accelerated", false); #else pref("gfx.canvas.azure.backends", "skia,cairo"); pref("gfx.content.azure.backends", "cairo"); diff --git a/xpcom/glue/nsISupportsImpl.h b/xpcom/glue/nsISupportsImpl.h index 6528a57764..51574d5495 100644 --- a/xpcom/glue/nsISupportsImpl.h +++ b/xpcom/glue/nsISupportsImpl.h @@ -1014,11 +1014,6 @@ NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \ MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \ NS_INTERFACE_TABLE_END -#define NS_IMPL_QUERY_INTERFACE_INHERITED0(aClass, aSuper) \ - NS_INTERFACE_TABLE_HEAD(aClass) \ - NS_INTERFACE_TABLE_INHERITED0(aClass) \ - NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) - #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...) \ NS_INTERFACE_TABLE_HEAD(aClass) \ NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__) \ @@ -1043,7 +1038,8 @@ NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \ NS_IMPL_QUERY_INTERFACE(aClass, __VA_ARGS__) #define NS_IMPL_ISUPPORTS_INHERITED0(aClass, aSuper) \ - NS_IMPL_QUERY_INTERFACE_INHERITED0(aClass, aSuper) \ + NS_INTERFACE_TABLE_HEAD(aClass) \ + NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) \ NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \ NS_IMPL_RELEASE_INHERITED(aClass, aSuper) \