From fc8179478c488829bce43324157633671d597e7a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 3 Jan 2018 21:03:27 -0500 Subject: [PATCH 01/28] Bug 1423492 part 1. Stop overring UnsetAttr in SVGAnimationElement. r=bytesized MozReview-Commit-ID: Ih8QmVkoOFZ --- dom/svg/SVGAnimationElement.cpp | 26 ++++++++------------------ dom/svg/SVGAnimationElement.h | 3 --- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/dom/svg/SVGAnimationElement.cpp b/dom/svg/SVGAnimationElement.cpp index d7db9f1bae86..6fcf5dc31985 100644 --- a/dom/svg/SVGAnimationElement.cpp +++ b/dom/svg/SVGAnimationElement.cpp @@ -291,6 +291,14 @@ SVGAnimationElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, nsIPrincipal* aSubjectPrincipal, bool aNotify) { + if (!aValue && aNamespaceID == kNameSpaceID_None) { + // Attribute is being removed. + if (AnimationFunction().UnsetAttr(aName) || + mTimedElement.UnsetAttr(aName)) { + AnimationNeedsResample(); + } + } + nsresult rv = SVGAnimationElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify); @@ -339,24 +347,6 @@ SVGAnimationElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, return rv; } -nsresult -SVGAnimationElement::UnsetAttr(int32_t aNamespaceID, - nsAtom* aAttribute, bool aNotify) -{ - nsresult rv = SVGAnimationElementBase::UnsetAttr(aNamespaceID, aAttribute, - aNotify); - NS_ENSURE_SUCCESS(rv,rv); - - if (aNamespaceID == kNameSpaceID_None) { - if (AnimationFunction().UnsetAttr(aAttribute) || - mTimedElement.UnsetAttr(aAttribute)) { - AnimationNeedsResample(); - } - } - - return NS_OK; -} - bool SVGAnimationElement::IsNodeOfType(uint32_t aFlags) const { diff --git a/dom/svg/SVGAnimationElement.h b/dom/svg/SVGAnimationElement.h index 1a1405b56531..e90ca783d143 100644 --- a/dom/svg/SVGAnimationElement.h +++ b/dom/svg/SVGAnimationElement.h @@ -48,9 +48,6 @@ public: bool aCompileEventHandlers) override; virtual void UnbindFromTree(bool aDeep, bool aNullParent) override; - virtual nsresult UnsetAttr(int32_t aNamespaceID, nsAtom* aAttribute, - bool aNotify) override; - virtual bool IsNodeOfType(uint32_t aFlags) const override; // Element specializations From 95e7db08f703310ef3d3af5ace880ede68bd427e Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 3 Jan 2018 21:03:29 -0500 Subject: [PATCH 02/28] Bug 1423492 part 2. Stop overring UnsetAttr in SVGMPathElement. r=bytesized MozReview-Commit-ID: JdjEuESAsD9 --- dom/svg/SVGMPathElement.cpp | 25 ++++++++++++++----------- dom/svg/SVGMPathElement.h | 7 +++++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/dom/svg/SVGMPathElement.cpp b/dom/svg/SVGMPathElement.cpp index 134f4fda453b..9ce89052a9b2 100644 --- a/dom/svg/SVGMPathElement.cpp +++ b/dom/svg/SVGMPathElement.cpp @@ -145,14 +145,14 @@ SVGMPathElement::ParseAttribute(int32_t aNamespaceID, } nsresult -SVGMPathElement::UnsetAttr(int32_t aNamespaceID, - nsAtom* aAttribute, bool aNotify) +SVGMPathElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, + const nsAttrValue* aValue, + const nsAttrValue* aOldValue, + nsIPrincipal* aMaybeScriptedPrincipal, + bool aNotify) { - nsresult rv = SVGMPathElementBase::UnsetAttr(aNamespaceID, aAttribute, - aNotify); - NS_ENSURE_SUCCESS(rv, rv); - - if (aAttribute == nsGkAtoms::href) { + if (!aValue && aName == nsGkAtoms::href) { + // href attr being removed. if (aNamespaceID == kNameSpaceID_None) { UnlinkHrefTarget(true); @@ -163,13 +163,16 @@ SVGMPathElement::UnsetAttr(int32_t aNamespaceID, if (xlinkHref) { UpdateHrefTarget(GetParent(), xlinkHref->GetStringValue()); } - } else if (!HasAttr(kNameSpaceID_None, nsGkAtoms::href)) { + } else if (aNamespaceID == kNameSpaceID_XLink && + !HasAttr(kNameSpaceID_None, nsGkAtoms::href)) { UnlinkHrefTarget(true); - } // else: we unset xlink:href, but we still have href attribute, so keep - // the target linking to href. + } // else: we unset some random-namespace href attribute, or unset xlink:href + // but still have href attribute, so keep the target linking to href. } - return NS_OK; + return SVGMPathElementBase::AfterSetAttr(aNamespaceID, aName, + aValue, aOldValue, + aMaybeScriptedPrincipal, aNotify); } //---------------------------------------------------------------------- diff --git a/dom/svg/SVGMPathElement.h b/dom/svg/SVGMPathElement.h index 2e1de868c17b..f98b11282a17 100644 --- a/dom/svg/SVGMPathElement.h +++ b/dom/svg/SVGMPathElement.h @@ -49,14 +49,17 @@ public: bool aCompileEventHandlers) override; virtual void UnbindFromTree(bool aDeep, bool aNullParent) override; - virtual nsresult UnsetAttr(int32_t aNamespaceID, nsAtom* aAttribute, - bool aNotify) override; // Element specializations virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, const nsAString& aValue, nsIPrincipal* aMaybeScriptedPrincipal, nsAttrValue& aResult) override; + virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, + const nsAttrValue* aValue, + const nsAttrValue* aOldValue, + nsIPrincipal* aMaybeScriptedPrincipal, + bool aNotify) override; // Public helper method: If our xlink:href attribute links to a // element, this method returns a pointer to that element. Otherwise, From 834c47ec08108e972a6b669d9e661abe8354783d Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 3 Jan 2018 21:03:45 -0500 Subject: [PATCH 03/28] Bug 1423492 part 3. Stop overring UnsetAttr in SVGMarkerElement. r=bytesized,qdot This changes behavior some, by moving the code involved from "before we remove the attribute" to AfterSetAttr. But I think it should be OK, and SVG elements can't sanely implement BeforeSetAttr right now... MozReview-Commit-ID: KQGIDQOMGne --- dom/svg/SVGMarkerElement.cpp | 19 ++++++++++++------- dom/svg/SVGMarkerElement.h | 7 +++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/dom/svg/SVGMarkerElement.cpp b/dom/svg/SVGMarkerElement.cpp index 7abc0f795017..ead1344a2268 100644 --- a/dom/svg/SVGMarkerElement.cpp +++ b/dom/svg/SVGMarkerElement.cpp @@ -237,16 +237,21 @@ SVGMarkerElement::ParseAttribute(int32_t aNameSpaceID, nsAtom* aName, } nsresult -SVGMarkerElement::UnsetAttr(int32_t aNamespaceID, nsAtom* aName, - bool aNotify) +SVGMarkerElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, + const nsAttrValue* aValue, + const nsAttrValue* aOldValue, + nsIPrincipal* aMaybeScriptedPrincipal, + bool aNotify) { - if (aNamespaceID == kNameSpaceID_None) { - if (aName == nsGkAtoms::orient) { - mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE); - } + if (!aValue && aNamespaceID == kNameSpaceID_None && + aName == nsGkAtoms::orient) { + mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE); } - return nsSVGElement::UnsetAttr(aNamespaceID, aName, aNotify); + return SVGMarkerElementBase::AfterSetAttr(aNamespaceID, aName, + aValue, aOldValue, + aMaybeScriptedPrincipal, + aNotify); } //---------------------------------------------------------------------- diff --git a/dom/svg/SVGMarkerElement.h b/dom/svg/SVGMarkerElement.h index c0a0a4a24473..26e068a90789 100644 --- a/dom/svg/SVGMarkerElement.h +++ b/dom/svg/SVGMarkerElement.h @@ -115,8 +115,11 @@ public: // nsIContent interface NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* name) const override; - virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute, - bool aNotify) override; + virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, + const nsAttrValue* aValue, + const nsAttrValue* aOldValue, + nsIPrincipal* aMaybeScriptedPrincipal, + bool aNotify) override; // nsSVGSVGElement methods: virtual bool HasValidDimensions() const override; From 9874643dc6b87d44ec8ebf26eb1829f4d8e9d9e3 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 3 Jan 2018 21:03:50 -0500 Subject: [PATCH 04/28] Bug 1423492 part 4. Stop overring UnsetAttr in SVGElement. r=bytesized There are now no more overrides of UnsetAttr, so it can stop being virtual. MozReview-Commit-ID: 4QzAKCkRfgs --- dom/base/Element.h | 4 +--- dom/svg/nsSVGElement.cpp | 11 +++++++---- dom/svg/nsSVGElement.h | 10 +--------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/dom/base/Element.h b/dom/base/Element.h index 542d2c8b1423..9168fd219840 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -927,9 +927,7 @@ public: * @param aNotify specifies whether or not the document should be * notified of the attribute change */ - virtual nsresult UnsetAttr(int32_t aNameSpaceID, - nsAtom* aAttribute, - bool aNotify); + nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute, bool aNotify); /** * Get the namespace / name / prefix of a given attribute. diff --git a/dom/svg/nsSVGElement.cpp b/dom/svg/nsSVGElement.cpp index 19aae79b9db4..aa1d342ffcee 100644 --- a/dom/svg/nsSVGElement.cpp +++ b/dom/svg/nsSVGElement.cpp @@ -895,11 +895,14 @@ nsSVGElement::UnsetAttrInternal(int32_t aNamespaceID, nsAtom* aName, } nsresult -nsSVGElement::UnsetAttr(int32_t aNamespaceID, nsAtom* aName, - bool aNotify) +nsSVGElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName, + const nsAttrValueOrString* aValue, + bool aNotify) { - UnsetAttrInternal(aNamespaceID, aName, aNotify); - return nsSVGElementBase::UnsetAttr(aNamespaceID, aName, aNotify); + if (!aValue) { + UnsetAttrInternal(aNamespaceID, aName, aNotify); + } + return nsSVGElementBase::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify); } nsChangeHint diff --git a/dom/svg/nsSVGElement.h b/dom/svg/nsSVGElement.h index 16478314c977..205ee4fafd35 100644 --- a/dom/svg/nsSVGElement.h +++ b/dom/svg/nsSVGElement.h @@ -105,9 +105,6 @@ public: nsIContent* aBindingParent, bool aCompileEventHandlers) override; - virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute, - bool aNotify) override; - virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute, int32_t aModType) const override; @@ -336,7 +333,6 @@ public: protected: virtual JSObject* WrapNode(JSContext *cx, JS::Handle aGivenProto) override; -#ifdef DEBUG // We define BeforeSetAttr here and mark it final to ensure it is NOT used // by SVG elements. // This is because we're not currently passing the correct value for aValue to @@ -344,11 +340,7 @@ protected: // See the comment in nsSVGElement::WillChangeValue. virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString* aValue, - bool aNotify) override final - { - return nsSVGElementBase::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify); - } -#endif // DEBUG + bool aNotify) override final; virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, const nsAttrValue* aValue, const nsAttrValue* aOldValue, From f007b19e6f31e60ee9152360e2dbd7dd6fb28be8 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Thu, 4 Jan 2018 14:11:00 -0500 Subject: [PATCH 05/28] Bug 1426123: add assertion and comments that SelectSendResolution() can never result in divide-by-zero r=jib --- media/webrtc/signaling/src/media-conduit/VideoConduit.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp index 9cad4f12774f..17f05a49169a 100644 --- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp +++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp @@ -1962,9 +1962,13 @@ WebrtcVideoConduit::SendVideoFrame(const webrtc::VideoFrame& frame) // Waiting for it to finish return kMediaConduitNoError; } + // mLastWidth/Height starts at 0, so we'll never call SelectSendResolution with a 0 size. + // We in some cases set them back to 0 to force SelectSendResolution to be called again. if (frame.width() != mLastWidth || frame.height() != mLastHeight) { CSFLogVerbose(LOGTAG, "%s: call SelectSendResolution with %ux%u", __FUNCTION__, frame.width(), frame.height()); + MOZ_ASSERT(frame.width() != 0 && frame.height() != 0); + // Note coverity will flag this since it thinks they can be 0 if (SelectSendResolution(frame.width(), frame.height(), &frame)) { // SelectSendResolution took ownership of the data in i420_frame. // Submit the frame after reconfig is done From bc65f35f15fc3fe51cde7701e65c01d2a9aab61f Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Wed, 3 Jan 2018 16:55:01 -0600 Subject: [PATCH 06/28] Only queue a ContentClient buffer state if it has operations (bug 1427089, r=dvander) --HG-- extra : rebase_source : 200e59db7a140b0981b1d07ebf6d8ee241336322 --- gfx/layers/PaintThread.h | 5 +++++ gfx/layers/client/ClientPaintedLayer.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gfx/layers/PaintThread.h b/gfx/layers/PaintThread.h index c86a83ea4f30..8270da8bb9b6 100644 --- a/gfx/layers/PaintThread.h +++ b/gfx/layers/PaintThread.h @@ -116,6 +116,11 @@ public: */ bool PrepareBuffer(); + bool HasOperations() const + { + return mBufferFinalize || mBufferUnrotate || mBufferInitialize; + } + template void ForEachTextureClient(F aClosure) const { diff --git a/gfx/layers/client/ClientPaintedLayer.cpp b/gfx/layers/client/ClientPaintedLayer.cpp index 8c802752f2dc..36ff76c1d283 100644 --- a/gfx/layers/client/ClientPaintedLayer.cpp +++ b/gfx/layers/client/ClientPaintedLayer.cpp @@ -228,7 +228,7 @@ ClientPaintedLayer::PaintOffMainThread() uint32_t flags = GetPaintFlags(); PaintState state = mContentClient->BeginPaint(this, flags | ContentClient::PAINT_ASYNC); - if (state.mBufferState) { + if (state.mBufferState && state.mBufferState->HasOperations()) { PaintThread::Get()->PrepareBuffer(state.mBufferState); asyncPaints.Queue(); } From 51163a3c5277ef33df3a32745e82041dd1252cd8 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Wed, 3 Jan 2018 16:56:25 -0600 Subject: [PATCH 07/28] Wait for a previous empty transaction to complete before doing another empty transaction (bug 1427089, r=dvander) --HG-- extra : rebase_source : 26276bc5c2073c86f3c57296ed7b1b5126dc4c18 --- gfx/layers/client/ClientLayerManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 2049e67614b2..830125207afc 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -450,6 +450,12 @@ ClientLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) return false; } + if (mTransactionIncomplete) { + // If the previous transaction was incomplete then we may have buffer operations + // running on the paint thread that haven't finished yet + GetCompositorBridgeChild()->FlushAsyncPaints(); + } + if (!EndTransactionInternal(nullptr, nullptr, aFlags)) { // Return without calling ForwardTransaction. This leaves the // ShadowLayerForwarder transaction open; the following From 46e3052bc3476e1c5d422bcc8359a7607d5a0ced Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Thu, 4 Jan 2018 14:36:07 -0500 Subject: [PATCH 08/28] Bug 1423173 - Check for shadowing indexed properties when adding elements. r=jandem --- js/src/jit-test/tests/arrays/bug1423173.js | 13 +++++++++++++ js/src/jit/CacheIR.cpp | 3 +++ 2 files changed, 16 insertions(+) create mode 100644 js/src/jit-test/tests/arrays/bug1423173.js diff --git a/js/src/jit-test/tests/arrays/bug1423173.js b/js/src/jit-test/tests/arrays/bug1423173.js new file mode 100644 index 000000000000..38e584ce3655 --- /dev/null +++ b/js/src/jit-test/tests/arrays/bug1423173.js @@ -0,0 +1,13 @@ +// |jit-test| --baseline-eager +Array.prototype.push(1); +Object.freeze([].__proto__); +var x = []; +var c = 0; +for (var j = 0; j < 5; ++j) { + try { + x.push(function() {}); + } catch (e) { + c++; + } +} +assertEq(c, j); diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 507788a7c182..fa5fc6bc6f91 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -3406,6 +3406,9 @@ CanAttachAddElement(JSObject* obj, bool isInit) if (!proto->isNative()) return false; + if (proto->as().denseElementsAreFrozen()) + return false; + obj = proto; } while (true); From bd8e3761b94467834426834a29590aa627ebd46f Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 4 Jan 2018 20:43:55 +0100 Subject: [PATCH 09/28] Bug 1343980 - [css-ui] Skip anonymous boxes (rather than all pseudos) when looking for the 'overflow' style frame. r=bz --- layout/generic/TextOverflow.cpp | 2 +- testing/web-platform/meta/MANIFEST.json | 50 +++++++++++++++++++ .../css/css-ui/text-overflow-024-ref.html | 26 ++++++++++ .../tests/css/css-ui/text-overflow-024.html | 31 ++++++++++++ .../css/css-ui/text-overflow-025-ref.html | 24 +++++++++ .../tests/css/css-ui/text-overflow-025.html | 33 ++++++++++++ 6 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 testing/web-platform/tests/css/css-ui/text-overflow-024-ref.html create mode 100644 testing/web-platform/tests/css/css-ui/text-overflow-024.html create mode 100644 testing/web-platform/tests/css/css-ui/text-overflow-025-ref.html create mode 100644 testing/web-platform/tests/css/css-ui/text-overflow-025.html diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp index ee20c23f1294..75c9b30569c6 100644 --- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -102,7 +102,7 @@ IsInlineAxisOverflowVisible(nsIFrame* aFrame) "expected a block frame"); nsIFrame* f = aFrame; - while (f && f->StyleContext()->GetPseudo() && !f->IsScrollFrame()) { + while (f && f->StyleContext()->IsAnonBox() && !f->IsScrollFrame()) { f = f->GetParent(); } if (!f) { diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 5de1d8785ea7..3540c54efc7b 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -143597,6 +143597,30 @@ {} ] ], + "css/css-ui/text-overflow-024.html": [ + [ + "/css/css-ui/text-overflow-024.html", + [ + [ + "/css/css-ui/text-overflow-024-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-ui/text-overflow-025.html": [ + [ + "/css/css-ui/text-overflow-025.html", + [ + [ + "/css/css-ui/text-overflow-025-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-values/attr-color-invalid-cast.html": [ [ "/css/css-values/attr-color-invalid-cast.html", @@ -250142,6 +250166,16 @@ {} ] ], + "css/css-ui/text-overflow-024-ref.html": [ + [ + {} + ] + ], + "css/css-ui/text-overflow-025-ref.html": [ + [ + {} + ] + ], "css/css-ui/text-overflow-ref.html": [ [ {} @@ -504502,6 +504536,22 @@ "4fd38a517e41851216d12db8c6b732d96f76e325", "testharness" ], + "css/css-ui/text-overflow-024-ref.html": [ + "458105b3deb397f37c1664d373c86e5ea869a414", + "support" + ], + "css/css-ui/text-overflow-024.html": [ + "bedd5c72400a578e09387dd5dd8afaf63c91c76b", + "reftest" + ], + "css/css-ui/text-overflow-025-ref.html": [ + "907c7d52cc9b872253aa544d3041329e13dc7f5b", + "support" + ], + "css/css-ui/text-overflow-025.html": [ + "b03fc53093345268573b21cccc82d841f66c192f", + "reftest" + ], "css/css-ui/text-overflow-ref.html": [ "db55b0b95a7406e9c4f00081b3e2cbe6b07363f7", "support" diff --git a/testing/web-platform/tests/css/css-ui/text-overflow-024-ref.html b/testing/web-platform/tests/css/css-ui/text-overflow-024-ref.html new file mode 100644 index 000000000000..2e9b8301f469 --- /dev/null +++ b/testing/web-platform/tests/css/css-ui/text-overflow-024-ref.html @@ -0,0 +1,26 @@ + + + + + Reference: text-overflow on tr::before with overflow:hidden + + + +PASS if there is an ellipsis at the end of the text below. + + +
Some long text here that overflows and whatnot.
+ + + diff --git a/testing/web-platform/tests/css/css-ui/text-overflow-024.html b/testing/web-platform/tests/css/css-ui/text-overflow-024.html new file mode 100644 index 000000000000..0ca5b428cb4d --- /dev/null +++ b/testing/web-platform/tests/css/css-ui/text-overflow-024.html @@ -0,0 +1,31 @@ + + + + + Test: text-overflow on tr::before with overflow:hidden + + + + + + +PASS if there is an ellipsis at the end of the text below. + + +
+ + + diff --git a/testing/web-platform/tests/css/css-ui/text-overflow-025-ref.html b/testing/web-platform/tests/css/css-ui/text-overflow-025-ref.html new file mode 100644 index 000000000000..c8acd479603a --- /dev/null +++ b/testing/web-platform/tests/css/css-ui/text-overflow-025-ref.html @@ -0,0 +1,24 @@ + + + + + Reference: text-overflow on tr::before without overflow:hidden + + + +PASS if there is no ellipsis below. + + +
Some long text here that overflows and whatnot.
+ + + diff --git a/testing/web-platform/tests/css/css-ui/text-overflow-025.html b/testing/web-platform/tests/css/css-ui/text-overflow-025.html new file mode 100644 index 000000000000..3e0fce0afb0e --- /dev/null +++ b/testing/web-platform/tests/css/css-ui/text-overflow-025.html @@ -0,0 +1,33 @@ + + + + + Test: text-overflow on tr::before without overflow:hidden + + + + + + +PASS if there is no ellipsis below. + + +
+ + + From 49526eeeb69fbd2eec7de7444d0e80dab75629c5 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 4 Jan 2018 20:43:55 +0100 Subject: [PATCH 10/28] Bug 1403986 part 1 - [css-ui] Treat text frames with only trimmable space as empty for 'text-overflow' purposes. r=jfkthame --- layout/generic/TextOverflow.cpp | 18 ++++++++++++++---- layout/generic/nsTextFrame.cpp | 15 +++++++++++++++ layout/generic/nsTextFrame.h | 9 +++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp index 75c9b30569c6..6917366d27e5 100644 --- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -452,6 +452,8 @@ TextOverflow::AnalyzeMarkerEdges(nsIFrame* aFrame, bool* aFoundVisibleTextOrAtomic, InnerClipEdges* aClippedMarkerEdges) { + MOZ_ASSERT(aFrameType == LayoutFrameType::Text || + IsAtomicElement(aFrame, aFrameType)); LogicalRect borderRect(mBlockWM, nsRect(aFrame->GetOffsetTo(mBlock), aFrame->GetSize()), @@ -481,11 +483,12 @@ TextOverflow::AnalyzeMarkerEdges(nsIFrame* aFrame, if ((istartOverlap > 0 && insideIStartEdge) || (iendOverlap > 0 && insideIEndEdge)) { if (aFrameType == LayoutFrameType::Text) { - if (aInsideMarkersArea.IStart(mBlockWM) < - aInsideMarkersArea.IEnd(mBlockWM)) { + auto textFrame = static_cast(aFrame); + if ((aInsideMarkersArea.IStart(mBlockWM) < + aInsideMarkersArea.IEnd(mBlockWM)) && + textFrame->HasNonSuppressedText()) { // a clipped text frame and there is some room between the markers nscoord snappedIStart, snappedIEnd; - auto textFrame = static_cast(aFrame); bool isFullyClipped = mBlockWM.IsBidiLTR() ? IsFullyClipped(textFrame, istartOverlap, iendOverlap, &snappedIStart, &snappedIEnd) : @@ -515,7 +518,14 @@ TextOverflow::AnalyzeMarkerEdges(nsIFrame* aFrame, } else { // frame is inside aAlignmentEdges->Accumulate(mBlockWM, borderRect); - *aFoundVisibleTextOrAtomic = true; + if (aFrameType == LayoutFrameType::Text) { + auto textFrame = static_cast(aFrame); + if (textFrame->HasNonSuppressedText()) { + *aFoundVisibleTextOrAtomic = true; + } + } else { + *aFoundVisibleTextOrAtomic = true; + } } } diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 70ee0d7ccd34..49dc7a54d44c 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -10415,3 +10415,18 @@ nsTextFrame::CountGraphemeClusters() const frag->AppendTo(content, GetContentOffset(), GetContentLength()); return unicode::CountGraphemeClusters(content.Data(), content.Length()); } + +bool +nsTextFrame::HasNonSuppressedText() +{ + if (HasAnyStateBits(TEXT_ISNOT_ONLY_WHITESPACE)) { + return true; + } + + if (!GetTextRun(nsTextFrame::eInflated)) { + return false; + } + + TrimmedOffsets offsets = GetTrimmedOffsets(mContent->GetText(), false); + return offsets.mLength != 0; +} diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 54be6c6bad60..e93b3cfae556 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -362,6 +362,15 @@ public: nscoord* aSnappedStartEdge, nscoord* aSnappedEndEdge); + /** + * Return true if this box has some text to display. + * It returns false if at least one of these conditions are met: + * a. the frame hasn't been reflowed yet + * b. GetContentLength() == 0 + * c. it contains only non-significant white-space + */ + bool HasNonSuppressedText(); + /** * Object with various callbacks for PaintText() to invoke for different parts * of the frame's text rendering, when we're generating paths rather than From 89df57b846178d98e001c6ed2cf4c5bad882b425 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 4 Jan 2018 20:43:57 +0100 Subject: [PATCH 11/28] Bug 1403986 part 2 - [css-ui] Add a 'text-overflow' web platform test. --- testing/web-platform/meta/MANIFEST.json | 33 +++++++-- .../css/css-ui/text-overflow-026-ref.html | 62 +++++++++++++++++ .../tests/css/css-ui/text-overflow-026.html | 67 +++++++++++++++++++ 3 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 testing/web-platform/tests/css/css-ui/text-overflow-026-ref.html create mode 100644 testing/web-platform/tests/css/css-ui/text-overflow-026.html diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 3540c54efc7b..4a66b6644f9c 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -143621,6 +143621,18 @@ {} ] ], + "css/css-ui/text-overflow-026.html": [ + [ + "/css/css-ui/text-overflow-026.html", + [ + [ + "/css/css-ui/text-overflow-026-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-values/attr-color-invalid-cast.html": [ [ "/css/css-values/attr-color-invalid-cast.html", @@ -250176,6 +250188,11 @@ {} ] ], + "css/css-ui/text-overflow-026-ref.html": [ + [ + {} + ] + ], "css/css-ui/text-overflow-ref.html": [ [ {} @@ -504537,19 +504554,27 @@ "testharness" ], "css/css-ui/text-overflow-024-ref.html": [ - "458105b3deb397f37c1664d373c86e5ea869a414", + "c43715bf1ea3dd118f7b71479bd5239e01bbb314", "support" ], "css/css-ui/text-overflow-024.html": [ - "bedd5c72400a578e09387dd5dd8afaf63c91c76b", + "7c18a786a3bfc9d1a8e9cc108ae228b979cacb6e", "reftest" ], "css/css-ui/text-overflow-025-ref.html": [ - "907c7d52cc9b872253aa544d3041329e13dc7f5b", + "13056acc82d5e59310d10af30da8e46f73929e5f", "support" ], "css/css-ui/text-overflow-025.html": [ - "b03fc53093345268573b21cccc82d841f66c192f", + "b4a2e0d1b86fd8893421de4335c9b6f36df1fc4d", + "reftest" + ], + "css/css-ui/text-overflow-026-ref.html": [ + "1a7d6d524a217d8fc2252e6434ac1b8fb3d5af2f", + "support" + ], + "css/css-ui/text-overflow-026.html": [ + "34cb2b690321f6f93763de2841ebdf5a9275f515", "reftest" ], "css/css-ui/text-overflow-ref.html": [ diff --git a/testing/web-platform/tests/css/css-ui/text-overflow-026-ref.html b/testing/web-platform/tests/css/css-ui/text-overflow-026-ref.html new file mode 100644 index 000000000000..f2db8c747fa8 --- /dev/null +++ b/testing/web-platform/tests/css/css-ui/text-overflow-026-ref.html @@ -0,0 +1,62 @@ + + + + + Reference: text-overflow with leading white-space + + + + + +
+The test PASS if all of the following are true:
+1. there are no red areas
+2. the first two blocks display "PASS" but no ellipsis
+3. the last three blocks display an ellipsis
+
+ +
+ + PASS PASS PASS PASS PASS +
+ +
+ + + PASS PASS PASS PASS PASS +
+ +
+  … +
+ +
+  … +
+ +
+ a… +
+ + + diff --git a/testing/web-platform/tests/css/css-ui/text-overflow-026.html b/testing/web-platform/tests/css/css-ui/text-overflow-026.html new file mode 100644 index 000000000000..2d1aa57cc892 --- /dev/null +++ b/testing/web-platform/tests/css/css-ui/text-overflow-026.html @@ -0,0 +1,67 @@ + + + + + Test: text-overflow with leading white-space + + + + + + + +
+The test PASS if all of the following are true:
+1. there are no red areas
+2. the first two blocks display "PASS" but no ellipsis
+3. the last three blocks display an ellipsis
+
+ +
+ + PASS PASS PASS PASS PASS +
+ +
+ + + PASS PASS PASS PASS PASS +
+ +
+   + FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL +
+ +
+   + FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL +
+ +
+ a + FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL +
+ + + From 4b4ce8d7203334231d843d693fe13cb15f1f3e9e Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 4 Jan 2018 22:16:37 +0100 Subject: [PATCH 12/28] Bug 1423761 - Make CorrectStyleParentFrame / UpdateStyleOfChildAnonBox deal with abs.pos. anon boxes. r=dholbert For an OOF frame, the parent frame that's associated with our parent style context is the *placeholder's* parent -- not the OOF frame's parent. --- layout/generic/nsFrame.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index cd53730870eb..a66c0fcfb905 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -9843,7 +9843,7 @@ nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent, return parent; } - parent = parent->GetParent(); + parent = parent->GetInFlowParent(); } while (parent); if (aProspectiveParent->StyleContext()->GetPseudo() == @@ -10688,7 +10688,7 @@ nsIFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame, ServoRestyleState& aRestyleState) { #ifdef DEBUG - nsIFrame* parent = aChildFrame->GetParent();; + nsIFrame* parent = aChildFrame->GetInFlowParent(); if (aChildFrame->IsTableFrame()) { parent = parent->GetParent(); } From 54388800fe72485e18bfc027d2d2a62877feba42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Qu=C3=A8ze?= Date: Thu, 4 Jan 2018 22:23:48 +0100 Subject: [PATCH 13/28] Bug 1410072 - browser/base/content/test/performance tests should not modify startupRecorder data in order to pass test-verify, r=johannh. --- browser/base/content/test/performance/browser_startup.js | 2 +- browser/base/content/test/performance/browser_startup_images.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/base/content/test/performance/browser_startup.js b/browser/base/content/test/performance/browser_startup.js index 29b21dff3208..6c3839d0372b 100644 --- a/browser/base/content/test/performance/browser_startup.js +++ b/browser/base/content/test/performance/browser_startup.js @@ -153,7 +153,7 @@ add_task(async function() { let loader = Cc["@mozilla.org/moz/jsloader;1"].getService(Ci.xpcIJSModuleLoader); let componentStacks = new Map(); - let data = startupRecorder.data.code; + let data = Cu.cloneInto(startupRecorder.data.code, {}); // Keep only the file name for components, as the path is an absolute file // URL rather than a resource:// URL like for modules. for (let phase in data) { diff --git a/browser/base/content/test/performance/browser_startup_images.js b/browser/base/content/test/performance/browser_startup_images.js index 5d25c9505b52..a92999b9cb34 100644 --- a/browser/base/content/test/performance/browser_startup_images.js +++ b/browser/base/content/test/performance/browser_startup_images.js @@ -93,7 +93,7 @@ add_task(async function() { let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject; await startupRecorder.done; - let data = startupRecorder.data.images; + let data = Cu.cloneInto(startupRecorder.data.images, {}); let filteredWhitelist = whitelist.filter(el => { return el.platforms.includes(AppConstants.platform); }); From 8b1b458cacb57dcb3e82db031712ebfc4744b7fa Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Thu, 4 Jan 2018 17:35:41 -0500 Subject: [PATCH 14/28] Bug 1428077 Make FinalChannelPrincipalIsValid always defined instead of only for MOZ_DIAGNOSTIC_ASSERT. r=baku --- dom/workers/WorkerPrivate.cpp | 4 ++-- dom/workers/WorkerPrivate.h | 2 +- dom/workers/Workers.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 872cb4f87a59..a1bfd0adeaa3 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2000,7 +2000,6 @@ WorkerLoadInfo::SetPrincipalFromChannel(nsIChannel* aChannel) return SetPrincipalOnMainThread(principal, loadGroup); } -#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED bool WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel) { @@ -2030,6 +2029,7 @@ WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel) return false; } +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED bool WorkerLoadInfo::PrincipalIsValid() const { @@ -4000,7 +4000,6 @@ WorkerPrivateParent::SetPrincipalFromChannel(nsIChannel* aChannel) return mLoadInfo.SetPrincipalFromChannel(aChannel); } -#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED template bool WorkerPrivateParent::FinalChannelPrincipalIsValid(nsIChannel* aChannel) @@ -4008,6 +4007,7 @@ WorkerPrivateParent::FinalChannelPrincipalIsValid(nsIChannel* aChannel) return mLoadInfo.FinalChannelPrincipalIsValid(aChannel); } +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED template bool WorkerPrivateParent::PrincipalURIMatchesScriptURL() diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index f19b1509f76d..67646b2291cf 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -684,10 +684,10 @@ public: nsresult SetPrincipalFromChannel(nsIChannel* aChannel); -#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED bool FinalChannelPrincipalIsValid(nsIChannel* aChannel); +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED bool PrincipalURIMatchesScriptURL(); #endif diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index 01b860b99291..561dea75be3c 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -286,10 +286,10 @@ struct WorkerLoadInfo nsresult SetPrincipalFromChannel(nsIChannel* aChannel); -#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED bool FinalChannelPrincipalIsValid(nsIChannel* aChannel); +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED bool PrincipalIsValid() const; From 798ca9ae4ee8d68b965d2b30c7ac93ccaef1e4a8 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 21 Dec 2017 18:04:08 +1300 Subject: [PATCH 15/28] bug 1418820 add diagnostic asserts to check for running with incorrect lifecycle state r=padenot MozReview-Commit-ID: HfwBfHoIsTu --HG-- extra : rebase_source : 854ac34687bdcea2faf01d8006f8302ff2139923 --- dom/media/MediaStreamGraph.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index c6d2f39469f7..b54551db36e0 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -1314,6 +1314,11 @@ MediaStreamGraphImpl::UpdateMainThreadState() bool MediaStreamGraphImpl::OneIteration(GraphTime aStateEnd) { + // Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph + // thread, and so the monitor need not be held to check mLifecycleState. + // LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline + // graphs that have not started. + MOZ_DIAGNOSTIC_ASSERT(mLifecycleState <= LIFECYCLE_RUNNING); MOZ_ASSERT(OnGraphThread()); WebCore::DenormalDisabler disabler; @@ -1742,6 +1747,9 @@ MediaStreamGraphImpl::SignalMainThreadCleanup() MOZ_ASSERT(mDriver->OnThread()); MonitorAutoLock lock(mMonitor); + // LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline + // graphs that have not started. + MOZ_DIAGNOSTIC_ASSERT(mLifecycleState <= LIFECYCLE_RUNNING); LOG(LogLevel::Debug, ("MediaStreamGraph %p waiting for main thread cleanup", this)); LifecycleStateRef() = From a848c67de01548cdee57ef5f6c7f8af6e969d581 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 21 Dec 2017 20:08:21 +1300 Subject: [PATCH 16/28] bug 1418820 add diagnostic asserts to check for multiple concurrent drivers r=padenot MozReview-Commit-ID: 5nRELgRkjQY --HG-- extra : rebase_source : cc08e88c88e7997a2808aa6c1f59f8a70cd7f191 --- dom/media/GraphDriver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index 74b54e519cb0..afcc56f4c031 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -49,6 +49,7 @@ void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver, MOZ_ASSERT(!PreviousDriver()); MOZ_ASSERT(aPreviousDriver); + MOZ_DIAGNOSTIC_ASSERT(GraphImpl()->CurrentDriver() == aPreviousDriver); LOG(LogLevel::Debug, ("Setting previous driver: %p (%s)", From 7b2fb44f60198c91c83626d52bf9970278ad1eef Mon Sep 17 00:00:00 2001 From: Kyle Machulis Date: Thu, 4 Jan 2018 12:45:54 -0800 Subject: [PATCH 17/28] Backing out 8fd1d4a79a48 (Bug 952453) due to notification bustage on MacOS MozReview-Commit-ID: BeziRSoUvh2 --- dom/base/Navigator.cpp | 23 ++ dom/base/Navigator.h | 3 + dom/notification/DesktopNotification.cpp | 332 ++++++++++++++++++ dom/notification/DesktopNotification.h | 178 ++++++++++ dom/notification/moz.build | 2 + .../mochitest/general/test_interfaces.js | 4 + .../create_notification.html | 16 + .../desktop-notification/moz.build | 6 + .../notification_common.js | 70 ++++ .../test_basic_notification.html | 50 +++ .../test_basic_notification_click.html | 53 +++ .../test_leak_windowClose.html | 34 ++ .../test_notification_tag.html | 110 ++++++ .../test_system_principal.xul | 85 +++++ dom/webidl/DesktopNotification.webidl | 26 ++ dom/webidl/Navigator.webidl | 6 + dom/webidl/moz.build | 4 + modules/libpref/init/all.js | 3 + widget/cocoa/OSXNotificationCenter.h | 3 + widget/cocoa/OSXNotificationCenter.mm | 75 ++++ 20 files changed, 1083 insertions(+) create mode 100644 dom/notification/DesktopNotification.cpp create mode 100644 dom/notification/DesktopNotification.h create mode 100644 dom/tests/mochitest/notification/desktop-notification/create_notification.html create mode 100644 dom/tests/mochitest/notification/desktop-notification/moz.build create mode 100644 dom/tests/mochitest/notification/desktop-notification/notification_common.js create mode 100644 dom/tests/mochitest/notification/desktop-notification/test_basic_notification.html create mode 100644 dom/tests/mochitest/notification/desktop-notification/test_basic_notification_click.html create mode 100644 dom/tests/mochitest/notification/desktop-notification/test_leak_windowClose.html create mode 100644 dom/tests/mochitest/notification/desktop-notification/test_notification_tag.html create mode 100644 dom/tests/mochitest/notification/desktop-notification/test_system_principal.xul create mode 100644 dom/webidl/DesktopNotification.webidl diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 9e63e708eb1e..cdda6fd67448 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -13,6 +13,7 @@ #include "nsMimeTypeArray.h" #include "mozilla/MemoryReporting.h" #include "mozilla/dom/BodyExtractor.h" +#include "mozilla/dom/DesktopNotification.h" #include "mozilla/dom/FetchBinding.h" #include "mozilla/dom/File.h" #include "nsGeolocation.h" @@ -194,6 +195,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection) @@ -236,6 +238,11 @@ Navigator::Invalidate() mGeolocation = nullptr; } + if (mNotification) { + mNotification->Shutdown(); + mNotification = nullptr; + } + if (mBatteryManager) { mBatteryManager->Shutdown(); mBatteryManager = nullptr; @@ -1309,6 +1316,22 @@ Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints, aInnerWindowID, aCallID); } +DesktopNotificationCenter* +Navigator::GetMozNotification(ErrorResult& aRv) +{ + if (mNotification) { + return mNotification; + } + + if (!mWindow || !mWindow->GetDocShell()) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + mNotification = new DesktopNotificationCenter(mWindow); + return mNotification; +} + //***************************************************************************** // Navigator::nsINavigatorBattery //***************************************************************************** diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 04326a96a3f2..eb31ff7b3699 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -59,6 +59,7 @@ class BatteryManager; class Promise; +class DesktopNotificationCenter; class MozIdleObserver; class Gamepad; class GamepadServiceTest; @@ -177,6 +178,7 @@ public: void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv); void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv); + DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv); already_AddRefed MozTCPSocket(); network::Connection* GetConnection(ErrorResult& aRv); MediaDevices* GetMediaDevices(ErrorResult& aRv); @@ -273,6 +275,7 @@ private: RefPtr mPlugins; RefPtr mPermissions; RefPtr mGeolocation; + RefPtr mNotification; RefPtr mBatteryManager; RefPtr mBatteryPromise; RefPtr mConnection; diff --git a/dom/notification/DesktopNotification.cpp b/dom/notification/DesktopNotification.cpp new file mode 100644 index 000000000000..2ba872398282 --- /dev/null +++ b/dom/notification/DesktopNotification.cpp @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "mozilla/dom/DesktopNotification.h" +#include "mozilla/dom/DesktopNotificationBinding.h" +#include "mozilla/dom/AppNotificationServiceOptionsBinding.h" +#include "mozilla/dom/ToJSValue.h" +#include "mozilla/EventStateManager.h" +#include "nsComponentManagerUtils.h" +#include "nsContentPermissionHelper.h" +#include "nsXULAppAPI.h" +#include "mozilla/dom/PBrowserChild.h" +#include "mozilla/Preferences.h" +#include "nsGlobalWindow.h" +#include "nsIScriptSecurityManager.h" +#include "nsServiceManagerUtils.h" +#include "PermissionMessageUtils.h" +#include "nsILoadContext.h" + +namespace mozilla { +namespace dom { + +/* + * Simple Request + */ +class DesktopNotificationRequest : public nsIContentPermissionRequest + , public Runnable +{ + virtual ~DesktopNotificationRequest() + { + } + + nsCOMPtr mRequester; +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSICONTENTPERMISSIONREQUEST + + explicit DesktopNotificationRequest(DesktopNotification* aNotification) + : Runnable("dom::DesktopNotificationRequest") + , mDesktopNotification(aNotification) + { + mRequester = new nsContentPermissionRequester(mDesktopNotification->GetOwner()); + } + + NS_IMETHOD Run() override + { + nsCOMPtr window = mDesktopNotification->GetOwner(); + nsContentPermissionUtils::AskPermission(this, window); + return NS_OK; + } + + RefPtr mDesktopNotification; +}; + +/* ------------------------------------------------------------------------ */ +/* AlertServiceObserver */ +/* ------------------------------------------------------------------------ */ + +NS_IMPL_ISUPPORTS(AlertServiceObserver, nsIObserver) + +/* ------------------------------------------------------------------------ */ +/* DesktopNotification */ +/* ------------------------------------------------------------------------ */ + +uint32_t DesktopNotification::sCount = 0; + +nsresult +DesktopNotification::PostDesktopNotification() +{ + if (!mObserver) { + mObserver = new AlertServiceObserver(this); + } + + nsCOMPtr alerts = do_GetService("@mozilla.org/alerts-service;1"); + if (!alerts) { + return NS_ERROR_NOT_IMPLEMENTED; + } + + // Generate a unique name (which will also be used as a cookie) because + // the nsIAlertsService will coalesce notifications with the same name. + // In the case of IPC, the parent process will use the cookie to map + // to nsIObservers, thus cookies must be unique to differentiate observers. + nsString uniqueName = NS_LITERAL_STRING("desktop-notification:"); + uniqueName.AppendInt(sCount++); + nsCOMPtr owner = GetOwner(); + if (!owner) { + return NS_ERROR_FAILURE; + } + nsCOMPtr doc = owner->GetDoc(); + nsIPrincipal* principal = doc->NodePrincipal(); + nsCOMPtr loadContext = doc->GetLoadContext(); + bool inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing(); + nsCOMPtr alert = + do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID); + NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE); + nsresult rv = alert->Init(uniqueName, mIconURL, mTitle, + mDescription, + true, + uniqueName, + NS_LITERAL_STRING("auto"), + EmptyString(), + EmptyString(), + principal, + inPrivateBrowsing, + false /* requireInteraction */); + NS_ENSURE_SUCCESS(rv, rv); + return alerts->ShowAlert(alert, mObserver); +} + +DesktopNotification::DesktopNotification(const nsAString & title, + const nsAString & description, + const nsAString & iconURL, + nsPIDOMWindowInner* aWindow, + bool aIsHandlingUserInput, + nsIPrincipal* principal) + : DOMEventTargetHelper(aWindow) + , mTitle(title) + , mDescription(description) + , mIconURL(iconURL) + , mPrincipal(principal) + , mIsHandlingUserInput(aIsHandlingUserInput) + , mAllow(false) + , mShowHasBeenCalled(false) +{ + if (Preferences::GetBool("notification.disabled", false)) { + return; + } + + // If we are in testing mode (running mochitests, for example) + // and we are suppose to allow requests, then just post an allow event. + if (Preferences::GetBool("notification.prompt.testing", false) && + Preferences::GetBool("notification.prompt.testing.allow", true)) { + mAllow = true; + } +} + +void +DesktopNotification::Init() +{ + RefPtr request = new DesktopNotificationRequest(this); + + NS_DispatchToMainThread(request); +} + +DesktopNotification::~DesktopNotification() +{ + if (mObserver) { + mObserver->Disconnect(); + } +} + +void +DesktopNotification::DispatchNotificationEvent(const nsString& aName) +{ + if (NS_FAILED(CheckInnerWindowCorrectness())) { + return; + } + + RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); + // it doesn't bubble, and it isn't cancelable + event->InitEvent(aName, false, false); + event->SetTrusted(true); + bool dummy; + DispatchEvent(event, &dummy); +} + +nsresult +DesktopNotification::SetAllow(bool aAllow) +{ + mAllow = aAllow; + + // if we have called Show() already, lets go ahead and post a notification + if (mShowHasBeenCalled && aAllow) { + return PostDesktopNotification(); + } + + return NS_OK; +} + +void +DesktopNotification::HandleAlertServiceNotification(const char *aTopic) +{ + if (NS_FAILED(CheckInnerWindowCorrectness())) { + return; + } + + if (!strcmp("alertclickcallback", aTopic)) { + DispatchNotificationEvent(NS_LITERAL_STRING("click")); + } else if (!strcmp("alertfinished", aTopic)) { + DispatchNotificationEvent(NS_LITERAL_STRING("close")); + } +} + +void +DesktopNotification::Show(ErrorResult& aRv) +{ + mShowHasBeenCalled = true; + + if (!mAllow) { + return; + } + + aRv = PostDesktopNotification(); +} + +JSObject* +DesktopNotification::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return DesktopNotificationBinding::Wrap(aCx, this, aGivenProto); +} + +/* ------------------------------------------------------------------------ */ +/* DesktopNotificationCenter */ +/* ------------------------------------------------------------------------ */ + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(DesktopNotificationCenter) +NS_IMPL_CYCLE_COLLECTING_ADDREF(DesktopNotificationCenter) +NS_IMPL_CYCLE_COLLECTING_RELEASE(DesktopNotificationCenter) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DesktopNotificationCenter) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +already_AddRefed +DesktopNotificationCenter::CreateNotification(const nsAString& aTitle, + const nsAString& aDescription, + const nsAString& aIconURL) +{ + MOZ_ASSERT(mOwner); + + RefPtr notification = + new DesktopNotification(aTitle, + aDescription, + aIconURL, + mOwner, + EventStateManager::IsHandlingUserInput(), + mPrincipal); + notification->Init(); + return notification.forget(); +} + +JSObject* +DesktopNotificationCenter::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return DesktopNotificationCenterBinding::Wrap(aCx, this, aGivenProto); +} + +/* ------------------------------------------------------------------------ */ +/* DesktopNotificationRequest */ +/* ------------------------------------------------------------------------ */ + +NS_IMPL_ISUPPORTS_INHERITED(DesktopNotificationRequest, Runnable, + nsIContentPermissionRequest) + +NS_IMETHODIMP +DesktopNotificationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) +{ + if (!mDesktopNotification) { + return NS_ERROR_NOT_INITIALIZED; + } + + NS_IF_ADDREF(*aRequestingPrincipal = mDesktopNotification->mPrincipal); + return NS_OK; +} + +NS_IMETHODIMP +DesktopNotificationRequest::GetWindow(mozIDOMWindow** aRequestingWindow) +{ + if (!mDesktopNotification) { + return NS_ERROR_NOT_INITIALIZED; + } + + NS_IF_ADDREF(*aRequestingWindow = mDesktopNotification->GetOwner()); + return NS_OK; +} + +NS_IMETHODIMP +DesktopNotificationRequest::GetElement(nsIDOMElement * *aElement) +{ + NS_ENSURE_ARG_POINTER(aElement); + *aElement = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +DesktopNotificationRequest::GetIsHandlingUserInput(bool *aIsHandlingUserInput) +{ + *aIsHandlingUserInput = mDesktopNotification->mIsHandlingUserInput; + return NS_OK; +} + +NS_IMETHODIMP +DesktopNotificationRequest::Cancel() +{ + nsresult rv = mDesktopNotification->SetAllow(false); + mDesktopNotification = nullptr; + return rv; +} + +NS_IMETHODIMP +DesktopNotificationRequest::Allow(JS::HandleValue aChoices) +{ + MOZ_ASSERT(aChoices.isUndefined()); + nsresult rv = mDesktopNotification->SetAllow(true); + mDesktopNotification = nullptr; + return rv; +} + +NS_IMETHODIMP +DesktopNotificationRequest::GetRequester(nsIContentPermissionRequester** aRequester) +{ + NS_ENSURE_ARG_POINTER(aRequester); + + nsCOMPtr requester = mRequester; + requester.forget(aRequester); + return NS_OK; +} + +NS_IMETHODIMP +DesktopNotificationRequest::GetTypes(nsIArray** aTypes) +{ + nsTArray emptyOptions; + return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"), + NS_LITERAL_CSTRING("unused"), + emptyOptions, + aTypes); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/notification/DesktopNotification.h b/dom/notification/DesktopNotification.h new file mode 100644 index 000000000000..763b5744393d --- /dev/null +++ b/dom/notification/DesktopNotification.h @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 mozilla_dom_DesktopNotification_h +#define mozilla_dom_DesktopNotification_h + +#include "nsIPrincipal.h" +#include "nsIAlertsService.h" +#include "nsIContentPermissionPrompt.h" + +#include "nsIObserver.h" +#include "nsString.h" +#include "nsWeakPtr.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIDOMWindow.h" +#include "nsIScriptObjectPrincipal.h" + +#include "nsIDOMEvent.h" + +#include "mozilla/Attributes.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/ErrorResult.h" +#include "nsWrapperCache.h" + + +namespace mozilla { +namespace dom { + +class AlertServiceObserver; +class DesktopNotification; + +/* + * DesktopNotificationCenter + * Object hangs off of the navigator object and hands out DesktopNotification objects + */ +class DesktopNotificationCenter final : public nsISupports, + public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DesktopNotificationCenter) + + explicit DesktopNotificationCenter(nsPIDOMWindowInner* aWindow) + { + MOZ_ASSERT(aWindow); + mOwner = aWindow; + + nsCOMPtr sop = do_QueryInterface(aWindow); + MOZ_ASSERT(sop); + + mPrincipal = sop->GetPrincipal(); + MOZ_ASSERT(mPrincipal); + } + + void Shutdown() { + mOwner = nullptr; + } + + nsPIDOMWindowInner* GetParentObject() const + { + return mOwner; + } + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + already_AddRefed + CreateNotification(const nsAString& title, + const nsAString& description, + const nsAString& iconURL); + +private: + virtual ~DesktopNotificationCenter() + { + } + + nsCOMPtr mOwner; + nsCOMPtr mPrincipal; +}; + +class DesktopNotificationRequest; + +class DesktopNotification final : public DOMEventTargetHelper +{ + friend class DesktopNotificationRequest; + +public: + + DesktopNotification(const nsAString& aTitle, + const nsAString& aDescription, + const nsAString& aIconURL, + nsPIDOMWindowInner* aWindow, + bool aIsHandlingUserInput, + nsIPrincipal* principal); + + virtual ~DesktopNotification(); + + void Init(); + + /* + * PostDesktopNotification + * Uses alert service to display a notification + */ + nsresult PostDesktopNotification(); + + nsresult SetAllow(bool aAllow); + + /* + * Creates and dispatches a dom event of type aName + */ + void DispatchNotificationEvent(const nsString& aName); + + void HandleAlertServiceNotification(const char *aTopic); + + // WebIDL + + nsPIDOMWindowInner* GetParentObject() const + { + return GetOwner(); + } + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + void Show(ErrorResult& aRv); + + IMPL_EVENT_HANDLER(click) + IMPL_EVENT_HANDLER(close) + +protected: + + nsString mTitle; + nsString mDescription; + nsString mIconURL; + + RefPtr mObserver; + nsCOMPtr mPrincipal; + bool mIsHandlingUserInput; + bool mAllow; + bool mShowHasBeenCalled; + + static uint32_t sCount; +}; + +class AlertServiceObserver: public nsIObserver +{ + public: + NS_DECL_ISUPPORTS + + explicit AlertServiceObserver(DesktopNotification* notification) + : mNotification(notification) {} + + void Disconnect() { mNotification = nullptr; } + + NS_IMETHOD + Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) override + { + + // forward to parent + if (mNotification) { + mNotification->HandleAlertServiceNotification(aTopic); + } + return NS_OK; + }; + + private: + virtual ~AlertServiceObserver() {} + + DesktopNotification* mNotification; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_DesktopNotification_h */ diff --git a/dom/notification/moz.build b/dom/notification/moz.build index 23d362af4de7..819743b1fd28 100644 --- a/dom/notification/moz.build +++ b/dom/notification/moz.build @@ -17,11 +17,13 @@ EXTRA_JS_MODULES += [ ] EXPORTS.mozilla.dom += [ + 'DesktopNotification.h', 'Notification.h', 'NotificationEvent.h', ] UNIFIED_SOURCES += [ + 'DesktopNotification.cpp', 'Notification.cpp', 'NotificationEvent.cpp', ] diff --git a/dom/tests/mochitest/general/test_interfaces.js b/dom/tests/mochitest/general/test_interfaces.js index 52c33c1f4eea..bcdd45153b0b 100644 --- a/dom/tests/mochitest/general/test_interfaces.js +++ b/dom/tests/mochitest/general/test_interfaces.js @@ -270,6 +270,10 @@ var interfaceNamesInGlobalScope = "DataTransferItemList", // IMPORTANT: Do not change this list without review from a DOM peer! "DelayNode", +// IMPORTANT: Do not change this list without review from a DOM peer! + "DesktopNotification", +// IMPORTANT: Do not change this list without review from a DOM peer! + "DesktopNotificationCenter", // IMPORTANT: Do not change this list without review from a DOM peer! "DeviceLightEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/tests/mochitest/notification/desktop-notification/create_notification.html b/dom/tests/mochitest/notification/desktop-notification/create_notification.html new file mode 100644 index 000000000000..b0387e4ffb84 --- /dev/null +++ b/dom/tests/mochitest/notification/desktop-notification/create_notification.html @@ -0,0 +1,16 @@ + + + + Create a notification + + + + + diff --git a/dom/tests/mochitest/notification/desktop-notification/moz.build b/dom/tests/mochitest/notification/desktop-notification/moz.build new file mode 100644 index 000000000000..28919c271d33 --- /dev/null +++ b/dom/tests/mochitest/notification/desktop-notification/moz.build @@ -0,0 +1,6 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + diff --git a/dom/tests/mochitest/notification/desktop-notification/notification_common.js b/dom/tests/mochitest/notification/desktop-notification/notification_common.js new file mode 100644 index 000000000000..921b1e753cd8 --- /dev/null +++ b/dom/tests/mochitest/notification/desktop-notification/notification_common.js @@ -0,0 +1,70 @@ +const MOCK_ALERTS_CID = SpecialPowers.wrap(SpecialPowers.Components).ID("{48068bc2-40ab-4904-8afd-4cdfb3a385f3}"); +const ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/alerts-service;1"; + +const MOCK_SYSTEM_ALERTS_CID = SpecialPowers.wrap(SpecialPowers.Components).ID("{e86d888c-e41b-4b78-9104-2f2742a532de}"); +const SYSTEM_ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/system-alerts-service;1"; + +var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager. + QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar); + +var mockAlertsService = { + showAlert: function(alert, alertListener) { + // probably should do this async.... + SpecialPowers.wrap(alertListener).observe(null, "alertshow", alert.cookie); + + if (SpecialPowers.getBoolPref("notification.prompt.testing.click_on_notification") == true) { + SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", alert.cookie); + } + + SpecialPowers.wrap(alertListener).observe(null, "alertfinished", alert.cookie); + }, + + showAlertNotification: function(imageUrl, title, text, textClickable, + cookie, alertListener, name, bidi, + lang, data) { + return this.showAlert({ + cookie: cookie + }, alertListener); + }, + + QueryInterface: function(aIID) { + if (SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) || + SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService)) { + return this; + } + throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE; + }, + + createInstance: function(aOuter, aIID) { + if (aOuter != null) { + throw SpecialPowers.Components.results.NS_ERROR_NO_AGGREGATION; + } + return this.QueryInterface(aIID); + } +}; +mockAlertsService = SpecialPowers.wrapCallbackObject(mockAlertsService); + +function setup_notifications(allowPrompt, forceClick, callback) { + SpecialPowers.pushPrefEnv({'set': [["notification.prompt.testing", true], + ["notification.prompt.testing.allow", allowPrompt], + ["notification.prompt.testing.click_on_notification", forceClick]]}, + callback); + + registrar.registerFactory(MOCK_SYSTEM_ALERTS_CID, "system alerts service", + SYSTEM_ALERTS_SERVICE_CONTRACT_ID, + mockAlertsService); + + registrar.registerFactory(MOCK_ALERTS_CID, "alerts service", + ALERTS_SERVICE_CONTRACT_ID, + mockAlertsService); +} + +function reset_notifications() { + registrar.unregisterFactory(MOCK_SYSTEM_ALERTS_CID, mockAlertsService); + registrar.unregisterFactory(MOCK_ALERTS_CID, mockAlertsService); +} + +function is_feature_enabled() { + return navigator.mozNotification && SpecialPowers.getBoolPref("notification.feature.enabled"); +} + diff --git a/dom/tests/mochitest/notification/desktop-notification/test_basic_notification.html b/dom/tests/mochitest/notification/desktop-notification/test_basic_notification.html new file mode 100644 index 000000000000..75f3c84b4ab9 --- /dev/null +++ b/dom/tests/mochitest/notification/desktop-notification/test_basic_notification.html @@ -0,0 +1,50 @@ + + + + + Basic functional test + + + + + +Basic property tests +

+ +
+
+ + + diff --git a/dom/tests/mochitest/notification/desktop-notification/test_basic_notification_click.html b/dom/tests/mochitest/notification/desktop-notification/test_basic_notification_click.html new file mode 100644 index 000000000000..defa0f412099 --- /dev/null +++ b/dom/tests/mochitest/notification/desktop-notification/test_basic_notification_click.html @@ -0,0 +1,53 @@ + + + + + Basic functional test + + + + + +Basic property tests +

+ +
+
+ + + diff --git a/dom/tests/mochitest/notification/desktop-notification/test_leak_windowClose.html b/dom/tests/mochitest/notification/desktop-notification/test_leak_windowClose.html new file mode 100644 index 000000000000..136ea049565f --- /dev/null +++ b/dom/tests/mochitest/notification/desktop-notification/test_leak_windowClose.html @@ -0,0 +1,34 @@ + + + + + Test for leak when window closes + + + + + + + +

I like to write tests

+ + diff --git a/dom/tests/mochitest/notification/desktop-notification/test_notification_tag.html b/dom/tests/mochitest/notification/desktop-notification/test_notification_tag.html new file mode 100644 index 000000000000..37bcb16c0299 --- /dev/null +++ b/dom/tests/mochitest/notification/desktop-notification/test_notification_tag.html @@ -0,0 +1,110 @@ + + + + + Bug 782211 + + + + +Bug 782211 +

+ + + + +
+
+ + + diff --git a/dom/tests/mochitest/notification/desktop-notification/test_system_principal.xul b/dom/tests/mochitest/notification/desktop-notification/test_system_principal.xul new file mode 100644 index 000000000000..1690bc101bdf --- /dev/null +++ b/dom/tests/mochitest/notification/desktop-notification/test_system_principal.xul @@ -0,0 +1,85 @@ + + + + + + + diff --git a/dom/webidl/DesktopNotification.webidl b/dom/webidl/DesktopNotification.webidl new file mode 100644 index 000000000000..18bfce9dc5fe --- /dev/null +++ b/dom/webidl/DesktopNotification.webidl @@ -0,0 +1,26 @@ +/* -*- Mode: IDL; tab-width: 2; 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/. + */ + +interface MozObserver; + +[HeaderFile="mozilla/dom/DesktopNotification.h"] +interface DesktopNotificationCenter +{ + [NewObject] + DesktopNotification createNotification(DOMString title, + DOMString description, + optional DOMString iconURL = ""); +}; + +interface DesktopNotification : EventTarget +{ + [Throws] + void show(); + + attribute EventHandler onclick; + + attribute EventHandler onclose; +}; diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index 4dd89cc89a74..587bd5517407 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -200,6 +200,12 @@ partial interface Navigator { void removeIdleObserver(MozIdleObserver aIdleObserver); }; +// nsIDOMNavigatorDesktopNotification +partial interface Navigator { + [Throws, Pref="notification.feature.enabled", UnsafeInPrerendering] + readonly attribute DesktopNotificationCenter mozNotification; +}; + // NetworkInformation partial interface Navigator { [Throws, Pref="dom.netinfo.enabled"] diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 3929d2b9d928..25aad128ef7a 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -97,6 +97,9 @@ with Files("DelayNode.webidl"): with Files("DynamicsCompressorNode.webidl"): BUG_COMPONENT = ("Core", "Web Audio") +with Files("DesktopNotification.webidl"): + BUG_COMPONENT = ("Toolkit", "Notifications and Alerts") + with Files("FakePluginTagInit.webidl"): BUG_COMPONENT = ("Core", "Plug-ins") @@ -475,6 +478,7 @@ WEBIDL_FILES = [ 'DecoderDoctorNotification.webidl', 'DedicatedWorkerGlobalScope.webidl', 'DelayNode.webidl', + 'DesktopNotification.webidl', 'DeviceMotionEvent.webidl', 'Directory.webidl', 'Document.webidl', diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 7c11eebfe4a5..27e4e46c534f 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5024,6 +5024,9 @@ pref("extensions.webcompat-reporter.enabled", false); pref("network.buffer.cache.count", 24); pref("network.buffer.cache.size", 32768); +// Desktop Notification +pref("notification.feature.enabled", false); + // Web Notification pref("dom.webnotifications.enabled", true); pref("dom.webnotifications.serviceworker.enabled", true); diff --git a/widget/cocoa/OSXNotificationCenter.h b/widget/cocoa/OSXNotificationCenter.h index b18ec12e94a3..30767b5c55a6 100644 --- a/widget/cocoa/OSXNotificationCenter.h +++ b/widget/cocoa/OSXNotificationCenter.h @@ -13,6 +13,8 @@ #include "nsTArray.h" #include "mozilla/RefPtr.h" +@class mozNotificationCenterDelegate; + #if !defined(MAC_OS_X_VERSION_10_8) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8) typedef NSInteger NSUserNotificationActivationType; #endif @@ -43,6 +45,7 @@ protected: virtual ~OSXNotificationCenter(); private: + mozNotificationCenterDelegate *mDelegate; nsTArray > mActiveAlerts; nsTArray > mPendingAlerts; }; diff --git a/widget/cocoa/OSXNotificationCenter.mm b/widget/cocoa/OSXNotificationCenter.mm index ff7ceeb6c681..4c7849ecfb9d 100644 --- a/widget/cocoa/OSXNotificationCenter.mm +++ b/widget/cocoa/OSXNotificationCenter.mm @@ -78,6 +78,69 @@ enum { - (void)_removeDisplayedNotification:(id)notification; @end +@interface mozNotificationCenterDelegate : NSObject +{ + OSXNotificationCenter *mOSXNC; +} + - (id)initWithOSXNC:(OSXNotificationCenter*)osxnc; +@end + +@implementation mozNotificationCenterDelegate + +- (id)initWithOSXNC:(OSXNotificationCenter*)osxnc +{ + [super init]; + // We should *never* outlive this OSXNotificationCenter. + mOSXNC = osxnc; + return self; +} + +- (void)userNotificationCenter:(id)center + didDeliverNotification:(id)notification +{ + +} + +- (void)userNotificationCenter:(id)center + didActivateNotification:(id)notification +{ + unsigned long long additionalActionIndex = ULLONG_MAX; + if ([notification respondsToSelector:@selector(_alternateActionIndex)]) { + NSNumber *alternateActionIndex = [(NSObject*)notification valueForKey:@"_alternateActionIndex"]; + additionalActionIndex = [alternateActionIndex unsignedLongLongValue]; + } + mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"], + notification.activationType, + additionalActionIndex); +} + +- (BOOL)userNotificationCenter:(id)center + shouldPresentNotification:(id)notification +{ + return YES; +} + +// This is an undocumented method that we need for parity with Safari. +// Apple bug #15440664. +- (void)userNotificationCenter:(id)center + didRemoveDeliveredNotifications:(NSArray *)notifications +{ + for (id notification in notifications) { + NSString *name = [[notification userInfo] valueForKey:@"name"]; + mOSXNC->CloseAlertCocoaString(name); + } +} + +// This is an undocumented method that we need to be notified if a user clicks the close button. +- (void)userNotificationCenter:(id)center + didDismissAlert:(id)notification +{ + NSString *name = [[notification userInfo] valueForKey:@"name"]; + mOSXNC->CloseAlertCocoaString(name); +} + +@end + namespace mozilla { enum { @@ -138,10 +201,22 @@ static id GetNotificationCenter() { OSXNotificationCenter::OSXNotificationCenter() { + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + mDelegate = [[mozNotificationCenterDelegate alloc] initWithOSXNC:this]; + GetNotificationCenter().delegate = mDelegate; + + NS_OBJC_END_TRY_ABORT_BLOCK; } OSXNotificationCenter::~OSXNotificationCenter() { + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + [GetNotificationCenter() removeAllDeliveredNotifications]; + [mDelegate release]; + + NS_OBJC_END_TRY_ABORT_BLOCK; } NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsIAlertsIconData, From c845da008c02d8ce60208442e4c9625544c3d271 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Tue, 2 Jan 2018 18:30:15 -0800 Subject: [PATCH 18/28] Bug 1347731 - Simplify WGL initialization code. - r=daoshengmu MozReview-Commit-ID: DpS0nkTghXD --- gfx/gl/GLContextProviderWGL.cpp | 654 +++++++++++++++----------------- gfx/gl/GLContextWGL.h | 19 +- gfx/gl/WGLLibrary.h | 76 ++-- 3 files changed, 357 insertions(+), 392 deletions(-) diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp index b81935b6882b..4899038fbfff 100644 --- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -31,12 +31,25 @@ using namespace mozilla::widget; WGLLibrary sWGLLib; -HWND -WGLLibrary::CreateDummyWindow(HDC* aWindowDC) + + +/* +ScopedWindow::~ScopedWindow() { - WNDCLASSW wc; + if (mDC) { + MOZ_ALWAYS_TRUE( ReleaseDC(mDC) ); + } + if (mWindow) { + MOZ_ALWAYS_TRUE( DestroyWindow(mWindow) ); + } +} +*/ +static HWND +CreateDummyWindow() +{ + WNDCLASSW wc{}; if (!GetClassInfoW(GetModuleHandle(nullptr), L"GLContextWGLClass", &wc)) { - ZeroMemory(&wc, sizeof(WNDCLASSW)); + wc = {}; wc.style = CS_OWNDC; wc.hInstance = GetModuleHandle(nullptr); wc.lpfnWndProc = DefWindowProc; @@ -48,46 +61,10 @@ WGLLibrary::CreateDummyWindow(HDC* aWindowDC) } } - HWND win = CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0, - 0, 0, 16, 16, - nullptr, nullptr, GetModuleHandle(nullptr), - nullptr); - NS_ENSURE_TRUE(win, nullptr); - - HDC dc = GetDC(win); - NS_ENSURE_TRUE(dc, nullptr); - - if (mWindowPixelFormat == 0) { - PIXELFORMATDESCRIPTOR pfd; - ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cRedBits = 8; - pfd.cGreenBits = 8; - pfd.cBlueBits = 8; - pfd.cAlphaBits = 8; - pfd.cDepthBits = gfxVars::UseWebRender() ? 24 : 0; - pfd.iLayerType = PFD_MAIN_PLANE; - - mWindowPixelFormat = ChoosePixelFormat(dc, &pfd); - } - - if (!mWindowPixelFormat || - !SetPixelFormat(dc, mWindowPixelFormat, nullptr)) - { - NS_WARNING("SetPixelFormat failed!"); - DestroyWindow(win); - return nullptr; - } - - if (aWindowDC) { - *aWindowDC = dc; - } - - return win; + return CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0, + 0, 0, 1, 1, + nullptr, nullptr, GetModuleHandle(nullptr), + nullptr); } static inline bool @@ -137,128 +114,137 @@ WGLLibrary::EnsureInitialized() return false; } - // This is ridiculous -- we have to actually create a context to - // get the OpenGL ICD to load. - mWindow = CreateDummyWindow(&mWindowDC); - NS_ENSURE_TRUE(mWindow, false); + mDummyWindow = CreateDummyWindow(); + MOZ_ASSERT(mDummyWindow); + if (!mDummyWindow) + return false; + auto cleanup = MakeScopeExit([&]() { + Reset(); + }); + + mRootDc = GetDC(mDummyWindow); + MOZ_ASSERT(mRootDc); + if (!mRootDc) + return false; + + // -- + + { + PIXELFORMATDESCRIPTOR pfd{}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + //pfd.iPixelType = PFD_TYPE_RGBA; + //pfd.cColorBits = 24; + //pfd.cRedBits = 8; + //pfd.cGreenBits = 8; + //pfd.cBlueBits = 8; + //pfd.cAlphaBits = 8; + pfd.iLayerType = PFD_MAIN_PLANE; + + const auto pixelFormat = ChoosePixelFormat(mRootDc, &pfd); + MOZ_ASSERT(pixelFormat); + if (!pixelFormat) + return false; + const bool setPixelFormatOk = SetPixelFormat(mRootDc, pixelFormat, nullptr); + MOZ_ASSERT(setPixelFormatOk); + if (!setPixelFormatOk) + return false; + } + + // -- // create rendering context - mWindowGLContext = mSymbols.fCreateContext(mWindowDC); - NS_ENSURE_TRUE(mWindowGLContext, false); + mDummyGlrc = mSymbols.fCreateContext(mRootDc); + if (!mDummyGlrc) + return false; - if (!mSymbols.fMakeCurrent(mWindowDC, mWindowGLContext)) { + const auto curCtx = mSymbols.fGetCurrentContext(); + const auto curDC = mSymbols.fGetCurrentDC(); + + if (!mSymbols.fMakeCurrent(mRootDc, mDummyGlrc)) { NS_WARNING("wglMakeCurrent failed"); return false; } + const auto resetContext = MakeScopeExit([&]() { + mSymbols.fMakeCurrent(curDC, curCtx); + }); - const auto& curCtx = mSymbols.fGetCurrentContext(); - const auto& curDC = mSymbols.fGetCurrentDC(); - - const auto& lookupFunc = (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress; + const auto lookupFunc = (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress; // Now we can grab all the other symbols that we couldn't without having // a context current. - const GLLibraryLoader::SymLoadStruct pbufferSymbols[] = { + const GLLibraryLoader::SymLoadStruct reqExtSymbols[] = { { (PRFuncPtr*)&mSymbols.fCreatePbuffer, { "wglCreatePbufferARB", "wglCreatePbufferEXT", nullptr } }, { (PRFuncPtr*)&mSymbols.fDestroyPbuffer, { "wglDestroyPbufferARB", "wglDestroyPbufferEXT", nullptr } }, { (PRFuncPtr*)&mSymbols.fGetPbufferDC, { "wglGetPbufferDCARB", "wglGetPbufferDCEXT", nullptr } }, - { (PRFuncPtr*)&mSymbols.fBindTexImage, { "wglBindTexImageARB", "wglBindTexImageEXT", nullptr } }, - { (PRFuncPtr*)&mSymbols.fReleaseTexImage, { "wglReleaseTexImageARB", "wglReleaseTexImageEXT", nullptr } }, - END_OF_SYMBOLS - }; - - const GLLibraryLoader::SymLoadStruct pixFmtSymbols[] = { + { (PRFuncPtr*)&mSymbols.fReleasePbufferDC, { "wglReleasePbufferDCARB", "wglReleasePbufferDCEXT", nullptr } }, + // { (PRFuncPtr*)&mSymbols.fBindTexImage, { "wglBindTexImageARB", "wglBindTexImageEXT", nullptr } }, + // { (PRFuncPtr*)&mSymbols.fReleaseTexImage, { "wglReleaseTexImageARB", "wglReleaseTexImageEXT", nullptr } }, { (PRFuncPtr*)&mSymbols.fChoosePixelFormat, { "wglChoosePixelFormatARB", "wglChoosePixelFormatEXT", nullptr } }, - { (PRFuncPtr*)&mSymbols.fGetPixelFormatAttribiv, { "wglGetPixelFormatAttribivARB", "wglGetPixelFormatAttribivEXT", nullptr } }, - END_OF_SYMBOLS - }; - - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, pbufferSymbols, lookupFunc)) { - // this isn't an error, just means that pbuffers aren't supported - ClearSymbols(pbufferSymbols); - } - - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, pixFmtSymbols, lookupFunc)) { - // this isn't an error, just means that we don't have the pixel format extension - ClearSymbols(pixFmtSymbols); - } - - const GLLibraryLoader::SymLoadStruct extensionsSymbols[] = { + // { (PRFuncPtr*)&mSymbols.fGetPixelFormatAttribiv, { "wglGetPixelFormatAttribivARB", "wglGetPixelFormatAttribivEXT", nullptr } }, SYMBOL(GetExtensionsStringARB), END_OF_SYMBOLS }; - - const GLLibraryLoader::SymLoadStruct robustnessSymbols[] = { - SYMBOL(CreateContextAttribsARB), - END_OF_SYMBOLS - }; - - const GLLibraryLoader::SymLoadStruct dxInteropSymbols[] = { - SYMBOL(DXSetResourceShareHandleNV), - SYMBOL(DXOpenDeviceNV), - SYMBOL(DXCloseDeviceNV), - SYMBOL(DXRegisterObjectNV), - SYMBOL(DXUnregisterObjectNV), - SYMBOL(DXObjectAccessNV), - SYMBOL(DXLockObjectsNV), - SYMBOL(DXUnlockObjectsNV), - END_OF_SYMBOLS - }; - - if (GLLibraryLoader::LoadSymbols(mOGLLibrary, extensionsSymbols, lookupFunc)) { - const char* extString = mSymbols.fGetExtensionsStringARB(mWindowDC); - MOZ_ASSERT(extString); - MOZ_ASSERT(HasExtension(extString, "WGL_ARB_extensions_string")); - - if (HasExtension(extString, "WGL_ARB_create_context")) { - if (GLLibraryLoader::LoadSymbols(mOGLLibrary, robustnessSymbols, lookupFunc)) { - if (HasExtension(extString, "WGL_ARB_create_context_robustness")) { - mHasRobustness = true; - } - } else { - NS_ERROR("WGL supports ARB_create_context without supplying its functions."); - ClearSymbols(robustnessSymbols); - } - } - - //// - - bool hasDXInterop2 = HasExtension(extString, "WGL_NV_DX_interop2"); - if (gfxVars::DXInterop2Blocked() && - !gfxPrefs::IgnoreDXInterop2Blacklist()) - { - hasDXInterop2 = false; - } - - if (hasDXInterop2) { - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, dxInteropSymbols, - lookupFunc)) - { - NS_ERROR("WGL supports NV_DX_interop(2) without supplying its functions."); - ClearSymbols(dxInteropSymbols); - } - } + if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, reqExtSymbols, lookupFunc)) { + NS_WARNING("reqExtSymbols missing"); + return false; } - // reset back to the previous context, just in case - mSymbols.fMakeCurrent(curDC, curCtx); + // -- - if (mHasRobustness) { - mSymbols.fDeleteContext(mWindowGLContext); + const auto extString = mSymbols.fGetExtensionsStringARB(mRootDc); + MOZ_ASSERT(extString); + MOZ_ASSERT(HasExtension(extString, "WGL_ARB_extensions_string")); - const int attribs[] = { - LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, - LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, - 0 + // -- + + if (HasExtension(extString, "WGL_ARB_create_context")) { + const GLLibraryLoader::SymLoadStruct createContextSymbols[] = { + SYMBOL(CreateContextAttribsARB), + END_OF_SYMBOLS }; - - mWindowGLContext = mSymbols.fCreateContextAttribsARB(mWindowDC, nullptr, attribs); - if (!mWindowGLContext) { - mHasRobustness = false; - mWindowGLContext = mSymbols.fCreateContext(mWindowDC); + if (GLLibraryLoader::LoadSymbols(mOGLLibrary, createContextSymbols, lookupFunc)) { + if (HasExtension(extString, "WGL_ARB_create_context_robustness")) { + mHasRobustness = true; + } + } else { + NS_ERROR("WGL_ARB_create_context announced without supplying its functions."); + ClearSymbols(createContextSymbols); } } + // -- + + bool hasDXInterop2 = HasExtension(extString, "WGL_NV_DX_interop2"); + if (gfxVars::DXInterop2Blocked() && + !gfxPrefs::IgnoreDXInterop2Blacklist()) + { + hasDXInterop2 = false; + } + + if (hasDXInterop2) { + const GLLibraryLoader::SymLoadStruct dxInteropSymbols[] = { + SYMBOL(DXSetResourceShareHandleNV), + SYMBOL(DXOpenDeviceNV), + SYMBOL(DXCloseDeviceNV), + SYMBOL(DXRegisterObjectNV), + SYMBOL(DXUnregisterObjectNV), + SYMBOL(DXObjectAccessNV), + SYMBOL(DXLockObjectsNV), + SYMBOL(DXUnlockObjectsNV), + END_OF_SYMBOLS + }; + if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, dxInteropSymbols, lookupFunc)) { + NS_ERROR("WGL_NV_DX_interop2 announceed without supplying its functions."); + ClearSymbols(dxInteropSymbols); + } + } + + // -- + + cleanup.release(); + mInitialized = true; reporter.SetSuccessful(); @@ -268,6 +254,23 @@ WGLLibrary::EnsureInitialized() #undef SYMBOL #undef END_OF_SYMBOLS +void +WGLLibrary::Reset() +{ + if (mDummyGlrc) { + (void)mSymbols.fDeleteContext(mDummyGlrc); + mDummyGlrc = nullptr; + } + if (mRootDc) { + (void)ReleaseDC(mDummyWindow, mRootDc); + mRootDc = nullptr; + } + if (mDummyWindow) { + (void)DestroyWindow(mDummyWindow); + mDummyWindow = nullptr; + } +} + GLContextWGL::GLContextWGL(CreateContextFlags flags, const SurfaceCaps& caps, bool isOffscreen, HDC aDC, HGLRC aContext, HWND aWindow) : GLContext(flags, caps, nullptr, isOffscreen), @@ -297,12 +300,16 @@ GLContextWGL::~GLContextWGL() { MarkDestroyed(); - sWGLLib.mSymbols.fDeleteContext(mContext); + (void)sWGLLib.mSymbols.fDeleteContext(mContext); - if (mPBuffer) - sWGLLib.mSymbols.fDestroyPbuffer(mPBuffer); - if (mWnd) + if (mPBuffer) { + (void)sWGLLib.mSymbols.fReleasePbufferDC(mPBuffer, mDC); + (void)sWGLLib.mSymbols.fDestroyPbuffer(mPBuffer); + } + if (mWnd) { + (void)ReleaseDC(mWnd, mDC); DestroyWindow(mWnd); + } } bool @@ -336,20 +343,9 @@ GLContextWGL::IsCurrentImpl() const return sWGLLib.mSymbols.fGetCurrentContext() == mContext; } -void -GLContextWGL::SetIsDoubleBuffered(bool aIsDB) -{ - mIsDoubleBuffered = aIsDB; -} - bool -GLContextWGL::IsDoubleBuffered() const +GLContextWGL::SwapBuffers() { - return mIsDoubleBuffered; -} - -bool -GLContextWGL::SwapBuffers() { if (!mIsDoubleBuffered) return false; return ::SwapBuffers(mDC); @@ -375,89 +371,112 @@ GLContextWGL::SetupLookupFunction() return true; } -static bool -GetMaxSize(HDC hDC, int format, IntSize& size) -{ - int query[] = {LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB, LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB}; - int result[2]; - - // (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int* piValues) - if (!sWGLLib.mSymbols.fGetPixelFormatAttribiv(hDC, format, 0, 2, query, result)) - return false; - - size.width = result[0]; - size.height = result[1]; - return true; -} - -static bool -IsValidSizeForFormat(HDC hDC, int format, - const IntSize& requested) -{ - IntSize max; - if (!GetMaxSize(hDC, format, max)) - return true; - - if (requested.width > max.width) - return false; - if (requested.height > max.height) - return false; - - return true; -} - already_AddRefed GLContextProviderWGL::CreateWrappingExisting(void*, void*) { return nullptr; } -already_AddRefed -CreateForWidget(HWND aHwnd, - bool aWebRender, - bool aForceAccelerated) +HGLRC +WGLLibrary::CreateContextWithFallback(const HDC dc, const bool tryRobustBuffers) const { - if (!sWGLLib.EnsureInitialized()) { - return nullptr; - } + if (mHasRobustness) { + if (tryRobustBuffers) { + const int attribs[] = { + LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, + LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, + 0 + }; + const auto context = mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs); + if (context) + return context; + } - /** - * We need to make sure we call SetPixelFormat -after- calling - * EnsureInitialized, otherwise it can load/unload the dll and - * wglCreateContext will fail. - */ - - HDC dc = ::GetDC(aHwnd); - - SetPixelFormat(dc, sWGLLib.GetWindowPixelFormat(), nullptr); - HGLRC context; - - if (sWGLLib.HasRobustness()) { - int attribs[] = { - LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, + const int attribs[] = { LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, 0 }; - - context = sWGLLib.mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs); - } else { - context = sWGLLib.mSymbols.fCreateContext(dc); + const auto context = mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs); + if (context) + return context; } + if (mSymbols.fCreateContextAttribsARB) { + const auto context = mSymbols.fCreateContextAttribsARB(dc, nullptr, nullptr); + if (context) + return context; + } + return mSymbols.fCreateContext(dc); +} - if (!context) { +static RefPtr +CreateForWidget(const HWND window, const bool isWebRender, const bool requireAccelerated) +{ + auto& wgl = sWGLLib; + if (!wgl.EnsureInitialized()) return nullptr; + + const auto dc = GetDC(window); + if (!dc) + return nullptr; + auto cleanupDc = MakeScopeExit([&](){ + (void)ReleaseDC(window, dc); + }); + + int chosenFormat; + UINT foundFormats = 0; + + if (!foundFormats) { + const int kAttribs[] = { + LOCAL_WGL_DRAW_TO_WINDOW_ARB, true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, true, + LOCAL_WGL_DOUBLE_BUFFER_ARB, true, + LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB, + 0 + }; + if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, + &chosenFormat, &foundFormats)) + { + foundFormats = 0; + } } + if (!foundFormats) { + if (requireAccelerated) + return nullptr; + + const int kAttribs[] = { + LOCAL_WGL_DRAW_TO_WINDOW_ARB, true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, true, + LOCAL_WGL_DOUBLE_BUFFER_ARB, true, + 0 + }; + if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, + &chosenFormat, &foundFormats)) + { + foundFormats = 0; + } + } + if (!foundFormats) + return nullptr; + + // We need to make sure we call SetPixelFormat -after- calling + // EnsureInitialized, otherwise it can load/unload the dll and + // wglCreateContext will fail. + + SetPixelFormat(dc, chosenFormat, nullptr); + const auto context = sWGLLib.CreateContextWithFallback(dc, false); + if (!context) + return nullptr; SurfaceCaps caps = SurfaceCaps::ForRGBA(); - RefPtr glContext = new GLContextWGL(CreateContextFlags::NONE, caps, - false, dc, context); - if (!glContext->Init()) { + const RefPtr gl = new GLContextWGL(CreateContextFlags::NONE, + SurfaceCaps::ForRGBA(), false, + dc, context); + cleanupDc.release(); + gl->mIsDoubleBuffered = true; + if (!gl->Init()) return nullptr; - } - glContext->SetIsDoubleBuffered(true); - - return glContext.forget(); + return gl; } already_AddRefed @@ -465,145 +484,84 @@ GLContextProviderWGL::CreateForCompositorWidget(CompositorWidget* aCompositorWid { return CreateForWidget(aCompositorWidget->AsWindows()->GetHwnd(), aCompositorWidget->GetCompositorOptions().UseWebRender(), - aForceAccelerated); + aForceAccelerated).forget(); } already_AddRefed GLContextProviderWGL::CreateForWindow(nsIWidget* aWidget, bool aWebRender, bool aForceAccelerated) { - return CreateForWidget((HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW), aWebRender, aForceAccelerated); -} - -static already_AddRefed -CreatePBufferOffscreenContext(CreateContextFlags flags, const IntSize& aSize) -{ - WGLLibrary& wgl = sWGLLib; - - const int pfAttribs[] = { - LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE, - LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB, - - LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE, - LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE, - LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE, - - 0 - }; - - // We only need one! - static const uint32_t kMaxFormats = 1024; - int formats[kMaxFormats]; - uint32_t foundFormats; - HDC windowDC = wgl.GetWindowDC(); - if (!wgl.mSymbols.fChoosePixelFormat(windowDC, pfAttribs, nullptr, kMaxFormats, - formats, &foundFormats) - || foundFormats == 0) - { - return nullptr; - } - - // We don't care; just pick the first one. - int chosenFormat = formats[0]; - if (!IsValidSizeForFormat(windowDC, chosenFormat, aSize)) - return nullptr; - - const int pbAttribs[] = { 0 }; - HANDLE pbuffer = wgl.mSymbols.fCreatePbuffer(windowDC, chosenFormat, aSize.width, - aSize.height, pbAttribs); - if (!pbuffer) { - return nullptr; - } - - HDC pbdc = wgl.mSymbols.fGetPbufferDC(pbuffer); - NS_ASSERTION(pbdc, "expected a dc"); - - HGLRC context; - if (wgl.HasRobustness()) { - const int attribs[] = { - LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, - LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, - 0 - }; - context = wgl.mSymbols.fCreateContextAttribsARB(pbdc, nullptr, attribs); - } else { - context = wgl.mSymbols.fCreateContext(pbdc); - } - - if (!context) { - wgl.mSymbols.fDestroyPbuffer(pbuffer); - return nullptr; - } - - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - RefPtr glContext = new GLContextWGL(flags, dummyCaps, true, pbuffer, - pbdc, context, chosenFormat); - return glContext.forget(); -} - -static already_AddRefed -CreateWindowOffscreenContext() -{ - HDC dc; - HWND win = sWGLLib.CreateDummyWindow(&dc); - if (!win) { - return nullptr; - } - - HGLRC context = sWGLLib.mSymbols.fCreateContext(dc); - if (sWGLLib.HasRobustness()) { - int attribs[] = { - LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, - LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, - 0 - }; - - context = sWGLLib.mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs); - } else { - context = sWGLLib.mSymbols.fCreateContext(dc); - } - - if (!context) { - return nullptr; - } - - SurfaceCaps caps = SurfaceCaps::ForRGBA(); - RefPtr glContext = new GLContextWGL(CreateContextFlags::NONE, caps, - true, dc, context, win); - return glContext.forget(); + return CreateForWidget((HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW), aWebRender, + aForceAccelerated).forget(); } /*static*/ already_AddRefed -GLContextProviderWGL::CreateHeadless(CreateContextFlags flags, +GLContextProviderWGL::CreateHeadless(const CreateContextFlags flags, nsACString* const out_failureId) { - if (!sWGLLib.EnsureInitialized()) { + auto& wgl = sWGLLib; + if (!wgl.EnsureInitialized()) return nullptr; + + int chosenFormat; + UINT foundFormats = 0; + + if (!foundFormats) { + const int kAttribs[] = { + LOCAL_WGL_DRAW_TO_PBUFFER_ARB, true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, true, + LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB, + 0 + }; + if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, + &chosenFormat, &foundFormats)) + { + foundFormats = 0; + } } - - RefPtr glContext; - - // Always try to create a pbuffer context first, because we - // want the context isolation. - if (sWGLLib.mSymbols.fCreatePbuffer && - sWGLLib.mSymbols.fChoosePixelFormat) - { - IntSize dummySize = IntSize(16, 16); - glContext = CreatePBufferOffscreenContext(flags, dummySize); + if (!foundFormats) { + const int kAttribs[] = { + LOCAL_WGL_DRAW_TO_PBUFFER_ARB, true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, true, + 0 + }; + if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, + &chosenFormat, &foundFormats)) + { + foundFormats = 0; + } } - - // If it failed, then create a window context and use a FBO. - if (!glContext) { - glContext = CreateWindowOffscreenContext(); - } - - if (!glContext || - !glContext->Init()) - { + if (!foundFormats) return nullptr; - } + const int kPbufferAttribs[] = {0}; + const auto pbuffer = wgl.mSymbols.fCreatePbuffer(wgl.RootDc(), chosenFormat, 1, 1, + kPbufferAttribs); + if (!pbuffer) + return nullptr; + auto cleanupPbuffer = MakeScopeExit([&]() { + (void)wgl.mSymbols.fDestroyPbuffer(pbuffer); + }); - RefPtr retGL = glContext.get(); - return retGL.forget(); + const auto dc = wgl.mSymbols.fGetPbufferDC(pbuffer); + if (!dc) + return nullptr; + auto cleanupDc = MakeScopeExit([&]() { + (void)wgl.mSymbols.fReleasePbufferDC(pbuffer, dc); + }); + + const auto context = wgl.CreateContextWithFallback(dc, true); + if (!context) + return nullptr; + + const bool isOffscreen = true; + const RefPtr gl = new GLContextWGL(flags, SurfaceCaps::Any(), + isOffscreen, pbuffer, dc, context, + chosenFormat); + cleanupPbuffer.release(); + cleanupDc.release(); + if (!gl->Init()) + return nullptr; + + return RefPtr(gl.get()).forget(); } /*static*/ already_AddRefed @@ -612,14 +570,14 @@ GLContextProviderWGL::CreateOffscreen(const IntSize& size, CreateContextFlags flags, nsACString* const out_failureId) { + *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WGL_INIT"); + RefPtr gl = CreateHeadless(flags, out_failureId); if (!gl) return nullptr; - if (!gl->InitOffscreen(size, minCaps)) { - *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WGL_INIT"); + if (!gl->InitOffscreen(size, minCaps)) return nullptr; - } return gl.forget(); } diff --git a/gfx/gl/GLContextWGL.h b/gfx/gl/GLContextWGL.h index 2458913a1184..f4b54293201c 100644 --- a/gfx/gl/GLContextWGL.h +++ b/gfx/gl/GLContextWGL.h @@ -13,7 +13,7 @@ namespace mozilla { namespace gl { -class GLContextWGL : public GLContext +class GLContextWGL final : public GLContext { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextWGL, override) @@ -38,27 +38,13 @@ public: virtual GLContextType GetContextType() const override { return GLContextType::WGL; } - static GLContextWGL* Cast(GLContext* gl) { - MOZ_ASSERT(gl->GetContextType() == GLContextType::WGL); - return static_cast(gl); - } - bool Init() override; - virtual bool MakeCurrentImpl() const override; - virtual bool IsCurrentImpl() const override; - - void SetIsDoubleBuffered(bool aIsDB); - - virtual bool IsDoubleBuffered() const override; - + virtual bool IsDoubleBuffered() const override { return mIsDoubleBuffered; } virtual bool SwapBuffers() override; - virtual bool SetupLookupFunction() override; - virtual void GetWSIInfo(nsCString* const out) const override; - HGLRC Context() { return mContext; } protected: @@ -69,6 +55,7 @@ protected: HWND mWnd; HANDLE mPBuffer; int mPixelFormat; +public: bool mIsDoubleBuffered; }; diff --git a/gfx/gl/WGLLibrary.h b/gfx/gl/WGLLibrary.h index d9746d46c8b4..eed0ebf5b9e4 100644 --- a/gfx/gl/WGLLibrary.h +++ b/gfx/gl/WGLLibrary.h @@ -4,27 +4,52 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "GLContextTypes.h" +#include "mozilla/UniquePtr.h" #include struct PRLibrary; namespace mozilla { namespace gl { +/* +struct ScopedDC +{ + const HDC mDC; + ScopedDC() = delete; + virtual ~ScopedDC() = 0; +}; + +struct WindowDC final : public ScopedDC +{ + const HWND mWindow; + + WindowDC() = delete; + ~WindowDC(); +}; + +struct PBufferDC final : public ScopedDC +{ + const HWND mWindow; + + PBufferDC() = delete; + ~PBufferDC(); +}; +*/ class WGLLibrary { public: WGLLibrary() - : mSymbols{nullptr} - , mInitialized(false) - , mOGLLibrary(nullptr) - , mHasRobustness(false) - , mWindow (0) - , mWindowDC(0) - , mWindowGLContext(0) - , mWindowPixelFormat(0) + : mSymbols{} { } + ~WGLLibrary() { + Reset(); + } + +private: + void Reset(); + public: struct { HGLRC (GLAPIENTRY * fCreateContext) (HDC); @@ -33,20 +58,21 @@ public: PROC (GLAPIENTRY * fGetProcAddress) (LPCSTR); HGLRC (GLAPIENTRY * fGetCurrentContext) (void); HDC (GLAPIENTRY * fGetCurrentDC) (void); - BOOL (GLAPIENTRY * fShareLists) (HGLRC oldContext, HGLRC newContext); + //BOOL (GLAPIENTRY * fShareLists) (HGLRC oldContext, HGLRC newContext); HANDLE (GLAPIENTRY * fCreatePbuffer) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList); BOOL (GLAPIENTRY * fDestroyPbuffer) (HANDLE hPbuffer); HDC (GLAPIENTRY * fGetPbufferDC) (HANDLE hPbuffer); - BOOL (GLAPIENTRY * fBindTexImage) (HANDLE hPbuffer, int iBuffer); - BOOL (GLAPIENTRY * fReleaseTexImage) (HANDLE hPbuffer, int iBuffer); + int (GLAPIENTRY * fReleasePbufferDC) (HANDLE hPbuffer, HDC dc); + //BOOL (GLAPIENTRY * fBindTexImage) (HANDLE hPbuffer, int iBuffer); + //BOOL (GLAPIENTRY * fReleaseTexImage) (HANDLE hPbuffer, int iBuffer); BOOL (GLAPIENTRY * fChoosePixelFormat) (HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); - BOOL (GLAPIENTRY * fGetPixelFormatAttribiv) (HDC hdc, int iPixelFormat, - int iLayerPlane, UINT nAttributes, - int* piAttributes, int* piValues); + //BOOL (GLAPIENTRY * fGetPixelFormatAttribiv) (HDC hdc, int iPixelFormat, + // int iLayerPlane, UINT nAttributes, + // int* piAttributes, int* piValues); const char* (GLAPIENTRY * fGetExtensionsStringARB) (HDC hdc); HGLRC (GLAPIENTRY * fCreateContextAttribsARB) (HDC hdc, HGLRC hShareContext, const int* attribList); @@ -67,27 +93,21 @@ public: } mSymbols; bool EnsureInitialized(); - HWND CreateDummyWindow(HDC* aWindowDC = nullptr); + //UniquePtr CreateDummyWindow(); + HGLRC CreateContextWithFallback(HDC dc, bool tryRobustBuffers) const; - bool HasRobustness() const { return mHasRobustness; } bool HasDXInterop2() const { return bool(mSymbols.fDXOpenDeviceNV); } bool IsInitialized() const { return mInitialized; } - HWND GetWindow() const { return mWindow; } - HDC GetWindowDC() const {return mWindowDC; } - HGLRC GetWindowGLContext() const {return mWindowGLContext; } - int GetWindowPixelFormat() const { return mWindowPixelFormat; } - PRLibrary* GetOGLLibrary() { return mOGLLibrary; } + auto GetOGLLibrary() const { return mOGLLibrary; } + auto RootDc() const { return mRootDc; } private: - bool mInitialized; + bool mInitialized = false; PRLibrary* mOGLLibrary; bool mHasRobustness; - - HWND mWindow; - HDC mWindowDC; - HGLRC mWindowGLContext; - int mWindowPixelFormat; - + HWND mDummyWindow; + HDC mRootDc; + HGLRC mDummyGlrc; }; // a global WGLLibrary instance From fe413b1d226ae51995d2dd02d03281c9c287d640 Mon Sep 17 00:00:00 2001 From: Paul Bone Date: Thu, 4 Jan 2018 17:03:36 +1100 Subject: [PATCH 19/28] Bug 1422337 - Remove this test r=gfritzsche I think it should be okay that there are no GCs in a telemetry ping. --HG-- extra : rebase_source : 11b86cf415acf33d9295a0351574fb64dcbcc4da --- .../components/telemetry/tests/browser/browser_TelemetryGC.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/toolkit/components/telemetry/tests/browser/browser_TelemetryGC.js b/toolkit/components/telemetry/tests/browser/browser_TelemetryGC.js index 02bc758231e6..301930d11f0a 100644 --- a/toolkit/components/telemetry/tests/browser/browser_TelemetryGC.js +++ b/toolkit/components/telemetry/tests/browser/browser_TelemetryGC.js @@ -100,8 +100,6 @@ function check(entries) { } } } - - ok(foundGCs > 0, "saw at least one GC"); } add_task(async function test() { From 0d1852004e1697f367ab2eb02b1c536e26b14c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Qu=C3=A8ze?= Date: Fri, 5 Jan 2018 00:53:59 +0100 Subject: [PATCH 20/28] Bug 862147 - remove window.external.addSearchEngine, r=smaug. --- dom/base/UseCounters.conf | 3 +-- dom/webidl/External.webidl | 7 ------- toolkit/components/search/nsSidebar.js | 13 ------------- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/dom/base/UseCounters.conf b/dom/base/UseCounters.conf index 7967c1b8dfa0..ae5ebfddd08e 100644 --- a/dom/base/UseCounters.conf +++ b/dom/base/UseCounters.conf @@ -57,9 +57,8 @@ custom DOMErrorConstructor constructed a DOMError method PushManager.subscribe method PushSubscription.unsubscribe -// window.sidebar.addSearchEngine +// window.sidebar attribute Window.sidebar -method External.addSearchEngine // AppCache API method OfflineResourceList.swapCache diff --git a/dom/webidl/External.webidl b/dom/webidl/External.webidl index 065acc048ddf..0e9ab854328a 100644 --- a/dom/webidl/External.webidl +++ b/dom/webidl/External.webidl @@ -10,10 +10,3 @@ interface External [UnsafeInPrerendering] void AddSearchProvider(DOMString aDescriptionURL); unsigned long IsSearchProviderInstalled(DOMString aSearchURL); }; - -// Mozilla extension -partial interface External { - [UnsafeInPrerendering, UseCounter] - void addSearchEngine(DOMString engineURL, DOMString iconURL, - DOMString suggestedTitle, DOMString suggestedCategory); -}; diff --git a/toolkit/components/search/nsSidebar.js b/toolkit/components/search/nsSidebar.js index 045b4e24e6cc..2a1229aaf307 100644 --- a/toolkit/components/search/nsSidebar.js +++ b/toolkit/components/search/nsSidebar.js @@ -7,9 +7,6 @@ const { interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -// File extension for Sherlock search plugin description files -const SHERLOCK_FILE_EXT_REGEXP = /\.src$/i; - function nsSidebar() { } @@ -26,16 +23,6 @@ nsSidebar.prototype = { } }, - // Deprecated, only left here to avoid breaking old browser-detection scripts. - addSearchEngine(engineURL, iconURL, suggestedTitle, suggestedCategory) { - if (SHERLOCK_FILE_EXT_REGEXP.test(engineURL)) { - Cu.reportError("Installing Sherlock search plugins is no longer supported."); - return; - } - - this.AddSearchProvider(engineURL); - }, - // This function implements window.external.AddSearchProvider(). // The capitalization, although nonstandard here, is to match other browsers' // APIs and is therefore important. From 496d14fe4e5fed5bb4dc5d9bb79eff3837833edc Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 5 Jan 2018 01:56:46 +0200 Subject: [PATCH 21/28] Bug 1427525, try to not leak IdleTaskRunners related to GC/CC during shutdow, r=mccr8 --- dom/base/nsJSEnvironment.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 46682e7210ac..864d1980c397 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1636,6 +1636,10 @@ nsJSContext::BeginCycleCollectionCallback() MOZ_ASSERT(!sICCRunner, "Tried to create a new ICC timer when one already existed."); + if (sShuttingDown) { + return; + } + // Create an ICC timer even if ICC is globally disabled, because we could be manually triggering // an incremental collection, and we want to be sure to finish it. sICCRunner = IdleTaskRunner::Create(ICCRunnerFired, @@ -1863,6 +1867,11 @@ void GCTimerFired(nsITimer *aTimer, void *aClosure) { nsJSContext::KillGCTimer(); + nsJSContext::KillInterSliceGCRunner(); + if (sShuttingDown) { + return; + } + // Now start the actual GC after initial timer has fired. sInterSliceGCRunner = IdleTaskRunner::Create([aClosure](TimeStamp aDeadline) { return InterSliceGCRunnerFired(aDeadline, aClosure); From cd775b61efd22695feb4bf8b4f4a2893a3e4c0bd Mon Sep 17 00:00:00 2001 From: Paul Bone Date: Fri, 5 Jan 2018 11:01:21 +1100 Subject: [PATCH 22/28] Bug 1422337 follow-up - Fix eslint failures r=eslint-fix --HG-- extra : rebase_source : c03567f778bc0d339f7de4c245a0624294562017 --- .../components/telemetry/tests/browser/browser_TelemetryGC.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/toolkit/components/telemetry/tests/browser/browser_TelemetryGC.js b/toolkit/components/telemetry/tests/browser/browser_TelemetryGC.js index 301930d11f0a..065ee26371a3 100644 --- a/toolkit/components/telemetry/tests/browser/browser_TelemetryGC.js +++ b/toolkit/components/telemetry/tests/browser/browser_TelemetryGC.js @@ -29,8 +29,6 @@ function check(entries) { ok(FIELDS.includes(k), `${k} found in FIELDS`); } - let foundGCs = 0; - for (let f of FIELDS) { ok(Array.isArray(entries[f]), "have an array of GCs"); @@ -39,8 +37,6 @@ function check(entries) { for (let gc of entries[f]) { isnot(gc, null, "GC is non-null"); - foundGCs++; - ok(Object.keys(gc).length <= 24, "number of keys in GC is not too large"); // Sanity check the GC data. From a83070dfd4858d7bfab57aa258f26d1b27175e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Qu=C3=A8ze?= Date: Thu, 4 Jan 2018 22:17:38 +0100 Subject: [PATCH 23/28] Bug 1428176 - Enable browser_startup.js on DevEdition builds. r=mccr8, r=florian --- browser/base/content/test/performance/browser.ini | 1 - browser/base/content/test/performance/browser_startup.js | 5 +++-- js/xpconnect/loader/mozJSComponentLoader.cpp | 6 +++--- js/xpconnect/loader/mozJSComponentLoader.h | 8 ++++++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/browser/base/content/test/performance/browser.ini b/browser/base/content/test/performance/browser.ini index 37c160f08374..38704f4936c4 100644 --- a/browser/base/content/test/performance/browser.ini +++ b/browser/base/content/test/performance/browser.ini @@ -15,7 +15,6 @@ support-files = [browser_appmenu_reflows.js] skip-if = asan || debug # Bug 1382809, bug 1369959 [browser_startup.js] -skip-if = devedition # We ship startupRecorder.js on DevEdition, but this test still fails with it [browser_startup_content.js] skip-if = !e10s [browser_startup_flicker.js] diff --git a/browser/base/content/test/performance/browser_startup.js b/browser/base/content/test/performance/browser_startup.js index 6c3839d0372b..7b655c908385 100644 --- a/browser/base/content/test/performance/browser_startup.js +++ b/browser/base/content/test/performance/browser_startup.js @@ -142,9 +142,10 @@ if (!gBrowser.selectedBrowser.isRemoteBrowser) { } add_task(async function() { - if (!AppConstants.NIGHTLY_BUILD && !AppConstants.DEBUG) { + if (!AppConstants.NIGHTLY_BUILD && !AppConstants.MOZ_DEV_EDITION && !AppConstants.DEBUG) { ok(!("@mozilla.org/test/startuprecorder;1" in Cc), - "the startup recorder component shouldn't exist in this non-nightly non-debug build."); + "the startup recorder component shouldn't exist in this non-nightly/non-devedition/" + + "non-debug build."); return; } diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index 73549f3e6cea..f006db5c7aad 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -1035,7 +1035,7 @@ NS_IMETHODIMP mozJSComponentLoader::GetModuleImportStack(const nsACString& aLocation, nsACString& retval) { -#if defined(NIGHTLY_BUILD) || defined(DEBUG) +#ifdef STARTUP_RECORDER_ENABLED MOZ_ASSERT(nsContentUtils::IsCallerChrome()); MOZ_ASSERT(mInitialized); @@ -1058,7 +1058,7 @@ NS_IMETHODIMP mozJSComponentLoader::GetComponentLoadStack(const nsACString& aLocation, nsACString& retval) { -#if defined(NIGHTLY_BUILD) || defined(DEBUG) +#ifdef STARTUP_RECORDER_ENABLED MOZ_ASSERT(nsContentUtils::IsCallerChrome()); MOZ_ASSERT(mInitialized); @@ -1177,7 +1177,7 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation, return NS_ERROR_FILE_NOT_FOUND; } -#if defined(NIGHTLY_BUILD) || defined(DEBUG) +#ifdef STARTUP_RECORDER_ENABLED if (Preferences::GetBool("browser.startup.record", false)) { newEntry->importStack = xpc_PrintJSStack(callercx, false, false, false).get(); diff --git a/js/xpconnect/loader/mozJSComponentLoader.h b/js/xpconnect/loader/mozJSComponentLoader.h index 57381eff5e21..bc205867aca8 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.h +++ b/js/xpconnect/loader/mozJSComponentLoader.h @@ -37,6 +37,10 @@ namespace mozilla { { 0xbb, 0xef, 0xf0, 0xcc, 0xb5, 0xfa, 0x64, 0xb6 }} #define MOZJSCOMPONENTLOADER_CONTRACTID "@mozilla.org/moz/jsloader;1" +#if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION) || defined(DEBUG) +#define STARTUP_RECORDER_ENABLED +#endif + class mozJSComponentLoader final : public mozilla::ModuleLoader, public xpcIJSModuleLoader, public nsIObserver @@ -158,7 +162,7 @@ class mozJSComponentLoader final : public mozilla::ModuleLoader, obj = nullptr; thisObjectKey = nullptr; location = nullptr; -#if defined(NIGHTLY_BUILD) || defined(DEBUG) +#ifdef STARTUP_RECORDER_ENABLED importStack.Truncate(); #endif } @@ -173,7 +177,7 @@ class mozJSComponentLoader final : public mozilla::ModuleLoader, JS::PersistentRootedScript thisObjectKey; char* location; nsCString resolvedURL; -#if defined(NIGHTLY_BUILD) || defined(DEBUG) +#ifdef STARTUP_RECORDER_ENABLED nsCString importStack; #endif }; From 5fb86160b1096cc412976726a91027e1827a1fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Qu=C3=A8ze?= Date: Thu, 4 Jan 2018 23:22:26 +0100 Subject: [PATCH 24/28] Bug 1426559 - Fix browser_windowopen_flicker.js to pass on DevEdition builds. r=johannh --- .../content/test/performance/browser_windowopen_flicker.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/browser/base/content/test/performance/browser_windowopen_flicker.js b/browser/base/content/test/performance/browser_windowopen_flicker.js index a6d72b9cd0fa..cc84abbc4f2b 100644 --- a/browser/base/content/test/performance/browser_windowopen_flicker.js +++ b/browser/base/content/test/performance/browser_windowopen_flicker.js @@ -110,7 +110,10 @@ add_task(async function() { condition: r => r.h == 13 && inRange(r.w, 14, 16) && // icon size inRange(r.y1, 40, 80) && // in the toolbar // near the left side of the screen - inRange(r.x1, 65, 100) + // The reload icon is shifted on devedition builds + // where there's an additional devtools toolbar icon. + AppConstants.MOZ_DEV_EDITION ? inRange(r.x1, 100, 120) : + inRange(r.x1, 65, 100) }, {name: "bug 1401955 - about:home favicon should be visible at first paint", From 4a8c7e79c97554fc5a7c287dee03a61b00eaae00 Mon Sep 17 00:00:00 2001 From: Georg Fritzsche Date: Thu, 4 Jan 2018 00:51:00 -0500 Subject: [PATCH 25/28] Bug 1425140 - Move "adding a new probe" guide into in-tree docs. r=dexter --- toolkit/components/telemetry/docs/index.rst | 1 + .../docs/start/adding-a-new-probe.rst | 148 ++++++++++++++++++ .../components/telemetry/docs/start/index.rst | 10 ++ 3 files changed, 159 insertions(+) create mode 100644 toolkit/components/telemetry/docs/start/adding-a-new-probe.rst create mode 100644 toolkit/components/telemetry/docs/start/index.rst diff --git a/toolkit/components/telemetry/docs/index.rst b/toolkit/components/telemetry/docs/index.rst index 2a9522c2f7c6..6b1ba6061b77 100644 --- a/toolkit/components/telemetry/docs/index.rst +++ b/toolkit/components/telemetry/docs/index.rst @@ -18,6 +18,7 @@ Client-side, this consists of: :maxdepth: 5 :titlesonly: + start/index concepts/index collection/index data/index diff --git a/toolkit/components/telemetry/docs/start/adding-a-new-probe.rst b/toolkit/components/telemetry/docs/start/adding-a-new-probe.rst new file mode 100644 index 000000000000..e443301cd35b --- /dev/null +++ b/toolkit/components/telemetry/docs/start/adding-a-new-probe.rst @@ -0,0 +1,148 @@ +============================ +Adding a new Telemetry probe +============================ + +In Firefox, the Telemetry system collects various measures of Firefox performance, hardware, usage and customizations and submit it to Mozilla. This article provides an overview of what is needed to add any new Telemetry data collection. + +.. important:: + + Every new data collection in Firefox needs a `data collection review `_ from a data collection peer. Just set the feedback? flag for one of the data peers. They try to reply within a business day. + +What is your goal? +================== + +We have various :doc:`data collection tools <../collection/index>` available, each serving different needs. Before diving right into technical details, it is best to take a step back and consider what you need to achieve. + +Your goal could be to answer product questions like “how many people use feature X?” or “what is the error rate of service Y?”. +You could also be focused more on answering engineering questions, say “which web features are most used?” or “how is the performance of engine Z?”. + +From there, questions you should ask are: + +- What is the minimum data that can answer your questions? +- How many people do you need this data from? +- Is data from the pre-release channels sufficient? + +This also informs the `data collection review `_, which requires a plan for how to use the data. Data collection review is required for all new data collection. + +Data collection levels +====================== + +Most of our data collection falls into one of two levels, *release* and *pre-release*. + +**Release data** is recorded by default on all channels, users need to explicitly opt out to disable it. This has `stricter constraints `_ for what data we can collect. "Most" users submit this data. + +**Pre-release data** is not recorded on release, but is collected by default on our pre-release channels (Beta and Nightly), so it can be biased. + +These levels cover what is described in the `Firefox privacy notice `_. For other needs, there might be custom mechanisms that clearly require user opt-in and show what data is collected. + +Rich data & aggregate data +========================== + +For the recording and transmission of data, we have various data types available. We can divide these data types into two large groups. + +**Aggregate data** is aggregated on the client-side and cheap to send, process and analyze. This could e.g. be a simple count of tab opens or a histogram showing how long it takes to switch between tabs. This should be your default choice and is well supported in our analysis tools. + +**Rich data** is used when questions can not be answered from aggregate data. When we send more detailed data we can e.g. see when a specific UI interaction happened and in which context. + +As a general rule, you can inform the choice of data types from your goals like this: + ++------------------------+-----------------+-----------------------+ +| Goals | Collection type | Implementation | ++========================+=================+=======================+ +| On-going monitoring | Aggregate data | Histograms | +| | | | +| Health tracking | | Scalars | +| | | | +| KPI impact | | Environment data | ++------------------------+-----------------+-----------------------+ +| Detailed user behavior | Rich data | Event Telemetry | +| | | | +| Funnel analysis | | Detailed custom pings | +| | | | +| Diagnostics | | Logs | +| | | | +| | | Crash data | ++------------------------+-----------------+-----------------------+ + +Aggregate data +-------------- + +Most of our data collection happens through :doc:`scalars <../collection/scalars>` and :doc:`histograms <../collection/histograms>`: + +- Scalars allow collection of simple values, like counts, booleans and strings. +- Histograms allow collection of multiple different values, but aggregate them into a number of buckets. Each bucket has a value range and a count of how many values we recorded. + +Both scalars & histograms allow recording by keys. This allows for more flexible, two-level data collection. + +Other collections can build on top of scalars & histograms. An example is :doc:`use counters <../collection/use-counters>`, which submit web feature usage through histograms. + +We also collect :doc:`environment data <../data/environment>`. This consists of mostly scalar values that capture the “working environment” a Firefox session lives in, and includes e.g. data on hardware, OS, add-ons and some settings. Any data that is part of the "working environment", or needs to split :doc:`subsessions <../concepts/sessions>`, should go into it. + +Rich data +--------- + +Aggregate data can tell you that something happened, but is usually lacking details about what exactly. When more details are needed, we can collect them using other tools that submit less efficient data. This usually means that we can't enable the data collection for all users, for cost and performance concerns. + +There are multiple mechanisms to collect rich data: + +**Stack collection** helps with e.g. diagnosing hangs. Stack data is recorded into chrome hangs and threadhang stats. To diagnose where rarely used code is called from, you can use stack capturing. + +:doc:`Event Telemetry <../collection/events>` provides a way to record both when and what happened. This enables e.g. funnel analysis for usage. + +:doc:`Custom pings <../collection/custom-pings>` are used when other existing data collection does not cover your need. Submitting a custom ping enables you to submit your own JSON package that will be delivered to the Telemetry servers. However, this loses you access to existing tooling and makes it harder to join your data with other sources. + +Setup & building +================ + +Every build of Firefox has Telemetry enabled. Local developer builds with no custom build flags will record all Telemetry data, but not send it out. + +When adding any new scalar, histogram or event Firefox needs to be built. Artifact builds are currently not supported, even if code changes are limited to JavaScript. + +Usually you don't need to send out data to add new Telemetry. In the rare event you do, you need the following in your *.mozconfig*:: + + MOZ_TELEMETRY_REPORTING=1 + MOZILLA_OFFICIAL=1 + +Testing +======= + +Local confirmation +------------------ + +Your first step should always be to confirm your new data collection locally. + +The *about:telemetry* page allows to view any data you submitted to Telemetry in the last 60 days, whether it is in existing pings or in new custom pings. You can choose which pings to display on the top-left. + +If you need to confirm when - or if - pings are getting sent, you can run an instance of the `gzipServer `_ locally. It emulates roughly how the official Telemetry servers respond, and saves all received pings to disk for inspection. + +Test coverage +------------- + +Any data collection that you need to base decisions on needs to have test coverage. Using JS, you can access the recorded values for your data collection. You can use the following functions: + +- for scalars, `snapshotScalars() `_ or `snapshotKeyedScalars() `_ +- `histogram.snapshot()` for `histograms `_ or `keyed histograms `_ +- for events, `snapshotBuiltinEvents() `_ + +If you need to test that pings were correctly passed to Telemetry, you can use `TelemetryArchiveTesting `_. + +Validation +---------- + +While it's important to confirm that the data collection works on your machine, the Firefox user population is very diverse. Before basing decisions on any new data, it should be validated. This could take various forms. + +For *new data collection* using existing Telemetry data types, the transport mechanism is already tested. It is sufficient to validate the incoming values. This could happen through `Redash `_ or through `custom analysis `_. + +For *new custom pings*, you'll want to check schema validation results, as well as that the contents look valid. + +Getting help +============ + +You can find all important Telemetry resources listed on `telemetry.mozilla.org `_. + +The Telemetry team is there to help with any problems. You can reach us via: + +- IRC in `#telemetry `_ +- Slack in `#fx-metrics `_ +- the `fx-data-dev mailing list `_ +- flags for `one of the peers `_ on Bugzilla or send us an e-mail diff --git a/toolkit/components/telemetry/docs/start/index.rst b/toolkit/components/telemetry/docs/start/index.rst new file mode 100644 index 000000000000..80dd56a694cd --- /dev/null +++ b/toolkit/components/telemetry/docs/start/index.rst @@ -0,0 +1,10 @@ +=============== +Getting started +=============== + +.. toctree:: + :maxdepth: 2 + :titlesonly: + :glob: + + adding-a-new-probe From c27f04ab204642c232a4e4fd59b39b70d099a7ea Mon Sep 17 00:00:00 2001 From: Thomas Duellmann Date: Thu, 4 Jan 2018 13:50:30 +0200 Subject: [PATCH 26/28] Bug 106327 - Change shortcut label of VK_RETURN to "Enter" on Win/Unix. r=enndeakin, r=Gijs --- layout/xul/nsMenuFrame.cpp | 8 ++++--- .../mac/platformKeys.properties | 23 +++++++++++-------- .../unix/platformKeys.properties | 23 +++++++++++-------- .../win/platformKeys.properties | 23 +++++++++++-------- .../en-US/chrome/global/keys.properties | 1 - toolkit/modules/ShortcutUtils.jsm | 6 +++-- 6 files changed, 51 insertions(+), 33 deletions(-) diff --git a/layout/xul/nsMenuFrame.cpp b/layout/xul/nsMenuFrame.cpp index 271185de0c2f..3d789850fd53 100644 --- a/layout/xul/nsMenuFrame.cpp +++ b/layout/xul/nsMenuFrame.cpp @@ -1105,9 +1105,11 @@ nsMenuFrame::BuildAcceleratorText(bool aNotify) mozilla::services::GetStringBundleService(); if (bundleService) { nsCOMPtr bundle; - rv = bundleService->CreateBundle("chrome://global/locale/keys.properties", - getter_AddRefs(bundle)); - + rv = bundleService->CreateBundle( + (keyCode == "VK_RETURN" ? + "chrome://global-platform/locale/platformKeys.properties" + : "chrome://global/locale/keys.properties"), + getter_AddRefs(bundle)); if (NS_SUCCEEDED(rv) && bundle) { nsAutoString keyName; rv = bundle->GetStringFromName(NS_ConvertUTF16toUTF8(keyCode).get(), diff --git a/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties b/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties index 39f3d62e8306..725e97744126 100644 --- a/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties +++ b/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties @@ -2,24 +2,29 @@ # 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/. -#mac -#this file defines the on screen display names for the various modifier keys -#these are used in XP menus to show keyboard shortcuts +# Platform: Mac +# This file defines the on-screen display names for the various modifier keys +# and the Return key (VK_RETURN). +# These are used in XP menus to show keyboard shortcuts. -#the shift key - open up arrow symbol (ctrl-e) +# The Shift key - open up arrow symbol (ctrl-e) VK_SHIFT=\u21e7 -#the command key - clover leaf symbol (ctrl-q) +# The Command key - clover leaf symbol (ctrl-q) VK_META=\u2318 -#the win key - never generated by native key event +# The Win key - never generated by native key event VK_WIN=win -#the option/alt key - splitting tracks symbol (ctrl-g) +# The Option/Alt key - splitting tracks symbol (ctrl-g) VK_ALT=\u2325 -#the control key. hat symbol (ctrl-f) +# The Control key - hat symbol (ctrl-f) VK_CONTROL=\u2303 -#the separator character used between modifiers (none on Mac OS) +# The Return key (on the main keyboard or numpad): +# "Enter" on Windows/Unix, "Return" on Mac +VK_RETURN=Return + +# The separator character used between modifiers (none on Mac OS) MODIFIER_SEPARATOR= diff --git a/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties b/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties index 53321356e0b2..3a1394d87173 100644 --- a/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties +++ b/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties @@ -2,24 +2,29 @@ # 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/. -#default -#this file defines the on screen display names for the various modifier keys -#these are used in XP menus to show keyboard shortcuts +# Platform: Unix +# This file defines the on-screen display names for the various modifier keys +# and the Enter key (VK_RETURN). +# These are used in XP menus to show keyboard shortcuts. -#the shift key +# The Shift key VK_SHIFT=Shift -#the command key +# The Command key VK_META=Meta -#the win key (Super key and Hyper keys are mapped to DOM Win key) +# The Win key (Super key and Hyper keys are mapped to DOM Win key) VK_WIN=Win -#the alt key +# The Alt key VK_ALT=Alt -#the control key +# The Control key VK_CONTROL=Ctrl -#the separator character used between modifiers +# The Enter key (on the main keyboard or numpad): +# "Enter" on Windows/Unix, "Return" on Mac +VK_RETURN=Enter + +# The separator character used between modifiers MODIFIER_SEPARATOR=+ diff --git a/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties b/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties index 307eeaf195ca..e05354c9ae07 100644 --- a/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties +++ b/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties @@ -2,24 +2,29 @@ # 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/. -#default -#this file defines the on screen display names for the various modifier keys -#these are used in XP menus to show keyboard shortcuts +# Platform: Windows +# This file defines the on-screen display names for the various modifier keys +# and the Enter key (VK_RETURN). +# These are used in XP menus to show keyboard shortcuts. -#the shift key +# The Shift key VK_SHIFT=Shift -#the command key +# The Command key VK_META=Meta -#the win key +# The Win key VK_WIN=Win -#the alt key +# The Alt key VK_ALT=Alt -#the control key +# The Control key VK_CONTROL=Ctrl -#the separator character used between modifiers +# The Enter key (on the main keyboard or numpad): +# "Enter" on Windows/Unix, "Return" on Mac +VK_RETURN=Enter + +# The separator character used between modifiers MODIFIER_SEPARATOR=+ diff --git a/toolkit/locales/en-US/chrome/global/keys.properties b/toolkit/locales/en-US/chrome/global/keys.properties index 1137bf7c6189..03794367d5a4 100644 --- a/toolkit/locales/en-US/chrome/global/keys.properties +++ b/toolkit/locales/en-US/chrome/global/keys.properties @@ -57,7 +57,6 @@ VK_PAGE_DOWN=Page Down # otherwise you should probably just translate the glyph regions # LOCALIZATION NOTE : BLOCK maybe GLYPHS -VK_RETURN=Return VK_TAB=Tab VK_BACK=Backspace VK_DELETE=Del diff --git a/toolkit/modules/ShortcutUtils.jsm b/toolkit/modules/ShortcutUtils.jsm index 0a6e495c31c7..a5a8de0de787 100644 --- a/toolkit/modules/ShortcutUtils.jsm +++ b/toolkit/modules/ShortcutUtils.jsm @@ -88,9 +88,11 @@ var ShortcutUtils = { let key; let keyCode = aElemKey.getAttribute("keycode"); if (keyCode) { + keyCode = keyCode.toUpperCase(); try { - // Some keys might not exist in the locale file, which will throw: - key = Keys.GetStringFromName(keyCode.toUpperCase()); + let bundle = keyCode == "VK_RETURN" ? PlatformKeys : Keys; + // Some keys might not exist in the locale file, which will throw. + key = bundle.GetStringFromName(keyCode); } catch (ex) { Cu.reportError("Error finding " + keyCode + ": " + ex); key = keyCode.replace(/^VK_/, ""); From b88f05e8930bb8039883399449e06382c9df421b Mon Sep 17 00:00:00 2001 From: Andreea Pavel Date: Fri, 5 Jan 2018 04:46:46 +0200 Subject: [PATCH 27/28] Backed out changeset 3a55b10a6974 (bug 106327) for build bustage on /builds/worker/workspace/build/src/layout/xul/nsMenuFrame.cpp r=backout a=backout on a CLOSED TREE --HG-- extra : amend_source : e09bf154093728898ad2c27dd185108f9ff3b009 --- layout/xul/nsMenuFrame.cpp | 8 +++---- .../mac/platformKeys.properties | 23 ++++++++----------- .../unix/platformKeys.properties | 23 ++++++++----------- .../win/platformKeys.properties | 23 ++++++++----------- .../en-US/chrome/global/keys.properties | 1 + toolkit/modules/ShortcutUtils.jsm | 6 ++--- 6 files changed, 33 insertions(+), 51 deletions(-) diff --git a/layout/xul/nsMenuFrame.cpp b/layout/xul/nsMenuFrame.cpp index 3d789850fd53..271185de0c2f 100644 --- a/layout/xul/nsMenuFrame.cpp +++ b/layout/xul/nsMenuFrame.cpp @@ -1105,11 +1105,9 @@ nsMenuFrame::BuildAcceleratorText(bool aNotify) mozilla::services::GetStringBundleService(); if (bundleService) { nsCOMPtr bundle; - rv = bundleService->CreateBundle( - (keyCode == "VK_RETURN" ? - "chrome://global-platform/locale/platformKeys.properties" - : "chrome://global/locale/keys.properties"), - getter_AddRefs(bundle)); + rv = bundleService->CreateBundle("chrome://global/locale/keys.properties", + getter_AddRefs(bundle)); + if (NS_SUCCEEDED(rv) && bundle) { nsAutoString keyName; rv = bundle->GetStringFromName(NS_ConvertUTF16toUTF8(keyCode).get(), diff --git a/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties b/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties index 725e97744126..39f3d62e8306 100644 --- a/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties +++ b/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties @@ -2,29 +2,24 @@ # 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/. -# Platform: Mac -# This file defines the on-screen display names for the various modifier keys -# and the Return key (VK_RETURN). -# These are used in XP menus to show keyboard shortcuts. +#mac +#this file defines the on screen display names for the various modifier keys +#these are used in XP menus to show keyboard shortcuts -# The Shift key - open up arrow symbol (ctrl-e) +#the shift key - open up arrow symbol (ctrl-e) VK_SHIFT=\u21e7 -# The Command key - clover leaf symbol (ctrl-q) +#the command key - clover leaf symbol (ctrl-q) VK_META=\u2318 -# The Win key - never generated by native key event +#the win key - never generated by native key event VK_WIN=win -# The Option/Alt key - splitting tracks symbol (ctrl-g) +#the option/alt key - splitting tracks symbol (ctrl-g) VK_ALT=\u2325 -# The Control key - hat symbol (ctrl-f) +#the control key. hat symbol (ctrl-f) VK_CONTROL=\u2303 -# The Return key (on the main keyboard or numpad): -# "Enter" on Windows/Unix, "Return" on Mac -VK_RETURN=Return - -# The separator character used between modifiers (none on Mac OS) +#the separator character used between modifiers (none on Mac OS) MODIFIER_SEPARATOR= diff --git a/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties b/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties index 3a1394d87173..53321356e0b2 100644 --- a/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties +++ b/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties @@ -2,29 +2,24 @@ # 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/. -# Platform: Unix -# This file defines the on-screen display names for the various modifier keys -# and the Enter key (VK_RETURN). -# These are used in XP menus to show keyboard shortcuts. +#default +#this file defines the on screen display names for the various modifier keys +#these are used in XP menus to show keyboard shortcuts -# The Shift key +#the shift key VK_SHIFT=Shift -# The Command key +#the command key VK_META=Meta -# The Win key (Super key and Hyper keys are mapped to DOM Win key) +#the win key (Super key and Hyper keys are mapped to DOM Win key) VK_WIN=Win -# The Alt key +#the alt key VK_ALT=Alt -# The Control key +#the control key VK_CONTROL=Ctrl -# The Enter key (on the main keyboard or numpad): -# "Enter" on Windows/Unix, "Return" on Mac -VK_RETURN=Enter - -# The separator character used between modifiers +#the separator character used between modifiers MODIFIER_SEPARATOR=+ diff --git a/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties b/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties index e05354c9ae07..307eeaf195ca 100644 --- a/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties +++ b/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties @@ -2,29 +2,24 @@ # 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/. -# Platform: Windows -# This file defines the on-screen display names for the various modifier keys -# and the Enter key (VK_RETURN). -# These are used in XP menus to show keyboard shortcuts. +#default +#this file defines the on screen display names for the various modifier keys +#these are used in XP menus to show keyboard shortcuts -# The Shift key +#the shift key VK_SHIFT=Shift -# The Command key +#the command key VK_META=Meta -# The Win key +#the win key VK_WIN=Win -# The Alt key +#the alt key VK_ALT=Alt -# The Control key +#the control key VK_CONTROL=Ctrl -# The Enter key (on the main keyboard or numpad): -# "Enter" on Windows/Unix, "Return" on Mac -VK_RETURN=Enter - -# The separator character used between modifiers +#the separator character used between modifiers MODIFIER_SEPARATOR=+ diff --git a/toolkit/locales/en-US/chrome/global/keys.properties b/toolkit/locales/en-US/chrome/global/keys.properties index 03794367d5a4..1137bf7c6189 100644 --- a/toolkit/locales/en-US/chrome/global/keys.properties +++ b/toolkit/locales/en-US/chrome/global/keys.properties @@ -57,6 +57,7 @@ VK_PAGE_DOWN=Page Down # otherwise you should probably just translate the glyph regions # LOCALIZATION NOTE : BLOCK maybe GLYPHS +VK_RETURN=Return VK_TAB=Tab VK_BACK=Backspace VK_DELETE=Del diff --git a/toolkit/modules/ShortcutUtils.jsm b/toolkit/modules/ShortcutUtils.jsm index a5a8de0de787..0a6e495c31c7 100644 --- a/toolkit/modules/ShortcutUtils.jsm +++ b/toolkit/modules/ShortcutUtils.jsm @@ -88,11 +88,9 @@ var ShortcutUtils = { let key; let keyCode = aElemKey.getAttribute("keycode"); if (keyCode) { - keyCode = keyCode.toUpperCase(); try { - let bundle = keyCode == "VK_RETURN" ? PlatformKeys : Keys; - // Some keys might not exist in the locale file, which will throw. - key = bundle.GetStringFromName(keyCode); + // Some keys might not exist in the locale file, which will throw: + key = Keys.GetStringFromName(keyCode.toUpperCase()); } catch (ex) { Cu.reportError("Error finding " + keyCode + ": " + ex); key = keyCode.replace(/^VK_/, ""); From c3da3e7642d3deb449477003fe3cab5916802fbb Mon Sep 17 00:00:00 2001 From: Myk Melez Date: Thu, 4 Jan 2018 21:37:47 -0800 Subject: [PATCH 28/28] Bug 1379338 - scriptify preferences XBL; r=jaws MozReview-Commit-ID: Egyzs2KxhzH --- browser/base/content/sanitize.xul | 52 +- browser/base/content/sanitizeDialog.js | 63 +- .../test/general/browser_sanitizeDialog.js | 2 +- browser/base/content/utilityOverlay.js | 2 +- .../preferences/applicationManager.xul | 2 + browser/components/preferences/colors.js | 15 + browser/components/preferences/colors.xul | 51 +- browser/components/preferences/connection.js | 105 +- browser/components/preferences/connection.xul | 79 +- browser/components/preferences/fonts.js | 26 +- browser/components/preferences/fonts.xul | 54 +- .../preferences/in-content/containers.xul | 8 - .../components/preferences/in-content/main.js | 286 +++- .../preferences/in-content/main.xul | 239 --- .../preferences/in-content/preferences.js | 11 +- .../preferences/in-content/preferences.xul | 6 +- .../preferences/in-content/privacy.js | 163 +- .../preferences/in-content/privacy.xul | 159 -- .../preferences/in-content/search.js | 24 +- .../preferences/in-content/search.xul | 20 - .../components/preferences/in-content/sync.js | 11 + .../preferences/in-content/sync.xul | 27 - .../tests/browser_basic_rebuild_fonts_test.js | 8 +- .../in-content/tests/browser_bug731866.js | 3 +- .../tests/browser_bug795764_cachedisabled.js | 3 - .../in-content/tests/browser_connection.js | 4 +- .../tests/browser_connection_bug388287.js | 12 +- .../in-content/tests/browser_fluent.js | 3 +- .../browser_sanitizeOnShutdown_prefLocked.js | 2 +- .../tests/privacypane_tests_perwindow.js | 6 +- browser/components/preferences/jar.mn | 5 +- browser/components/preferences/languages.js | 21 +- browser/components/preferences/languages.xul | 75 +- browser/components/preferences/sanitize.js | 19 +- browser/components/preferences/sanitize.xul | 50 +- .../lib/ShieldPreferences.jsm | 15 +- .../themes/linux/preferences/preferences.css | 29 +- browser/themes/linux/sanitizeDialog.css | 2 +- .../osx/preferences/in-content/dialog.css | 6 +- .../themes/osx/preferences/preferences.css | 32 +- browser/themes/osx/sanitizeDialog.css | 2 +- .../shared/incontentprefs/dialog.inc.css | 5 +- .../shared/incontentprefs/preferences.inc.css | 7 +- .../windows/preferences/preferences.css | 36 +- browser/themes/windows/sanitizeDialog.css | 2 +- .../tests/unit/test_anonymous_content.py | 2 +- toolkit/content/jar.mn | 2 +- toolkit/content/preferencesBindings.js | 615 +++++++ toolkit/content/resetProfile.xul | 2 +- .../content/tests/chrome/test_preferences.xul | 107 +- .../chrome/test_preferences_beforeaccept.xul | 4 +- .../test_preferences_onsyncfrompreference.xul | 2 +- .../tests/chrome/window_preferences.xul | 49 +- .../tests/chrome/window_preferences2.xul | 18 +- .../tests/chrome/window_preferences3.xul | 52 +- .../window_preferences_beforeaccept.xul | 39 +- .../window_preferences_commandretarget.xul | 28 +- ...indow_preferences_onsyncfrompreference.xul | 36 +- toolkit/content/widgets/dialog.xml | 28 + toolkit/content/widgets/preferences.xml | 1409 ----------------- toolkit/content/xul.css | 50 - toolkit/mozapps/preferences/fontbuilder.js | 4 +- toolkit/themes/linux/global/global.css | 3 +- toolkit/themes/linux/global/jar.mn | 1 - toolkit/themes/linux/global/preferences.css | 62 - toolkit/themes/mobile/jar.mn | 1 - toolkit/themes/osx/global/global.css | 10 +- .../osx/global/icons/panebutton-active.png | Bin 400 -> 0 bytes .../osx/global/icons/panebutton-inactive.png | Bin 257 -> 0 bytes toolkit/themes/osx/global/jar.mn | 3 - toolkit/themes/osx/global/preferences.css | 59 - .../themes/shared/in-content/common.inc.css | 4 - toolkit/themes/windows/global/global.css | 3 +- toolkit/themes/windows/global/jar.mn | 1 - toolkit/themes/windows/global/preferences.css | 76 - 75 files changed, 1638 insertions(+), 2784 deletions(-) create mode 100644 browser/components/preferences/colors.js create mode 100644 toolkit/content/preferencesBindings.js delete mode 100644 toolkit/content/widgets/preferences.xml delete mode 100644 toolkit/themes/linux/global/preferences.css delete mode 100644 toolkit/themes/osx/global/icons/panebutton-active.png delete mode 100644 toolkit/themes/osx/global/icons/panebutton-inactive.png delete mode 100644 toolkit/themes/osx/global/preferences.css delete mode 100644 toolkit/themes/windows/global/preferences.css diff --git a/browser/base/content/sanitize.xul b/browser/base/content/sanitize.xul index 0bdb9cac29ec..922d375f1819 100644 --- a/browser/base/content/sanitize.xul +++ b/browser/base/content/sanitize.xul @@ -6,54 +6,48 @@ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + - + + %preferencesDTD; + %globalKeysDTD; %brandDTD; %sanitizeDTD; ]> - + - + - - - - - - - - - - + @@ -69,5 +60,5 @@ - - + + diff --git a/toolkit/content/tests/chrome/window_preferences2.xul b/toolkit/content/tests/chrome/window_preferences2.xul index 87158c9c7c24..7a1fa3bea783 100644 --- a/toolkit/content/tests/chrome/window_preferences2.xul +++ b/toolkit/content/tests/chrome/window_preferences2.xul @@ -3,23 +3,25 @@ - + - - + + diff --git a/toolkit/content/tests/chrome/window_preferences3.xul b/toolkit/content/tests/chrome/window_preferences3.xul index c37893a678b5..7e8bc26bf122 100644 --- a/toolkit/content/tests/chrome/window_preferences3.xul +++ b/toolkit/content/tests/chrome/window_preferences3.xul @@ -3,13 +3,15 @@ - + - - - - - - - - - - - + - - + + diff --git a/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul b/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul index ba200b614947..df9b65146f3d 100644 --- a/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul +++ b/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul @@ -3,18 +3,20 @@ - + - - - - - - + + - + diff --git a/toolkit/content/tests/chrome/window_preferences_commandretarget.xul b/toolkit/content/tests/chrome/window_preferences_commandretarget.xul index 77c6fd18ce71..bcea54cdac90 100644 --- a/toolkit/content/tests/chrome/window_preferences_commandretarget.xul +++ b/toolkit/content/tests/chrome/window_preferences_commandretarget.xul @@ -5,11 +5,13 @@ a checkbox with a command attribute properly updates even though the command event gets retargeted. --> - + + - - - - - + - - + + diff --git a/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul b/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul index e0366f989523..d5418c1b7481 100644 --- a/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul +++ b/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul @@ -8,24 +8,24 @@ This test ensures that onsyncfrompreference handlers are called after all the values of the corresponding preference element have been set correctly --> - + - - - - - - - + + + - + diff --git a/toolkit/content/widgets/dialog.xml b/toolkit/content/widgets/dialog.xml index 73356dec1c6b..2a6064e48ee6 100644 --- a/toolkit/content/widgets/dialog.xml +++ b/toolkit/content/widgets/dialog.xml @@ -3,6 +3,10 @@ - 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/. --> + + %globalKeysDTD; +]>