From 3f625686df592043ceae3ea2fac409f2c4f3cac7 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Tue, 2 Jan 2024 22:59:35 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1157064 - implementation of font-display. r=heycam,khuey (43fe566f45) - Bug 1235186 - fix small userfont logging nit. r=m_kato (d40bead913) - Bug 1188802 - only rebuild local webfont rules when needed. r=heycam (f74200aeb2) - Backout unrelated code landed in dee3e26cc1c0 by mistake. (5d254b78b6) - Bug 1236506: Add support for "-webkit-filter" as an alias for CSS property "filter". r=heycam (1e7ac6554a) - Bug 1230426 - Remove support for -webkit-border-image longhand CSS property aliases. r=dholbert (a1a2d5e82a) - Bug 1246101 - Restore some auto-completion for the align-/justify-* properties. r=dholbert (a33dd2e7c2) - Bug 1195142 patch 1 - Set CSS_PROPERTY_CREATES_STACKING_CONTEXT for the opacity property. r=BenWa (e547f7b420) - Bug 1195142 patch 2 - Add reftests for will-change creating a stacking context. r=BenWa (3bb9dc17b9) - Bug 1195142 patch 3 - Link to correct specification URLs so the CSSWG test suite system is happy. (a8121cdcf0) - Bug 1234966 - nsStylePosition::MaxDifference should include nsChangeHint_NeutralChange because CalcDiffrence returns it. r=heycam (aa0bf89e54) - Bug 1244166: Don't ignore stroke/fill properties in high-contrast mode, since doing so can produce icons that are invisible or whose colors are unrelated to the user's chosen high-contrast colors. r=longsonr (6448b05118) - Bug 1157057 - Rewrite the handling of the nsITimer object in nrappkitTimerCallback; r=ekr (7cc88409b0) - Bug 1117984: added proxy connection state enum. r=bwc (0c643ff34a) - Bug 1231971 - Refactor the NAT simulator to use e10s sockets when appropriate. r=drno (c0722c431b) - Bug 1231973 - Allow NAT simulator to be enabled with the pref system. r=drno (c92ca4fefa) - Bug 1201209 - Extend the timeout on socket readiness in test_nr_socket_unittest. r=drno (e9e5400902) - Bug 1216815 - fix memory leaks in test TCP STUN server. r=mjf (11219f41fc) - Bug 1194385 - Add new unit tests which demonstrate the current behavior. r=bwc (900c621491) - crashreporte (2ac99868b6) - Bug 1150966: Check whether |streams_| is null on stats methods in NrIceMediaStream. r=drno (130a9ac2da) - Bug 1241690: reduce logging output for unconnected PCs. r=bwc (aa236d7184) - Bug 1224845 - close sockets on errors and don't connect to IPv4 TURN TCP from IPv6 sockets. r=jesup (f128a67692) - Bug 1189961 - added DNS AAAA convertion to nICEr transport addr. r=bwc (30c14fe7dd) - Bug 1247536 - Fix -Wunreachable-code warning in media/mtransport/. r=drno (f6768f8539) - Bug 1194259: nsresult != NS_IMETHODIMP rs=bustage (3a922e6e14) - Bug 1237909 part 1 - Remove unused TransportLayer::RunOnThread function. r=bwc (d2d219d63a) - Bug 1237909 part 2 - Do not return value from task for sync dispatch. r=froydnj (c5ec2aecfc) - Bug 1245035 - Move LOCAL_INCLUDES to moz.build in media/omx-plugin/lib/ics/libvideoeditorplayer. r=mshal (54c363c9f7) - Bug 1232069 - Check box sizes before alloc©. r=jya (86cfe660e7) - Bug 1234778: Mark all audio frames as keyframes. r=kentuckyfriedtakahe (5e4f1b54d5) - Bug 1231169 - report rust mp4parse track status in telemetry. r=kinetik,vladan (260d0fed99) - Bug 1238420 - Update mp4parse-rust invocations in MP4Metadata to match CAPI changes. r=rillian (64c5d6a1ef) - Bug 1238420 - Report mp4parse-rust errors via Telemetry. r=rillian,vladan (ff72f8dead) - Bug 1219452 - Update script for rust mp4parser. r=kinetik (9abc268b60) - Bug 1220754 - Update rust mp4parse import script for v0.1.3. r=kinetik (7185657598) - Bug 1224785, Part 1 - Implement alert favicons backend. r=wchen (665c44b0cb) - Bug 1224785, Part 2 - Show the site favicon in OS X notifications. r=mstange (814ff022ba) - Bug 1224785, Part 3 - Don't include ShowWith{Icon}Backend on Android. r=me (fe323c2960) - Bug 1243418 - Fix up incorrect 'aOverwrite' usage and impl in GLUploadHelpers r=jgilbert (67677b4921) - clarify comment (88003aaf96) - Bug 1204284: Show paper size options in OS X print dialog. r=smichaud (8bb40b4349) - Bug 1214511 - Show copies, page range selection, and more on the expanded OSX print dialog. r=mstange (301d5cdccc) - Bug 1216478 - prefer tooltiptext on a XUL element over title attribute on a containing toolbaritem when determining accessible name, r=surkov (ec1dfcad37) - Bug 1248838 - ARIA owns change may fail, r=yzen (d183be3f3c) - Bug 1222531 - turn off -Wextra-tokens on clang-cl in accessible/ directories; r=tbsaunde (6dd4dcae20) - bug 1241453 - add DocAccessibleParent::GetXPCAccessible() r=davidb (f243398399) - Bug 1087608 - eliminating a pref observer leak and fixing test timeout overflow that cause intermittents. r=eeejay (413354c349) - Bug 1238368 - Re-introduce workaround for Android tap gesture. r=yzen (04bb9cea5a) - Bug 1233863 - ARM64: Disable tests that require ion.enable = 1. r=jimb (b268c03c22) - Bug 1191976 - Intentionally crash if we hit an IPC FatalError in the parent process. r=billm (b6e9d90d34) - Bug 1194721: Add |DaemonRunnable8|, r=shuang (0b293cb8a5) - Bug 1194721: Add PDU_ prefix to daemon PDU constants, r=shuang (834240b14b) - Bug 1228546 - Implement peripheral mode support for GATT API. r=brsun, r=mrbkap (01a711cac6) - Bug 1194721: Add helpers for Gonk sensors daemon, r=gsvelto (524d1d6792) --- accessible/generic/Accessible.cpp | 55 +++- accessible/generic/Accessible.h | 5 + accessible/generic/DocAccessible.cpp | 11 +- accessible/interfaces/ia2/moz.build | 8 + accessible/interfaces/msaa/moz.build | 8 + accessible/ipc/DocAccessibleParent.cpp | 9 + accessible/ipc/DocAccessibleParent.h | 3 + accessible/jsat/AccessFu.jsm | 15 +- accessible/jsat/Gestures.jsm | 25 +- accessible/tests/mochitest/common.js | 21 ++ accessible/tests/mochitest/jsat/dom_helper.js | 24 +- accessible/tests/mochitest/jsat/gestures.json | 20 +- accessible/tests/mochitest/jsat/jsatcommon.js | 35 ++- accessible/tests/mochitest/jsat/output.js | 2 +- .../mochitest/jsat/test_live_regions.html | 2 +- .../mochitest/jsat/test_quicknav_modes.html | 2 +- accessible/tests/mochitest/name/a11y.ini | 1 + .../tests/mochitest/name/test_toolbaritem.xul | 84 ++++++ .../mochitest/treeupdate/test_ariaowns.html | 46 ++- accessible/windows/ia2/moz.build | 8 + accessible/windows/msaa/moz.build | 8 + .../BluetoothDaemonGattInterface.cpp | 37 ++- .../bluedroid/BluetoothDaemonGattInterface.h | 15 +- .../bluedroid/BluetoothGattManager.cpp | 283 +++++++++++++++++- .../bluedroid/BluetoothGattManager.h | 13 + .../bluedroid/BluetoothServiceBluedroid.cpp | 43 +++ .../bluedroid/BluetoothServiceBluedroid.h | 14 + dom/bluetooth/bluez/BluetoothDBusService.cpp | 21 ++ dom/bluetooth/bluez/BluetoothDBusService.h | 14 + dom/bluetooth/common/BluetoothCommon.h | 56 ++++ dom/bluetooth/common/BluetoothInterface.h | 9 +- dom/bluetooth/common/BluetoothService.h | 17 ++ dom/bluetooth/common/BluetoothUtils.cpp | 49 +++ dom/bluetooth/common/BluetoothUtils.h | 14 + .../common/webapi/BluetoothGattServer.cpp | 189 ++++++++++++ .../common/webapi/BluetoothGattServer.h | 18 ++ dom/bluetooth/ipc/BluetoothMessageUtils.h | 30 ++ dom/bluetooth/ipc/BluetoothParent.cpp | 43 +++ dom/bluetooth/ipc/BluetoothParent.h | 9 + .../ipc/BluetoothServiceChildProcess.cpp | 25 ++ .../ipc/BluetoothServiceChildProcess.h | 14 + dom/bluetooth/ipc/PBluetooth.ipdl | 21 ++ dom/webidl/BluetoothGattServer.webidl | 76 +++++ dom/webidl/FontFace.webidl | 2 + gfx/gl/GLTextureImage.cpp | 6 +- gfx/gl/GLUploadHelpers.cpp | 8 +- gfx/gl/GLUploadHelpers.h | 4 +- gfx/gl/TextureImageEGL.cpp | 3 +- gfx/thebes/gfxUserFontSet.cpp | 46 ++- gfx/thebes/gfxUserFontSet.h | 22 +- hal/gonk/GonkSensorsHelpers.cpp | 112 +++++++ hal/gonk/GonkSensorsHelpers.h | 226 ++++++++++++++ hal/gonk/SensorsTypes.h | 140 +++++++++ hal/moz.build | 1 + ipc/glue/ProtocolUtils.cpp | 24 +- ipc/hal/DaemonRunnables.h | 88 ++++++ ipc/hal/DaemonSocket.cpp | 2 +- ipc/hal/DaemonSocketPDU.cpp | 26 +- ipc/hal/DaemonSocketPDU.h | 12 +- ipc/hal/DaemonSocketPDUHelpers.h | 166 ++++++++++ js/src/jit-test/lib/jitopts.js | 6 + js/src/jit/shared/CodeGenerator-shared.h | 1 - .../reftests/w3c-css/submitted/reftest.list | 3 + .../green-square-100-by-100-ref.html | 12 + .../submitted/will-change/reftest.list | 12 + ...l-change-stacking-context-clip-path-1.html | 21 ++ ...will-change-stacking-context-filter-1.html | 21 ++ ...will-change-stacking-context-height-1.html | 20 ++ ...l-change-stacking-context-isolation-1.html | 21 ++ .../will-change-stacking-context-mask-1.html | 21 ++ ...nge-stacking-context-mix-blend-mode-1.html | 21 ++ ...ill-change-stacking-context-opacity-1.html | 21 ++ ...change-stacking-context-perspective-1.html | 21 ++ ...ll-change-stacking-context-position-1.html | 21 ++ ...l-change-stacking-context-transform-1.html | 21 ++ ...ge-stacking-context-transform-style-1.html | 21 ++ ...ill-change-stacking-context-z-index-1.html | 21 ++ layout/style/FontFace.cpp | 26 +- layout/style/FontFace.h | 7 +- layout/style/FontFaceSet.cpp | 33 +- layout/style/FontFaceSet.h | 3 +- layout/style/nsCSSPropAliasList.h | 24 +- layout/style/nsCSSPropList.h | 34 +-- layout/style/nsCSSProps.cpp | 57 ++++ layout/style/nsCSSProps.h | 8 +- layout/style/nsFontFaceLoader.cpp | 130 ++++++-- layout/style/nsFontFaceLoader.h | 3 + layout/style/nsStyleStruct.h | 3 +- layout/style/test/descriptor_database.js | 5 + layout/style/test/property_database.js | 42 +-- .../style/test/test_descriptor_storage.html | 28 +- layout/style/test/test_font_loading_api.html | 21 +- media/libstagefright/binding/Box.cpp | 8 +- media/libstagefright/binding/Index.cpp | 4 +- media/libstagefright/binding/MP4Metadata.cpp | 33 +- media/libstagefright/binding/MoofParser.cpp | 4 +- .../binding/byteorder-mod.patch | 37 +++ .../binding/include/mp4_demuxer/Box.h | 2 + .../libstagefright/binding/mp4parse-mod.patch | 13 + media/libstagefright/binding/update-rust.sh | 37 +++ media/mtransport/nr_socket_prsock.cpp | 49 ++- media/mtransport/nr_socket_prsock.h | 7 +- media/mtransport/nr_timer.cpp | 22 +- media/mtransport/nricectx.cpp | 68 ++++- media/mtransport/nricectx.h | 20 +- media/mtransport/nricemediastream.cpp | 29 ++ media/mtransport/test/ice_unittest.cpp | 13 +- media/mtransport/test/mtransport_test_utils.h | 27 ++ .../test/multi_tcp_socket_unittest.cpp | 75 +++++ media/mtransport/test/stunserver.cpp | 5 +- .../test/test_nr_socket_unittest.cpp | 241 ++++++++++++++- media/mtransport/test_nr_socket.cpp | 207 +++++++++---- media/mtransport/test_nr_socket.h | 55 ++-- .../third_party/nICEr/src/ice/ice_component.c | 8 + .../third_party/nICEr/src/ice/ice_socket.c | 9 +- .../nICEr/src/net/nr_proxy_tunnel.c | 44 ++- .../nICEr/src/stun/nr_socket_buffered_stun.c | 12 + media/mtransport/transportlayer.cpp | 15 - media/mtransport/transportlayer.h | 4 - .../lib/ics/libvideoeditorplayer/Makefile.in | 19 -- .../lib/ics/libvideoeditorplayer/moz.build | 4 + modules/libpref/init/all.js | 1 + .../components/alerts/AlertNotification.cpp | 10 + toolkit/components/alerts/nsAlertsService.cpp | 118 +++++++- .../components/alerts/nsIAlertsService.idl | 36 ++- toolkit/components/telemetry/Histograms.json | 27 ++ widget/cocoa/OSXNotificationCenter.h | 4 +- widget/cocoa/OSXNotificationCenter.mm | 24 +- widget/cocoa/nsChildView.mm | 9 +- widget/cocoa/nsCocoaWindow.h | 6 + widget/cocoa/nsPrintDialogX.mm | 5 + xpcom/threads/nsIEventTarget.idl | 4 +- xpcom/threads/nsThread.cpp | 4 +- xpcom/threads/nsThreadSyncDispatch.h | 12 +- 134 files changed, 3808 insertions(+), 522 deletions(-) create mode 100644 accessible/tests/mochitest/name/test_toolbaritem.xul create mode 100644 hal/gonk/GonkSensorsHelpers.cpp create mode 100644 hal/gonk/GonkSensorsHelpers.h create mode 100644 hal/gonk/SensorsTypes.h create mode 100644 layout/reftests/w3c-css/submitted/will-change/green-square-100-by-100-ref.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/reftest.list create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-clip-path-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-filter-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-height-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-isolation-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-mask-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-mix-blend-mode-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-opacity-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-perspective-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-position-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-transform-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-transform-style-1.html create mode 100644 layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-z-index-1.html create mode 100644 media/libstagefright/binding/byteorder-mod.patch create mode 100644 media/libstagefright/binding/mp4parse-mod.patch create mode 100644 media/libstagefright/binding/update-rust.sh delete mode 100644 media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in diff --git a/accessible/generic/Accessible.cpp b/accessible/generic/Accessible.cpp index e0164a9a09..960823ae51 100644 --- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -815,9 +815,17 @@ Accessible::XULElmName(DocAccessible* aDocument, nsIContent *bindingParent = aElm->GetBindingParent(); nsIContent* parent = bindingParent? bindingParent->GetParent() : aElm->GetParent(); + nsAutoString ancestorTitle; while (parent) { if (parent->IsXULElement(nsGkAtoms::toolbaritem) && - parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) { + parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, ancestorTitle)) { + // Before returning this, check if the element itself has a tooltip: + if (aElm->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) { + aName.CompressWhitespace(); + return; + } + + aName.Assign(ancestorTitle); aName.CompressWhitespace(); return; } @@ -2116,6 +2124,51 @@ Accessible::RemoveChild(Accessible* aChild) return true; } +void +Accessible::MoveChild(uint32_t aNewIndex, Accessible* aChild) +{ + MOZ_ASSERT(aChild, "No child was given"); + MOZ_ASSERT(aChild->mParent == this, "A child from different subtree was given"); + MOZ_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given"); + MOZ_ASSERT(static_cast(aChild->mIndexInParent) != aNewIndex, + "No move, same index"); + MOZ_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given"); + +#ifdef DEBUG + // AutoTreeMutation should update group info. + AssertInMutatingSubtree(); +#endif + + mEmbeddedObjCollector = nullptr; + mChildren.RemoveElementAt(aChild->mIndexInParent); + + uint32_t startIdx = aNewIndex, endIdx = aChild->mIndexInParent; + + // If the child is moved after its current position. + if (static_cast(aChild->mIndexInParent) < aNewIndex) { + startIdx = aChild->mIndexInParent; + + if (aNewIndex == mChildren.Length() + 1) { + // The child is moved to the end. + mChildren.AppendElement(aChild); + endIdx = mChildren.Length() - 1; + } + else { + mChildren.InsertElementAt(aNewIndex - 1, aChild); + endIdx = aNewIndex; + } + } + else { + // The child is moved prior its current position. + mChildren.InsertElementAt(aNewIndex, aChild); + } + + for (uint32_t idx = startIdx; idx <= endIdx; idx++) { + mChildren[idx]->mIndexInParent = idx; + mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1; + } +} + Accessible* Accessible::GetChildAt(uint32_t aIndex) const { diff --git a/accessible/generic/Accessible.h b/accessible/generic/Accessible.h index deed3a9575..baf0311909 100644 --- a/accessible/generic/Accessible.h +++ b/accessible/generic/Accessible.h @@ -396,6 +396,11 @@ public: virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild); virtual bool RemoveChild(Accessible* aChild); + /** + * Reallocates the child withing its parent. + */ + void MoveChild(uint32_t aNewIndex, Accessible* aChild); + ////////////////////////////////////////////////////////////////////////////// // Accessible tree traverse methods diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index e4e609527a..c7053a03bf 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -2062,7 +2062,10 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner) } if (child->Parent() == aOwner) { - MoveChild(child, insertIdx - 1); + if (child->IsRelocated()) { + children->RemoveElement(child); + } + MoveChild(child, insertIdx); children->InsertElementAt(arrayIdx, child); arrayIdx++; @@ -2145,9 +2148,7 @@ DocAccessible::MoveChild(Accessible* aChild, int32_t aIdxInParent) reorderEvent->AddSubMutationEvent(hideEvent); AutoTreeMutation mut(parent); - parent->RemoveChild(aChild); - - parent->InsertChildAt(aIdxInParent, aChild); + parent->MoveChild(aIdxInParent, aChild); aChild->SetRelocated(true); FireDelayedEvent(hideEvent); @@ -2178,6 +2179,7 @@ DocAccessible::PutChildrenBack(nsTArray >* aChildren, RefPtr reorderEvent = new AccReorderEvent(owner); RefPtr hideEvent = new AccHideEvent(child, false); reorderEvent->AddSubMutationEvent(hideEvent); + FireDelayedEvent(hideEvent); { AutoTreeMutation mut(owner); @@ -2185,7 +2187,6 @@ DocAccessible::PutChildrenBack(nsTArray >* aChildren, child->SetRelocated(false); } - FireDelayedEvent(hideEvent); MaybeNotifyOfValueChange(owner); FireDelayedEvent(reorderEvent); } diff --git a/accessible/interfaces/ia2/moz.build b/accessible/interfaces/ia2/moz.build index 2454282082..ef01d7be0a 100644 --- a/accessible/interfaces/ia2/moz.build +++ b/accessible/interfaces/ia2/moz.build @@ -17,3 +17,11 @@ OS_LIBS += [ 'ole32', 'oleaut32', ] + +# The Windows MIDL code generator creates things like: +# +# #endif !_MIDL_USE_GUIDDEF_ +# +# which clang-cl complains about. MSVC doesn't, so turn this warning off. +if CONFIG['CLANG_CL']: + CXXFLAGS += ['-Wno-extra-tokens'] diff --git a/accessible/interfaces/msaa/moz.build b/accessible/interfaces/msaa/moz.build index c497fa3c35..6c942bd2c0 100644 --- a/accessible/interfaces/msaa/moz.build +++ b/accessible/interfaces/msaa/moz.build @@ -25,3 +25,11 @@ OS_LIBS += [ 'rpcrt4', 'oleaut32', ] + +# The Windows MIDL code generator creates things like: +# +# #endif !_MIDL_USE_GUIDDEF_ +# +# which clang-cl complains about. MSVC doesn't, so turn this warning off. +if CONFIG['CLANG_CL']: + CFLAGS += ['-Wno-extra-tokens'] diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp index 2b0c12dffb..cfd1a14695 100644 --- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -9,6 +9,7 @@ #include "mozilla/a11y/Platform.h" #include "ProxyAccessible.h" #include "mozilla/dom/TabParent.h" +#include "xpcAccessibleDocument.h" namespace mozilla { namespace a11y { @@ -292,5 +293,13 @@ DocAccessibleParent::CheckDocTree() const return true; } +xpcAccessibleGeneric* +DocAccessibleParent::GetXPCAccessible(ProxyAccessible* aProxy) +{ + xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this); + MOZ_ASSERT(doc); + + return doc->GetXPCAccessible(aProxy); +} } // a11y } // mozilla diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index 1b2720fd8b..fed344c4bb 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -17,6 +17,8 @@ namespace mozilla { namespace a11y { +class xpcAccessibleGeneric; + /* * These objects live in the main process and comunicate with and represent * an accessible document in a content process. @@ -159,6 +161,7 @@ private: const nsTArray& aNewTree, uint32_t aIdx, uint32_t aIdxInParent); MOZ_WARN_UNUSED_RESULT bool CheckDocTree() const; + xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy); nsTArray mChildDocs; DocAccessibleParent* mParentDoc; diff --git a/accessible/jsat/AccessFu.jsm b/accessible/jsat/AccessFu.jsm index 623cb4c690..f675187ef7 100644 --- a/accessible/jsat/AccessFu.jsm +++ b/accessible/jsat/AccessFu.jsm @@ -46,7 +46,7 @@ this.AccessFu = { // jshint ignore:line this._enableOrDisable(); }); aWindow.navigator.mozSettings.addObserver( - SCREENREADER_SETTING, this.handleEvent.bind(this)); + SCREENREADER_SETTING, this.handleEvent); } } @@ -68,12 +68,21 @@ this.AccessFu = { // jshint ignore:line Services.obs.removeObserver(this, 'Accessibility:Settings'); } else if (Utils.win.navigator.mozSettings) { Utils.win.navigator.mozSettings.removeObserver( - SCREENREADER_SETTING, this.handleEvent.bind(this)); + SCREENREADER_SETTING, this.handleEvent); } delete this._activatePref; Utils.uninit(); }, + /** + * A lazy getter for event handler that binds the scope to AccessFu object. + */ + get handleEvent() { + delete this.handleEvent; + this.handleEvent = this._handleEvent.bind(this); + return this.handleEvent; + }, + /** * Start AccessFu mode, this primarily means controlling the virtual cursor * with arrow keys. @@ -344,7 +353,7 @@ this.AccessFu = { // jshint ignore:line } }, - handleEvent: function handleEvent(aEvent) { + _handleEvent: function _handleEvent(aEvent) { switch (aEvent.type) { case 'TabOpen': { diff --git a/accessible/jsat/Gestures.jsm b/accessible/jsat/Gestures.jsm index 6450658e88..b6f9733d9e 100644 --- a/accessible/jsat/Gestures.jsm +++ b/accessible/jsat/Gestures.jsm @@ -79,6 +79,10 @@ const MOUSE_ID = 'mouse'; const EDGE = 0.1; // Multiply timeouts by this constant, x2 works great too for slower users. const TIMEOUT_MULTIPLIER = 1; +// A single pointer down/up sequence periodically precedes the tripple swipe +// gesture on Android. This delay acounts for that. +const IS_ANDROID = Utils.MozBuildApp === 'mobile/android' && + Utils.AndroidSdkVersion >= 14; /** * A point object containing distance travelled data. @@ -156,6 +160,14 @@ this.GestureSettings = { // jshint ignore:line maxConsecutiveGestureDelay: MAX_CONSECUTIVE_GESTURE_DELAY * TIMEOUT_MULTIPLIER, + /** + * A maximum time we wait for a next pointer down event to consider a sequence + * a multi-action gesture. + * @type {Number} + */ + maxGestureResolveTimeout: + MAX_CONSECUTIVE_GESTURE_DELAY * TIMEOUT_MULTIPLIER, + /** * Delay before tap turns into dwell * @type {Number} @@ -194,13 +206,13 @@ this.GestureTracker = { // jshint ignore:line * @param {Number} aTimeStamp A new pointer event timeStamp. * @param {Function} aGesture A gesture constructor (default: Tap). */ - _init: function GestureTracker__init(aDetail, aTimeStamp, aGesture = Tap) { + _init: function GestureTracker__init(aDetail, aTimeStamp, aGesture) { // Only create a new gesture on |pointerdown| event. if (aDetail.type !== 'pointerdown') { return; } let points = aDetail.points; - let GestureConstructor = aGesture; + let GestureConstructor = aGesture || (IS_ANDROID ? DoubleTap : Tap); this._create(GestureConstructor); this._update(aDetail, aTimeStamp); }, @@ -359,7 +371,7 @@ Gesture.prototype = { let delay = this._getDelay(aTimeStamp); let handler = () => { Logger.gesture('timer handler'); - delete this._timer; + this.clearTimer(); if (!this._inProgress) { this._deferred.reject(); } else if (this._rejectToOnWait) { @@ -502,6 +514,7 @@ Gesture.prototype = { } Logger.gesture('Resolving', this.id, 'gesture.'); this.isComplete = true; + this.clearTimer(); let detail = this.compile(); if (detail) { this._emit(detail); @@ -526,6 +539,7 @@ Gesture.prototype = { } Logger.gesture('Rejecting', this.id, 'gesture.'); this.isComplete = true; + this.clearTimer(); return { id: this.id, gestureType: aRejectTo @@ -692,11 +706,12 @@ TapGesture.prototype.pointerup = function TapGesture_pointerup(aPoints) { let complete = this._update(aPoints, 'pointerup', false, true); if (complete) { this.clearTimer(); - if (GestureSettings.maxConsecutiveGestureDelay) { + if (GestureSettings.maxGestureResolveTimeout) { this._pointerUpTimer = setTimeout(() => { + clearTimeout(this._pointerUpTimer); delete this._pointerUpTimer; this._deferred.resolve(); - }, GestureSettings.maxConsecutiveGestureDelay); + }, GestureSettings.maxGestureResolveTimeout); } else { this._deferred.resolve(); } diff --git a/accessible/tests/mochitest/common.js b/accessible/tests/mochitest/common.js index 40166436d5..842af97d03 100644 --- a/accessible/tests/mochitest/common.js +++ b/accessible/tests/mochitest/common.js @@ -110,6 +110,27 @@ function isLogged(aModule) return gAccRetrieval.isLogged(aModule); } +/** + * Dumps the accessible tree into console. + */ +function dumpTree(aId, aMsg) +{ + function dumpTreeIntl(acc, indent) + { + dump(indent + prettyName(acc) + "\n"); + + var children = acc.children; + for (var i = 0; i < children.length; i++) { + var child = children.queryElementAt(i, nsIAccessible); + dumpTreeIntl(child, indent + " "); + } + } + + dump(aMsg + "\n"); + var root = getAccessible(aId); + dumpTreeIntl(root, " "); +} + /** * Invokes the given function when document is loaded and focused. Preferable * to mochitests 'addLoadEvent' function -- additionally ensures state of the diff --git a/accessible/tests/mochitest/jsat/dom_helper.js b/accessible/tests/mochitest/jsat/dom_helper.js index 431bed1d55..c95d19dc11 100644 --- a/accessible/tests/mochitest/jsat/dom_helper.js +++ b/accessible/tests/mochitest/jsat/dom_helper.js @@ -4,12 +4,10 @@ SimpleTest, getBoundsForDOMElm, Point, Utils */ /* exported loadJSON, eventMap */ -const Ci = Components.interfaces; -const Cu = Components.utils; +var Ci = Components.interfaces; +var Cu = Components.utils; -Cu.import('resource://gre/modules/accessibility/Utils.jsm'); Cu.import('resource://gre/modules/Geometry.jsm'); -Cu.import("resource://gre/modules/accessibility/Gestures.jsm"); var win = getMainChromeWindow(window); @@ -100,11 +98,6 @@ var eventMap = { touchmove: sendTouchEvent }; -var originalDwellThreshold = GestureSettings.dwellThreshold; -var originalSwipeMaxDuration = GestureSettings.swipeMaxDuration; -var originalConsecutiveGestureDelay = - GestureSettings.maxConsecutiveGestureDelay; - /** * Attach a listener for the mozAccessFuGesture event that tests its * type. @@ -158,9 +151,11 @@ function setTimers(aTimeStamp, aRemoveDwellThreshold, aRemoveSwipeMaxDuration) { GestureTracker.current.startTimer(aTimeStamp); } -function resetTimers() { - GestureSettings.dwellThreshold = originalDwellThreshold; - GestureSettings.swipeMaxDuration = originalSwipeMaxDuration; +function resetTimers(aRemoveGestureResolveDelay) { + GestureSettings.dwellThreshold = AccessFuTest.dwellThreshold; + GestureSettings.swipeMaxDuration = AccessFuTest.swipeMaxDuration; + GestureSettings.maxGestureResolveTimeout = aRemoveGestureResolveDelay ? + 0 : AccessFuTest.maxGestureResolveTimeout; } /** @@ -179,10 +174,7 @@ AccessFuTest.addSequence = function AccessFuTest_addSequence(aSequence) { type: aEvent.type }; var timeStamp = Date.now(); - resetTimers(); - GestureSettings.maxConsecutiveGestureDelay = - aEvent.removeConsecutiveGestureDelay ? - 0 : originalConsecutiveGestureDelay; + resetTimers(aEvent.removeGestureResolveDelay); GestureTracker.handle(event, timeStamp); setTimers(timeStamp, aEvent.removeDwellThreshold, aEvent.removeSwipeMaxDuration); diff --git a/accessible/tests/mochitest/jsat/gestures.json b/accessible/tests/mochitest/jsat/gestures.json index b6cc23c4a0..1119943424 100644 --- a/accessible/tests/mochitest/jsat/gestures.json +++ b/accessible/tests/mochitest/jsat/gestures.json @@ -3,7 +3,7 @@ "events": [ {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}], - "removeConsecutiveGestureDelay": true } + "removeGestureResolveDelay": true } ], "expectedGestures": [{ "type": "tap" }] }, @@ -13,7 +13,7 @@ {"type": "pointermove", "points": [{"x": 1.03, "y": 1.03, "identifier": 1}]}, {"type": "pointerup", "points": [{"x": 1.03, "y": 1.03, "identifier": 1}], - "removeConsecutiveGestureDelay": true } + "removeGestureResolveDelay": true } ], "expectedGestures": [{ "type": "tap" }] }, @@ -37,7 +37,7 @@ "points": [{"x": 0.97, "y": 1.01, "identifier": 1}]}, {"type": "pointerup", "points": [{"x": 0.97, "y": 1.01, "identifier": 1}], - "removeConsecutiveGestureDelay": true } + "removeGestureResolveDelay": true } ], "expectedGestures": [{ "type": "doubletap" }] }, @@ -49,7 +49,7 @@ {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}], - "removeConsecutiveGestureDelay": true } + "removeGestureResolveDelay": true } ], "expectedGestures": [{ "type": "tripletap" }] }, @@ -292,7 +292,7 @@ {"y": 1.30098, "x": 1.52602, "identifier": 0}, {"y": 1.94093, "x": 1.02672, "identifier": 1}, {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerup", - "removeConsecutiveGestureDelay": false}], + "removeGestureResolveDelay": true}], "expectedGestures": [{ "type": "tripletap", "fingers": 3 }] }, { @@ -343,14 +343,8 @@ "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}, {"identifier": 2, "x": 2.15625, "y": 1.489583}]}, {"type": "pointerup", - "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}]}, - {"type": "pointermove", - "points": [{"identifier": 0, "x": 1.427083, "y": 2.59375}]}, - {"type": "pointerup", - "points": [{"identifier": 0, "x": 1.427083, "y": 2.59375}]}, - {"type": "pointerup", - "points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}], - "removeConsecutiveGestureDelay": false} + "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}], + "removeGestureResolveDelay": true} ], "expectedGestures": [{ "type": "tripletap", "fingers": 3 }] } diff --git a/accessible/tests/mochitest/jsat/jsatcommon.js b/accessible/tests/mochitest/jsat/jsatcommon.js index 3a7cfd2889..aa7ee74e40 100644 --- a/accessible/tests/mochitest/jsat/jsatcommon.js +++ b/accessible/tests/mochitest/jsat/jsatcommon.js @@ -19,17 +19,6 @@ Components.utils.import("resource://gre/modules/accessibility/Utils.jsm"); Components.utils.import("resource://gre/modules/accessibility/EventManager.jsm"); Components.utils.import("resource://gre/modules/accessibility/Gestures.jsm"); -const dwellThreshold = GestureSettings.dwellThreshold; -const swipeMaxDuration = GestureSettings.swipeMaxDuration; -const maxConsecutiveGestureDelay = GestureSettings.maxConsecutiveGestureDelay; - -// https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes -// SimpleTest.executeSoon timeout is bigger than the timer settings in -// GestureSettings that causes intermittents. -GestureSettings.dwellThreshold = dwellThreshold * 10; -GestureSettings.swipeMaxDuration = swipeMaxDuration * 10; -GestureSettings.maxConsecutiveGestureDelay = maxConsecutiveGestureDelay * 10; - var AccessFuTest = { addFunc: function AccessFuTest_addFunc(aFunc) { @@ -111,9 +100,13 @@ var AccessFuTest = { Logger.test = false; Logger.logLevel = Logger.INFO; // Reset Gesture Settings. - GestureSettings.dwellThreshold = dwellThreshold; - GestureSettings.swipeMaxDuration = swipeMaxDuration; - GestureSettings.maxConsecutiveGestureDelay = maxConsecutiveGestureDelay; + GestureSettings.dwellThreshold = this.dwellThreshold = + this.originalDwellThreshold; + GestureSettings.swipeMaxDuration = this.swipeMaxDuration = + this.originalSwipeMaxDuration; + GestureSettings.maxGestureResolveTimeout = + this.maxGestureResolveTimeout = + this.originalMaxGestureResolveTimeout; // Finish through idle callback to let AccessFu._disable complete. SimpleTest.executeSoon(function () { AccessFu.detach(); @@ -160,6 +153,20 @@ var AccessFuTest = { ['dom.mozSettings.enabled', true]]; prefs.push.apply(prefs, aAdditionalPrefs); + this.originalDwellThreshold = GestureSettings.dwellThreshold; + this.originalSwipeMaxDuration = GestureSettings.swipeMaxDuration; + this.originalMaxGestureResolveTimeout = + GestureSettings.maxGestureResolveTimeout; + // https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes + // SimpleTest.executeSoon timeout is bigger than the timer settings in + // GestureSettings that causes intermittents. + this.dwellThreshold = GestureSettings.dwellThreshold = + GestureSettings.dwellThreshold * 10; + this.swipeMaxDuration = GestureSettings.swipeMaxDuration = + GestureSettings.swipeMaxDuration * 10; + this.maxGestureResolveTimeout = GestureSettings.maxGestureResolveTimeout = + GestureSettings.maxGestureResolveTimeout * 10; + SpecialPowers.pushPrefEnv({ 'set': prefs }, function () { if (AccessFuTest._waitForExplicitFinish) { // Run all test functions asynchronously. diff --git a/accessible/tests/mochitest/jsat/output.js b/accessible/tests/mochitest/jsat/output.js index cd9b2a9f5f..5afcc8a666 100644 --- a/accessible/tests/mochitest/jsat/output.js +++ b/accessible/tests/mochitest/jsat/output.js @@ -1,4 +1,4 @@ -const Cu = Components.utils; +var Cu = Components.utils; const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance"; Cu.import('resource://gre/modules/accessibility/Utils.jsm'); diff --git a/accessible/tests/mochitest/jsat/test_live_regions.html b/accessible/tests/mochitest/jsat/test_live_regions.html index 5d1bdc683f..8867d7558b 100644 --- a/accessible/tests/mochitest/jsat/test_live_regions.html +++ b/accessible/tests/mochitest/jsat/test_live_regions.html @@ -20,7 +20,7 @@ function stopAccessFu() { SpecialPowers.setIntPref("accessibility.accessfu.activate", 0); - AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish); + AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish()); } function hide(id) { diff --git a/accessible/tests/mochitest/jsat/test_quicknav_modes.html b/accessible/tests/mochitest/jsat/test_quicknav_modes.html index f7201388a6..f8fde8b3f2 100644 --- a/accessible/tests/mochitest/jsat/test_quicknav_modes.html +++ b/accessible/tests/mochitest/jsat/test_quicknav_modes.html @@ -68,7 +68,7 @@ // Listen for initial 'EventManager.start' and disable AccessFu. function prefStop() { ok(AccessFu._enabled, "AccessFu was started via preference."); - AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish); + AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish()); SpecialPowers.setIntPref("accessibility.accessfu.activate", 0); } diff --git a/accessible/tests/mochitest/name/a11y.ini b/accessible/tests/mochitest/name/a11y.ini index 601e9af9a0..e5147ed2d7 100644 --- a/accessible/tests/mochitest/name/a11y.ini +++ b/accessible/tests/mochitest/name/a11y.ini @@ -13,4 +13,5 @@ support-files = [test_list.html] [test_markup.html] [test_svg.html] +[test_toolbaritem.xul] [test_tree.xul] diff --git a/accessible/tests/mochitest/name/test_toolbaritem.xul b/accessible/tests/mochitest/name/test_toolbaritem.xul new file mode 100644 index 0000000000..8968964a9e --- /dev/null +++ b/accessible/tests/mochitest/name/test_toolbaritem.xul @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + Mozilla Bug 1216478 + +

+ +
+    
+ + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/accessible/tests/mochitest/treeupdate/test_ariaowns.html b/accessible/tests/mochitest/treeupdate/test_ariaowns.html index b0ea67b9cc..2070136f1b 100644 --- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html +++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html @@ -23,19 +23,21 @@ // Invokers //////////////////////////////////////////////////////////////////////////// - function removeARIAOwns() + function changeARIAOwns() { this.eventSeq = [ - new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")), new invokerChecker(EVENT_HIDE, getNode("t1_button")), new invokerChecker(EVENT_SHOW, getNode("t1_button")), + new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")), + new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")), + new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")), new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")), new invokerChecker(EVENT_REORDER, getNode("t1_container")) ]; - this.invoke = function removeARIAOwns_invoke() + this.invoke = function setARIAOwns_invoke() { - // children are swapped + // children are swapped by ARIA owns var tree = { SECTION: [ { CHECKBUTTON: [ @@ -45,6 +47,41 @@ ] }; testAccessibleTree("t1_container", tree); + getNode("t1_container"). + setAttribute("aria-owns", "t1_button t1_subdiv"); + } + + this.finalCheck = function setARIAOwns_finalCheck() + { + // children are swapped again, button and subdiv are appended to + // the children. + var tree = + { SECTION: [ + { CHECKBUTTON: [ ] }, // checkbox, native order + { PUSHBUTTON: [ ] }, // button, rearranged by ARIA own + { SECTION: [ ] } // subdiv from the subtree, ARIA owned + ] }; + testAccessibleTree("t1_container", tree); + } + + this.getID = function setARIAOwns_getID() + { + return "Change @aria-owns attribute"; + } + } + + function removeARIAOwns() + { + this.eventSeq = [ + new invokerChecker(EVENT_HIDE, getNode("t1_button")), + new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")), + new invokerChecker(EVENT_SHOW, getNode("t1_button")), + new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")), + new invokerChecker(EVENT_REORDER, getNode("t1_container")) + ]; + + this.invoke = function removeARIAOwns_invoke() + { getNode("t1_container").removeAttribute("aria-owns"); } @@ -418,6 +455,7 @@ gQueue = new eventQueue(); // test1 + gQueue.push(new changeARIAOwns()); gQueue.push(new removeARIAOwns()); gQueue.push(new setARIAOwns()); gQueue.push(new addIdToARIAOwns()); diff --git a/accessible/windows/ia2/moz.build b/accessible/windows/ia2/moz.build index 6948a89c12..91a96bbcf1 100644 --- a/accessible/windows/ia2/moz.build +++ b/accessible/windows/ia2/moz.build @@ -50,4 +50,12 @@ FINAL_LIBRARY = 'xul' if CONFIG['GNU_CXX']: CXXFLAGS += ['-Wshadow'] +# The Windows MIDL code generator creates things like: +# +# #endif !_MIDL_USE_GUIDDEF_ +# +# which clang-cl complains about. MSVC doesn't, so turn this warning off. +if CONFIG['CLANG_CL']: + CXXFLAGS += ['-Wno-extra-tokens'] + include('/ipc/chromium/chromium-config.mozbuild') diff --git a/accessible/windows/msaa/moz.build b/accessible/windows/msaa/moz.build index 42469ada2d..f38b891830 100644 --- a/accessible/windows/msaa/moz.build +++ b/accessible/windows/msaa/moz.build @@ -58,6 +58,14 @@ LOCAL_INCLUDES += [ '/dom/base', ] +# The Windows MIDL code generator creates things like: +# +# #endif !_MIDL_USE_GUIDDEF_ +# +# which clang-cl complains about. MSVC doesn't, so turn this warning off. +if CONFIG['CLANG_CL']: + CXXFLAGS += ['-Wno-extra-tokens'] + include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp index c07049cc3b..e99f979d29 100644 --- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp +++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp @@ -588,9 +588,9 @@ nsresult BluetoothDaemonGattModule::ClientSetAdvDataCmd( int aServerIf, bool aIsScanRsp, bool aIsNameIncluded, bool aIsTxPowerIncluded, int aMinInterval, int aMaxInterval, int aApperance, - uint16_t aManufacturerLen, char* aManufacturerData, - uint16_t aServiceDataLen, char* aServiceData, - uint16_t aServiceUuidLen, char* aServiceUuid, + const nsTArray& aManufacturerData, + const nsTArray& aServiceData, + const nsTArray& aServiceUuids, BluetoothGattResultHandler* aRes) { MOZ_ASSERT(NS_IsMainThread()); @@ -598,6 +598,17 @@ BluetoothDaemonGattModule::ClientSetAdvDataCmd( nsAutoPtr pdu( new DaemonSocketPDU(SERVICE_ID, OPCODE_CLIENT_SET_ADV_DATA, 0)); + uint16_t manufacturerDataByteLen = + aManufacturerData.Length() * sizeof(uint8_t); + uint16_t serviceDataByteLen = aServiceData.Length() * sizeof(uint8_t); + uint16_t serviceUuidsByteLen = + aServiceUuids.Length() * sizeof(BluetoothUuid::mUuid); + uint8_t* manufacturerData = + const_cast(aManufacturerData.Elements()); + uint8_t* serviceData = const_cast(aServiceData.Elements()); + BluetoothUuid* serviceUuids = + const_cast(aServiceUuids.Elements()); + nsresult rv = PackPDU( PackConversion(aServerIf), PackConversion(aIsScanRsp), @@ -606,10 +617,12 @@ BluetoothDaemonGattModule::ClientSetAdvDataCmd( PackConversion(aMinInterval), PackConversion(aMaxInterval), PackConversion(aApperance), - aManufacturerLen, aServiceDataLen, aServiceUuidLen, - PackArray(aManufacturerData, aManufacturerLen), - PackArray(aServiceData, aServiceDataLen), - PackArray(aServiceUuid, aServiceUuidLen), *pdu); + manufacturerDataByteLen, serviceDataByteLen, serviceUuidsByteLen, + PackArray(manufacturerData, aManufacturerData.Length()), + PackArray(serviceData, aServiceData.Length()), + PackArray>( + serviceUuids, aServiceUuids.Length()), + *pdu); if (NS_FAILED(rv)) { return rv; } @@ -2415,17 +2428,17 @@ void BluetoothDaemonGattInterface::SetAdvData( int aServerIf, bool aIsScanRsp, bool aIsNameIncluded, bool aIsTxPowerIncluded, int aMinInterval, int aMaxInterval, int aApperance, - uint16_t aManufacturerLen, char* aManufacturerData, - uint16_t aServiceDataLen, char* aServiceData, - uint16_t aServiceUUIDLen, char* aServiceUUID, + const nsTArray& aManufacturerData, + const nsTArray& aServiceData, + const nsTArray& aServiceUuids, BluetoothGattResultHandler* aRes) { MOZ_ASSERT(mModule); nsresult rv = mModule->ClientSetAdvDataCmd( aServerIf, aIsScanRsp, aIsNameIncluded, aIsTxPowerIncluded, aMinInterval, - aMaxInterval, aApperance, aManufacturerLen, aManufacturerData, - aServiceDataLen, aServiceData, aServiceUUIDLen, aServiceUUID, aRes); + aMaxInterval, aApperance, aManufacturerData, aServiceData, aServiceUuids, + aRes); if (NS_FAILED(rv)) { DispatchError(aRes, rv); diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h index 98e7e45379..b438d51369 100644 --- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h +++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h @@ -203,12 +203,9 @@ public: int aMinInterval, int aMaxInterval, int aApperance, - uint16_t aManufacturerLen, - char* aManufacturerData, - uint16_t aServiceDataLen, - char* aServiceData, - uint16_t aServiceUUIDLen, - char* aServiceUUID, + const nsTArray& aManufacturerData, + const nsTArray& aServiceData, + const nsTArray& aServiceUuids, BluetoothGattResultHandler* aRes); nsresult ClientTestCommandCmd(int aCommand, @@ -908,9 +905,9 @@ public: int aMinInterval, int aMaxInterval, int aApperance, - uint16_t aManufacturerLen, char* aManufacturerData, - uint16_t aServiceDataLen, char* aServiceData, - uint16_t aServiceUuidLen, char* aServiceUuid, + const nsTArray& aManufacturerData, + const nsTArray& aServiceData, + const nsTArray& aServiceUuids, BluetoothGattResultHandler* aRes) override; void TestCommand(int aCommand, diff --git a/dom/bluetooth/bluedroid/BluetoothGattManager.cpp b/dom/bluetooth/bluedroid/BluetoothGattManager.cpp index 10247d86df..ea01e40a01 100644 --- a/dom/bluetooth/bluedroid/BluetoothGattManager.cpp +++ b/dom/bluetooth/bluedroid/BluetoothGattManager.cpp @@ -190,6 +190,8 @@ public: int mClientIf; int mConnId; RefPtr mStartLeScanRunnable; + RefPtr mStartAdvertisingRunnable; + RefPtr mStopAdvertisingRunnable; RefPtr mConnectRunnable; RefPtr mDisconnectRunnable; RefPtr mDiscoverRunnable; @@ -203,6 +205,8 @@ public: BluetoothGattClientReadDescState mReadDescriptorState; BluetoothGattClientWriteDescState mWriteDescriptorState; + BluetoothGattAdvertisingData mAdvertisingData; + /** * These temporary arrays are used only during discover operations. * All of them are empty if there are no ongoing discover operations. @@ -293,6 +297,7 @@ public: */ bool mIsRegistering; + RefPtr mRegisterServerRunnable; RefPtr mConnectPeripheralRunnable; RefPtr mDisconnectPeripheralRunnable; RefPtr mUnregisterServerRunnable; @@ -887,6 +892,195 @@ BluetoothGattManager::StopLeScan(const BluetoothUuid& aScanUuid, new StopLeScanResultHandler(aRunnable, client->mClientIf)); } +class BluetoothGattManager::StartAdvertisingResultHandler final + : public BluetoothGattResultHandler +{ +public: + StartAdvertisingResultHandler(BluetoothGattClient* aClient) + : mClient(aClient) + { + MOZ_ASSERT(mClient); + } + + void Listen() override + { + MOZ_ASSERT(mClient->mStartAdvertisingRunnable); + + DispatchReplySuccess(mClient->mStartAdvertisingRunnable); + mClient->mStartAdvertisingRunnable = nullptr; + } + + void OnError(BluetoothStatus aStatus) override + { + BT_WARNING("BluetoothGattInterface::StartLeAdvertising failed: %d", + (int)aStatus); + MOZ_ASSERT(mClient->mStartAdvertisingRunnable); + + // Unregister client if startAdvertising failed + if (mClient->mClientIf > 0) { + BluetoothGattManager* gattManager = BluetoothGattManager::Get(); + NS_ENSURE_TRUE_VOID(gattManager); + + RefPtr result = + new BluetoothVoidReplyRunnable(nullptr); + gattManager->UnregisterClient(mClient->mClientIf, result); + } + + DispatchReplyError(mClient->mStartAdvertisingRunnable, aStatus); + mClient->mStartAdvertisingRunnable = nullptr; + } + +private: + RefPtr mClient; +}; + +class BluetoothGattManager::SetAdvDataResultHandler final + : public BluetoothGattResultHandler +{ +public: + SetAdvDataResultHandler(BluetoothGattClient* aClient) + : mClient(aClient) + { + MOZ_ASSERT(mClient); + } + + void SetAdvData() override + { + sBluetoothGattInterface->Listen( + mClient->mClientIf, + true /* Start */, + new StartAdvertisingResultHandler(mClient)); + } + + void OnError(BluetoothStatus aStatus) override + { + BT_WARNING("BluetoothGattInterface::StartLeAdvertising failed: %d", + (int)aStatus); + MOZ_ASSERT(mClient->mStartAdvertisingRunnable); + + // Unregister client if startAdvertising failed + if (mClient->mClientIf > 0) { + BluetoothGattManager* gattManager = BluetoothGattManager::Get(); + NS_ENSURE_TRUE_VOID(gattManager); + + RefPtr result = + new BluetoothVoidReplyRunnable(nullptr); + gattManager->UnregisterClient(mClient->mClientIf, result); + } + + DispatchReplyError(mClient->mStartAdvertisingRunnable, aStatus); + mClient->mStartAdvertisingRunnable = nullptr; + } + +private: + RefPtr mClient; +}; + +void +BluetoothGattManager::StartAdvertising( + const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aData, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRunnable); + + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); + + size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); + + // Reject the startAdvertising request if the clientIf is being used. + if (NS_WARN_IF(index != sClients->NoIndex)) { + DispatchReplyError(aRunnable, + NS_LITERAL_STRING("start advertising failed")); + return; + } + + index = sClients->Length(); + sClients->AppendElement(new BluetoothGattClient(aAppUuid, + BluetoothAddress::ANY)); + RefPtr client = sClients->ElementAt(index); + client->mStartAdvertisingRunnable = aRunnable; + client->mAdvertisingData = aData; + + // 'startAdvertising' will be proceeded after client registered + sBluetoothGattInterface->RegisterClient( + aAppUuid, new RegisterClientResultHandler(client)); +} + +class BluetoothGattManager::StopAdvertisingResultHandler final + : public BluetoothGattResultHandler +{ +public: + StopAdvertisingResultHandler(BluetoothGattClient* aClient) + : mClient(aClient) + { + MOZ_ASSERT(mClient); + } + + void Listen() override + { + MOZ_ASSERT(mClient->mStopAdvertisingRunnable); + + // Unregister client when stopLeScan succeeded + if (mClient->mClientIf > 0) { + BluetoothGattManager* gattManager = BluetoothGattManager::Get(); + NS_ENSURE_TRUE_VOID(gattManager); + + RefPtr result = + new BluetoothVoidReplyRunnable(nullptr); + gattManager->UnregisterClient(mClient->mClientIf, result); + } + + DispatchReplySuccess(mClient->mStopAdvertisingRunnable); + mClient->mStopAdvertisingRunnable = nullptr; + } + + void OnError(BluetoothStatus aStatus) override + { + BT_WARNING("BluetoothGattInterface::StopAdvertising failed: %d", + (int)aStatus); + MOZ_ASSERT(mClient->mStopAdvertisingRunnable); + + DispatchReplyError(mClient->mStopAdvertisingRunnable, aStatus); + mClient->mStopAdvertisingRunnable = nullptr; + } + +private: + RefPtr mClient; +}; + +void +BluetoothGattManager::StopAdvertising(const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRunnable); + + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); + + size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); + if (NS_WARN_IF(index == sClients->NoIndex)) { + // Reject the stop advertising request + DispatchReplyError(aRunnable, NS_LITERAL_STRING("StopAdvertising failed")); + return; + } + + RefPtr client = sClients->ElementAt(index); + + // Reject the stop advertising request if there is an ongoing one. + if (client->mStopAdvertisingRunnable) { + DispatchReplyError(aRunnable, STATUS_BUSY); + return; + } + + client->mStopAdvertisingRunnable = aRunnable; + sBluetoothGattInterface->Listen( + client->mClientIf, + false /* Stop */, + new StopAdvertisingResultHandler(client)); +} + class BluetoothGattManager::ConnectResultHandler final : public BluetoothGattResultHandler { @@ -1642,6 +1836,12 @@ public: mServer->mAddServiceState.Reset(); } + if (mServer->mRegisterServerRunnable) { + DispatchReplyError(mServer->mRegisterServerRunnable, + NS_LITERAL_STRING("Register GATT server failed")); + mServer->mRegisterServerRunnable = nullptr; + } + mServer->mIsRegistering = false; sServers->RemoveElement(mServer); } @@ -1650,6 +1850,48 @@ private: RefPtr mServer; }; +void +BluetoothGattManager::RegisterServer(const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRunnable); + + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); + + size_t index = sServers->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); + if (index == sServers->NoIndex) { + index = sServers->Length(); + sServers->AppendElement(new BluetoothGattServer(aAppUuid)); + } + RefPtr server = (*sServers)[index]; + + /** + * There are four cases here for handling aRunnable. + * 1) Server interface is already registered: Resolve the runnable. + * 2) Server interface is not registered, but there is + * an existing |RegisterServerRunnable|: Reject with STATUS_BUSY. + * 3) Server interface is registering without an existing + * |RegisterServerRunnable|: Save the runnable into |GattServer| and will + * resolve or reject it in |RegisterServerNotification| later. + * 4) Server interface is neither registered nor registering: Save the + * the runnable into |GattServer| and trigger a registration procedure. + * The runnable will be resolved or rejected in + * |RegisterServerNotification| later. + */ + if (server->mServerIf > 0) { + DispatchReplySuccess(aRunnable); + } else if (server->mRegisterServerRunnable) { + DispatchReplyError(aRunnable, STATUS_BUSY); + } else if (server->mIsRegistering) { + server->mRegisterServerRunnable = aRunnable; + } else { + server->mRegisterServerRunnable = aRunnable; + sBluetoothGattInterface->RegisterServer( + aAppUuid, new RegisterServerResultHandler(server)); + } +} + class BluetoothGattManager::ConnectPeripheralResultHandler final : public BluetoothGattResultHandler { @@ -2552,7 +2794,9 @@ BluetoothGattManager::RegisterClientNotification(BluetoothGattStatus aStatus, NS_LITERAL_STRING( "StartLeScan failed due to registration failed")); client->mStartLeScanRunnable = nullptr; - } else if (client->mConnectRunnable) { + } + + if (client->mConnectRunnable) { // Reject the connect request DispatchReplyError(client->mConnectRunnable, NS_LITERAL_STRING( @@ -2560,6 +2804,15 @@ BluetoothGattManager::RegisterClientNotification(BluetoothGattStatus aStatus, client->mConnectRunnable = nullptr; } + if (client->mStartAdvertisingRunnable) { + // Reject the start advertising request + DispatchReplyError( + client->mStartAdvertisingRunnable, + NS_LITERAL_STRING( + "StartAdvertising failed due to registration failed")); + client->mStartAdvertisingRunnable = nullptr; + } + sClients->RemoveElement(client); return; } @@ -2577,7 +2830,9 @@ BluetoothGattManager::RegisterClientNotification(BluetoothGattStatus aStatus, sBluetoothGattInterface->Scan( aClientIf, true /* start */, new StartLeScanResultHandler(client)); - } else if (client->mConnectRunnable) { + } + + if (client->mConnectRunnable) { // Client just registered, proceed remaining connect request. ENSURE_GATT_INTF_IS_READY_VOID(client->mConnectRunnable); sBluetoothGattInterface->Connect( @@ -2585,6 +2840,17 @@ BluetoothGattManager::RegisterClientNotification(BluetoothGattStatus aStatus, TRANSPORT_AUTO, new ConnectResultHandler(client)); } + + if (client->mStartAdvertisingRunnable) { + // StartAdvertising request will be proceed after SetAdvData succeeded. + ENSURE_GATT_INTF_IS_READY_VOID(client->mStartAdvertisingRunnable); + BluetoothGattAdvertisingData* data = &(client->mAdvertisingData); + sBluetoothGattInterface->SetAdvData( + aClientIf, false /* isScanRsp */, data->mIncludeDevName, + data->mIncludeTxPower, 0 /* min interval */, 0 /* max interval */, + data->mAppearance, data->mManufacturerData, data->mServiceData, + data->mServiceUuids, new SetAdvDataResultHandler(client)); + } } class BluetoothGattManager::ScanDeviceTypeResultHandler final @@ -3355,6 +3621,14 @@ BluetoothGattManager::RegisterServerNotification(BluetoothGattStatus aStatus, server->mAddServiceState.Reset(); } + if (server->mRegisterServerRunnable) { + // Reject the register server request + DispatchReplyError( + server->mRegisterServerRunnable, + NS_LITERAL_STRING("Register server failed")); + server->mRegisterServerRunnable = nullptr; + } + sServers->RemoveElement(server); return; } @@ -3382,6 +3656,11 @@ BluetoothGattManager::RegisterServerNotification(BluetoothGattStatus aStatus, server->mAddServiceState.mHandleCount, new ServerAddServiceResultHandler(server)); } + + if (server->mRegisterServerRunnable) { + DispatchReplySuccess(server->mRegisterServerRunnable); + server->mRegisterServerRunnable = nullptr; + } } void diff --git a/dom/bluetooth/bluedroid/BluetoothGattManager.h b/dom/bluetooth/bluedroid/BluetoothGattManager.h index daede969df..adfe13ae74 100644 --- a/dom/bluetooth/bluedroid/BluetoothGattManager.h +++ b/dom/bluetooth/bluedroid/BluetoothGattManager.h @@ -35,6 +35,13 @@ public: void StopLeScan(const BluetoothUuid& aScanUuid, BluetoothReplyRunnable* aRunnable); + void StartAdvertising(const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aData, + BluetoothReplyRunnable* aRunnable); + + void StopAdvertising(const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable); + void Connect(const BluetoothUuid& aAppUuid, const BluetoothAddress& aDeviceAddr, BluetoothReplyRunnable* aRunnable); @@ -92,6 +99,9 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable); + void RegisterServer(const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable); + void ConnectPeripheral( const BluetoothUuid& aAppUuid, const BluetoothAddress& aAddress, @@ -176,6 +186,9 @@ private: class UnregisterClientResultHandler; class StartLeScanResultHandler; class StopLeScanResultHandler; + class StartAdvertisingResultHandler; + class SetAdvDataResultHandler; + class StopAdvertisingResultHandler; class ConnectResultHandler; class DisconnectResultHandler; class DiscoverResultHandler; diff --git a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp index 7abad6a08c..fdd4c2685b 100644 --- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp @@ -362,6 +362,35 @@ BluetoothServiceBluedroid::StopLeScanInternal( gatt->StopLeScan(aScanUuid, aRunnable); } +void +BluetoothServiceBluedroid::StartAdvertisingInternal( + const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aAdvData, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + ENSURE_BLUETOOTH_IS_ENABLED_VOID(aRunnable); + + BluetoothGattManager* gatt = BluetoothGattManager::Get(); + ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable); + + gatt->StartAdvertising(aAppUuid, aAdvData, aRunnable); +} + +void +BluetoothServiceBluedroid::StopAdvertisingInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + ENSURE_BLUETOOTH_IS_ENABLED_VOID(aRunnable); + + BluetoothGattManager* gatt = BluetoothGattManager::Get(); + ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable); + + gatt->StopAdvertising(aAppUuid, aRunnable); +} + void BluetoothServiceBluedroid::ConnectGattClientInternal( const BluetoothUuid& aAppUuid, const BluetoothAddress& aDeviceAddress, @@ -543,6 +572,20 @@ BluetoothServiceBluedroid::GattClientWriteDescriptorValueInternal( } // GATT Server +void +BluetoothServiceBluedroid::GattServerRegisterInternal( + const BluetoothUuid& aAppUuid, BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + + ENSURE_BLUETOOTH_IS_ENABLED_VOID(aRunnable); + + BluetoothGattManager* gatt = BluetoothGattManager::Get(); + ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable); + + gatt->RegisterServer(aAppUuid, aRunnable); +} + void BluetoothServiceBluedroid::GattServerConnectPeripheralInternal( const BluetoothUuid& aAppUuid, const BluetoothAddress& aAddress, diff --git a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h index 2f4ba58572..944aa219d1 100644 --- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h @@ -284,6 +284,15 @@ public: virtual void StopLeScanInternal(const BluetoothUuid& aScanUuid, BluetoothReplyRunnable* aRunnable); + virtual void StartAdvertisingInternal( + const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aAdvData, + BluetoothReplyRunnable* aRunnable) override; + + virtual void StopAdvertisingInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) override; + virtual void ConnectGattClientInternal(const BluetoothUuid& aAppUuid, const BluetoothAddress& aDeviceAddress, @@ -354,6 +363,11 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable) override; + virtual void + GattServerRegisterInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) override; + virtual void GattServerConnectPeripheralInternal( const BluetoothUuid& aAppUuid, diff --git a/dom/bluetooth/bluez/BluetoothDBusService.cpp b/dom/bluetooth/bluez/BluetoothDBusService.cpp index c1040b42d2..8c49d1620d 100644 --- a/dom/bluetooth/bluez/BluetoothDBusService.cpp +++ b/dom/bluetooth/bluez/BluetoothDBusService.cpp @@ -4300,6 +4300,21 @@ BluetoothDBusService::StopLeScanInternal( { } +void +BluetoothDBusService::StartAdvertisingInternal( + const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aAdvData, + BluetoothReplyRunnable* aRunnable) +{ +} + +void +BluetoothDBusService::StopAdvertisingInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) +{ +} + void BluetoothDBusService::ConnectGattClientInternal( const BluetoothUuid& aAppUuid, const BluetoothAddress& aDeviceAddress, @@ -4512,6 +4527,12 @@ BluetoothDBusService::ReplyToMapMessageUpdate(long aMasId, bool aStatus, { } +void +BluetoothDBusService::GattServerRegisterInternal( + const BluetoothUuid& aAppUuid, BluetoothReplyRunnable* aRunnable) +{ +} + void BluetoothDBusService::GattServerConnectPeripheralInternal( const BluetoothUuid& aAppUuid, const BluetoothAddress& aAddress, diff --git a/dom/bluetooth/bluez/BluetoothDBusService.h b/dom/bluetooth/bluez/BluetoothDBusService.h index 4ab4af6d24..e48b39bc28 100644 --- a/dom/bluetooth/bluez/BluetoothDBusService.h +++ b/dom/bluetooth/bluez/BluetoothDBusService.h @@ -292,6 +292,15 @@ public: StopLeScanInternal(const BluetoothUuid& aAppUuid, BluetoothReplyRunnable* aRunnable) override; + virtual void + StartAdvertisingInternal(const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aAdvData, + BluetoothReplyRunnable* aRunnable) override; + + virtual void + StopAdvertisingInternal(const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) override; + virtual void ConnectGattClientInternal(const BluetoothUuid& aAppUuid, const BluetoothAddress& aDeviceAddress, @@ -362,6 +371,11 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable) override; + virtual void + GattServerRegisterInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) override; + virtual void GattServerConnectPeripheralInternal( const BluetoothUuid& aAppUuid, diff --git a/dom/bluetooth/common/BluetoothCommon.h b/dom/bluetooth/common/BluetoothCommon.h index 966300cfe8..ce42de7067 100644 --- a/dom/bluetooth/common/BluetoothCommon.h +++ b/dom/bluetooth/common/BluetoothCommon.h @@ -1306,6 +1306,62 @@ enum BluetoothGapDataType { GAP_COMPLETE_NAME = 0X09, // Complete Local Name }; +struct BluetoothGattAdvertisingData { + /** + * Uuid value of Appearance characteristic of the GAP service which can be + * mapped to an icon or string that describes the physical representation of + * the device during the device discovery procedure. + */ + uint16_t mAppearance; + + /** + * Whether to broadcast with device name or not. + */ + bool mIncludeDevName; + + /** + * Whether to broadcast with TX power or not. + */ + bool mIncludeTxPower; + + /** + * Byte array of custom manufacturer specific data. + * + * The first 2 octets contain the Company Identifier Code followed by + * additional manufacturer specific data. See Core Specification Supplement + * (CSS) v6 1.4 for more details. + */ + nsTArray mManufacturerData; + + /** + * Consists of a service UUID with the data associated with that service. + * Please see Core Specification Supplement (CSS) v6 1.11 for more details. + */ + nsTArray mServiceData; + + /** + * A list of Service or Service Class UUIDs. + * Please see Core Specification Supplement (CSS) v6 1.1 for more details. + */ + nsTArray mServiceUuids; + + BluetoothGattAdvertisingData() + : mAppearance(0) + , mIncludeDevName(false) + , mIncludeTxPower(false) + { } + + bool operator==(const BluetoothGattAdvertisingData& aOther) const + { + return mIncludeDevName == aOther.mIncludeDevName && + mIncludeTxPower == aOther.mIncludeTxPower && + mAppearance == aOther.mAppearance && + mManufacturerData == aOther.mManufacturerData && + mServiceData == aOther.mServiceData && + mServiceUuids == aOther.mServiceUuids; + } +}; + END_BLUETOOTH_NAMESPACE #endif // mozilla_dom_bluetooth_BluetoothCommon_h diff --git a/dom/bluetooth/common/BluetoothInterface.h b/dom/bluetooth/common/BluetoothInterface.h index a8c798268c..77b257c874 100644 --- a/dom/bluetooth/common/BluetoothInterface.h +++ b/dom/bluetooth/common/BluetoothInterface.h @@ -1028,12 +1028,9 @@ public: int aMinInterval, int aMaxInterval, int aApperance, - uint16_t aManufacturerLen, - char* aManufacturerData, - uint16_t aServiceDataLen, - char* aServiceData, - uint16_t aServiceUUIDLen, - char* aServiceUUID, + const nsTArray& aManufacturerData, + const nsTArray& aServiceData, + const nsTArray& aServiceUuids, BluetoothGattResultHandler* aRes) = 0; virtual void TestCommand(int aCommand, diff --git a/dom/bluetooth/common/BluetoothService.h b/dom/bluetooth/common/BluetoothService.h index 634d8d95af..4357900041 100644 --- a/dom/bluetooth/common/BluetoothService.h +++ b/dom/bluetooth/common/BluetoothService.h @@ -239,6 +239,18 @@ public: StartLeScanInternal(const nsTArray& aServiceUuids, BluetoothReplyRunnable* aRunnable) = 0; + /** + * Start/Stop advertising. + */ + virtual void + StartAdvertisingInternal(const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aAdvData, + BluetoothReplyRunnable* aRunnable) { } + + virtual void + StopAdvertisingInternal(const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) { } + /** * Set a property for the specified object * @@ -586,6 +598,11 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable) = 0; + virtual void + GattServerRegisterInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) = 0; + virtual void GattServerConnectPeripheralInternal( const BluetoothUuid& aAppUuid, diff --git a/dom/bluetooth/common/BluetoothUtils.cpp b/dom/bluetooth/common/BluetoothUtils.cpp index 98b7efad71..2bb796d9a9 100644 --- a/dom/bluetooth/common/BluetoothUtils.cpp +++ b/dom/bluetooth/common/BluetoothUtils.cpp @@ -9,6 +9,7 @@ #include "BluetoothService.h" #include "jsapi.h" #include "mozilla/dom/BluetoothGattCharacteristicBinding.h" +#include "mozilla/dom/BluetoothGattServerBinding.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/bluetooth/BluetoothTypes.h" #include "nsContentUtils.h" @@ -413,7 +414,55 @@ GattPropertiesToBits(const GattCharacteristicProperties& aProperties, } } +nsresult +AdvertisingDataToGattAdvertisingData( + const BluetoothAdvertisingData& aAdvData, + BluetoothGattAdvertisingData& aGattAdvData) +{ + aGattAdvData.mAppearance = aAdvData.mAppearance; + aGattAdvData.mIncludeDevName = aAdvData.mIncludeDevName; + aGattAdvData.mIncludeTxPower = aAdvData.mIncludeTxPower; + for (size_t i = 0; i < aAdvData.mServiceUuids.Length(); i++) { + BluetoothUuid uuid; + if (NS_WARN_IF(NS_FAILED(StringToUuid(aAdvData.mServiceUuids[i], uuid)))) { + return NS_ERROR_ILLEGAL_VALUE; + } + aGattAdvData.mServiceUuids.AppendElement(uuid); + } + + if (!aAdvData.mManufacturerData.IsNull()) { + // First two bytes are manufacturer ID in little-endian. + LittleEndian::writeUint16(aGattAdvData.mManufacturerData.Elements(), + aAdvData.mManufacturerId); + + // Concatenate custom manufacturer data. + const ArrayBuffer& manufacturerData = aAdvData.mManufacturerData.Value(); + manufacturerData.ComputeLengthAndData(); + aGattAdvData.mManufacturerData.AppendElements(manufacturerData.Data(), + manufacturerData.Length()); + } + + if (!aAdvData.mServiceData.IsNull()) { + BluetoothUuid uuid; + if (NS_WARN_IF(NS_FAILED(StringToUuid(aAdvData.mServiceUuid, uuid)))) { + return NS_ERROR_ILLEGAL_VALUE; + } + + // First 16 bytes are service UUID in little-endian. + for (size_t i = 0; i < sizeof(uuid.mUuid); i++) { + aGattAdvData.mServiceData[i] = uuid.mUuid[sizeof(uuid.mUuid) - i - 1]; + } + + // Concatenate custom service data. + const ArrayBuffer& serviceData = aAdvData.mServiceData.Value(); + serviceData.ComputeLengthAndData(); + aGattAdvData.mServiceData.AppendElements(serviceData.Data(), + serviceData.Length()); + } + + return NS_OK; +} void GeneratePathFromGattId(const BluetoothGattId& aId, diff --git a/dom/bluetooth/common/BluetoothUtils.h b/dom/bluetooth/common/BluetoothUtils.h index 8cc6ec4e57..b9b0dc0ff3 100644 --- a/dom/bluetooth/common/BluetoothUtils.h +++ b/dom/bluetooth/common/BluetoothUtils.h @@ -14,6 +14,7 @@ namespace mozilla { namespace dom { class GattPermissions; class GattCharacteristicProperties; +class BluetoothAdvertisingData; } } @@ -175,6 +176,19 @@ void GeneratePathFromGattId(const BluetoothGattId& aId, nsAString& aPath); +/** + * Convert BluetoothAdvertisingData object used by applications to + * BluetoothGattAdvertisingData object used by gecko backend. + * + * @param aAdvData [in] BluetoothAdvertisingData object. + * @param aGattAdData [out] Target BluetoothGattAdvertisingData. + * @return NS_OK on success, NS_ERROR_ILLEGAL_VALUE otherwise. + */ +nsresult +AdvertisingDataToGattAdvertisingData( + const BluetoothAdvertisingData& aAdvData, + BluetoothGattAdvertisingData& aGattAdvData); + // // Register/Unregister bluetooth signal handlers // diff --git a/dom/bluetooth/common/webapi/BluetoothGattServer.cpp b/dom/bluetooth/common/webapi/BluetoothGattServer.cpp index ce46d64929..5d2bfc56d6 100644 --- a/dom/bluetooth/common/webapi/BluetoothGattServer.cpp +++ b/dom/bluetooth/common/webapi/BluetoothGattServer.cpp @@ -374,6 +374,195 @@ BluetoothGattServer::Disconnect(const nsAString& aAddress, ErrorResult& aRv) return promise.forget(); } +class BluetoothGattServer::StartAdvertisingTask final + : public BluetoothVoidReplyRunnable +{ +public: + StartAdvertisingTask(BluetoothGattServer* aServer, Promise* aPromise) + : BluetoothVoidReplyRunnable(nullptr, aPromise) + , mServer(aServer) + { + MOZ_ASSERT(aServer); + MOZ_ASSERT(aPromise); + } + + virtual void + ReleaseMembers() override + { + BluetoothReplyRunnable::ReleaseMembers(); + mServer = nullptr; + } + +protected: + virtual void OnErrorFired() override + { + mServer->mAdvertisingAppUuid.Clear(); + } + +private: + RefPtr mServer; +}; + +class BluetoothGattServer::RegisterServerAndStartAdvertisingTask final + : public BluetoothVoidReplyRunnable +{ +public: + RegisterServerAndStartAdvertisingTask( + BluetoothGattServer* aServer, + const BluetoothGattAdvertisingData& aAdvData, + Promise* aPromise) + : BluetoothVoidReplyRunnable(nullptr, nullptr) + /** + * aPromise is not managed by BluetoothVoidReplyRunnable. It would be + * passed to |StartAdvertisingTask| after this one executes successfully. + */ + , mServer(aServer) + , mAdvData(aAdvData) + , mPromise(aPromise) + { + MOZ_ASSERT(mServer); + MOZ_ASSERT(mPromise); + } + + void ReleaseMembers() override + { + BluetoothReplyRunnable::ReleaseMembers(); + mServer = nullptr; + mPromise = nullptr; + } + +private: + virtual void OnSuccessFired() override + { + BluetoothService* bs = BluetoothService::Get(); + if (NS_WARN_IF(!bs)) { + mPromise->MaybeReject(NS_ERROR_NOT_AVAILABLE); + } + + if (NS_WARN_IF(mServer->mAdvertisingAppUuid.IsCleared())) { + mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); + } + + bs->StartAdvertisingInternal( + mServer->mAdvertisingAppUuid, mAdvData, + new StartAdvertisingTask(mServer, mPromise)); + } + + virtual void OnErrorFired() override + { + mServer->mAdvertisingAppUuid.Clear(); + mPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR); + } + + RefPtr mServer; + BluetoothGattAdvertisingData mAdvData; + RefPtr mPromise; +}; + +already_AddRefed +BluetoothGattServer::StartAdvertising(const BluetoothAdvertisingData& aAdvData, + ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(GetParentObject()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + RefPtr promise = Promise::Create(global, aRv); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + + BT_ENSURE_TRUE_REJECT(mValid, promise, NS_ERROR_NOT_AVAILABLE); + + BT_ENSURE_TRUE_REJECT(mAdvertisingAppUuid.IsCleared(), + promise, + NS_ERROR_DOM_INVALID_STATE_ERR); + + nsresult rv = GenerateUuid(mAdvertisingAppUuid); + BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(rv) && !mAdvertisingAppUuid.IsCleared(), + promise, + NS_ERROR_DOM_OPERATION_ERR); + + BluetoothService* bs = BluetoothService::Get(); + BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE); + + BluetoothGattAdvertisingData data; + rv = AdvertisingDataToGattAdvertisingData(aAdvData, data); + BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(rv), promise, rv); + + BluetoothUuid appUuid; + rv = StringToUuid(mAppUuid, appUuid); + BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(rv), promise, rv); + + bs->GattServerRegisterInternal( + appUuid, + new RegisterServerAndStartAdvertisingTask(this, data, promise)); + + return promise.forget(); +} + +class BluetoothGattServer::StopAdvertisingTask final + : public BluetoothVoidReplyRunnable +{ +public: + StopAdvertisingTask(BluetoothGattServer* aServer, Promise* aPromise) + : BluetoothVoidReplyRunnable(nullptr, aPromise) + , mServer(aServer) + { + MOZ_ASSERT(aPromise); + MOZ_ASSERT(aServer); + } + + virtual void + ReleaseMembers() override + { + BluetoothReplyRunnable::ReleaseMembers(); + mServer = nullptr; + } + +protected: + virtual void OnSuccessFired() override + { + mServer->mAdvertisingAppUuid.Clear(); + } + + virtual void OnErrorFired() override + { + mServer->mAdvertisingAppUuid.Clear(); + } + +private: + RefPtr mServer; +}; + +already_AddRefed +BluetoothGattServer::StopAdvertising(ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(GetParentObject()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + RefPtr promise = Promise::Create(global, aRv); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + + BT_ENSURE_TRUE_REJECT(mValid, promise, NS_ERROR_NOT_AVAILABLE); + + if (mAdvertisingAppUuid.IsCleared()) { + promise->MaybeResolve(JS::UndefinedHandleValue); + return promise.forget(); + } + + BluetoothService* bs = BluetoothService::Get(); + BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE); + + bs->StopAdvertisingInternal(mAdvertisingAppUuid, + new StopAdvertisingTask(this, promise)); + + return promise.forget(); +} + class BluetoothGattServer::AddIncludedServiceTask final : public BluetoothReplyTaskQueue::SubTask { diff --git a/dom/bluetooth/common/webapi/BluetoothGattServer.h b/dom/bluetooth/common/webapi/BluetoothGattServer.h index c178264d70..0f3a5016f9 100644 --- a/dom/bluetooth/common/webapi/BluetoothGattServer.h +++ b/dom/bluetooth/common/webapi/BluetoothGattServer.h @@ -19,6 +19,7 @@ namespace mozilla { namespace dom { class Promise; +struct BluetoothAdvertisingData; } } @@ -57,10 +58,16 @@ public: const nsAString& aAddress, ErrorResult& aRv); already_AddRefed Disconnect( const nsAString& aAddress, ErrorResult& aRv); + + already_AddRefed StartAdvertising( + const BluetoothAdvertisingData& aAdvData, ErrorResult& aRv); + already_AddRefed StopAdvertising(ErrorResult& aRv); + already_AddRefed AddService(BluetoothGattService& aService, ErrorResult& aRv); already_AddRefed RemoveService(BluetoothGattService& aService, ErrorResult& aRv); + already_AddRefed NotifyCharacteristicChanged( const nsAString& aAddress, BluetoothGattCharacteristic& aCharacteristic, @@ -97,6 +104,9 @@ public: private: ~BluetoothGattServer(); + class StartAdvertisingTask; + class RegisterServerAndStartAdvertisingTask; + class StopAdvertisingTask; class AddIncludedServiceTask; class AddCharacteristicTask; class AddDescriptorTask; @@ -106,6 +116,9 @@ private: class AddServiceTask; class RemoveServiceTask; + friend class StartAdvertisingTask; + friend class RegisterServerAndStartAdvertisingTask; + friend class StopAdvertisingTask; friend class AddIncludedServiceTask; friend class AddCharacteristicTask; friend class AddDescriptorTask; @@ -171,6 +184,11 @@ private: * Map request information from the request ID. */ nsClassHashtable mRequestMap; + + /** + * AppUuid of the GATT client interface which is used to advertise. + */ + BluetoothUuid mAdvertisingAppUuid; }; END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/ipc/BluetoothMessageUtils.h b/dom/bluetooth/ipc/BluetoothMessageUtils.h index 9124b564bb..d075543761 100644 --- a/dom/bluetooth/ipc/BluetoothMessageUtils.h +++ b/dom/bluetooth/ipc/BluetoothMessageUtils.h @@ -323,6 +323,36 @@ struct ParamTraits } }; +template <> +struct ParamTraits +{ + typedef mozilla::dom::bluetooth::BluetoothGattAdvertisingData paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.mAppearance); + WriteParam(aMsg, aParam.mIncludeDevName); + WriteParam(aMsg, aParam.mIncludeTxPower); + WriteParam(aMsg, aParam.mManufacturerData); + WriteParam(aMsg, aParam.mServiceData); + WriteParam(aMsg, aParam.mServiceUuids); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + if (!ReadParam(aMsg, aIter, &(aResult->mAppearance)) || + !ReadParam(aMsg, aIter, &(aResult->mIncludeDevName)) || + !ReadParam(aMsg, aIter, &(aResult->mIncludeTxPower)) || + !ReadParam(aMsg, aIter, &(aResult->mManufacturerData)) || + !ReadParam(aMsg, aIter, &(aResult->mServiceData)) || + !ReadParam(aMsg, aIter, &(aResult->mServiceUuids))) { + return false; + } + + return true; + } +}; + } // namespace IPC #endif // mozilla_dom_bluetooth_ipc_BluetoothMessageUtils_h diff --git a/dom/bluetooth/ipc/BluetoothParent.cpp b/dom/bluetooth/ipc/BluetoothParent.cpp index d4a700c3f9..89731e3cfe 100644 --- a/dom/bluetooth/ipc/BluetoothParent.cpp +++ b/dom/bluetooth/ipc/BluetoothParent.cpp @@ -206,6 +206,10 @@ BluetoothParent::RecvPBluetoothRequestConstructor( return actor->DoRequest(aRequest.get_StartLeScanRequest()); case Request::TStopLeScanRequest: return actor->DoRequest(aRequest.get_StopLeScanRequest()); + case Request::TStartAdvertisingRequest: + return actor->DoRequest(aRequest.get_StartAdvertisingRequest()); + case Request::TStopAdvertisingRequest: + return actor->DoRequest(aRequest.get_StopAdvertisingRequest()); case Request::TPairRequest: return actor->DoRequest(aRequest.get_PairRequest()); case Request::TUnpairRequest: @@ -308,6 +312,9 @@ BluetoothParent::RecvPBluetoothRequestConstructor( case Request::TGattClientWriteDescriptorValueRequest: return actor->DoRequest( aRequest.get_GattClientWriteDescriptorValueRequest()); + case Request::TGattServerRegisterRequest: + return actor->DoRequest( + aRequest.get_GattServerRegisterRequest()); case Request::TGattServerConnectPeripheralRequest: return actor->DoRequest( aRequest.get_GattServerConnectPeripheralRequest()); @@ -496,6 +503,30 @@ BluetoothRequestParent::DoRequest(const StopLeScanRequest& aRequest) return true; } +bool +BluetoothRequestParent::DoRequest(const StartAdvertisingRequest& aRequest) +{ + MOZ_ASSERT(mService); + MOZ_ASSERT(mRequestType == Request::TStartAdvertisingRequest); + + mService->StartAdvertisingInternal(aRequest.appUuid(), + aRequest.data(), + mReplyRunnable.get()); + + return true; +} + +bool +BluetoothRequestParent::DoRequest(const StopAdvertisingRequest& aRequest) +{ + MOZ_ASSERT(mService); + MOZ_ASSERT(mRequestType == Request::TStopAdvertisingRequest); + + mService->StopAdvertisingInternal(aRequest.appUuid(), mReplyRunnable.get()); + + return true; +} + bool BluetoothRequestParent::DoRequest(const PairRequest& aRequest) { @@ -1119,6 +1150,18 @@ BluetoothRequestParent::DoRequest( return true; } +bool +BluetoothRequestParent::DoRequest(const GattServerRegisterRequest& aRequest) +{ + MOZ_ASSERT(mService); + MOZ_ASSERT(mRequestType == Request::TGattServerRegisterRequest); + + mService->GattServerRegisterInternal(aRequest.appUuid(), + mReplyRunnable.get()); + + return true; +} + bool BluetoothRequestParent::DoRequest( const GattServerConnectPeripheralRequest& aRequest) diff --git a/dom/bluetooth/ipc/BluetoothParent.h b/dom/bluetooth/ipc/BluetoothParent.h index 96d9bb3a2a..608c44cec1 100644 --- a/dom/bluetooth/ipc/BluetoothParent.h +++ b/dom/bluetooth/ipc/BluetoothParent.h @@ -152,6 +152,12 @@ protected: bool DoRequest(const StopLeScanRequest& aRequest); + bool + DoRequest(const StartAdvertisingRequest& aRequest); + + bool + DoRequest(const StopAdvertisingRequest& aRequest); + bool DoRequest(const PairRequest& aRequest); @@ -295,6 +301,9 @@ protected: bool DoRequest(const GattClientWriteDescriptorValueRequest& aRequest); + bool + DoRequest(const GattServerRegisterRequest& aRequest); + bool DoRequest(const GattServerConnectPeripheralRequest& aRequest); diff --git a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp index 79c5920753..dd0450235c 100644 --- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp +++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp @@ -177,6 +177,23 @@ BluetoothServiceChildProcess::StartLeScanInternal( SendRequest(aRunnable, StartLeScanRequest(aServiceUuids)); } +void +BluetoothServiceChildProcess::StartAdvertisingInternal( + const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aAdvData, + BluetoothReplyRunnable* aRunnable) +{ + SendRequest(aRunnable, StartAdvertisingRequest(aAppUuid, aAdvData)); +} + +void +BluetoothServiceChildProcess::StopAdvertisingInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) +{ + SendRequest(aRunnable, StopAdvertisingRequest(aAppUuid)); +} + nsresult BluetoothServiceChildProcess::SetProperty(BluetoothObjectType aType, const BluetoothNamedValue& aValue, @@ -668,6 +685,14 @@ BluetoothServiceChildProcess::GattClientWriteDescriptorValueInternal( aValue)); } +void +BluetoothServiceChildProcess::GattServerRegisterInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) +{ + SendRequest(aRunnable,GattServerRegisterRequest(aAppUuid)); +} + void BluetoothServiceChildProcess::GattServerConnectPeripheralInternal( const BluetoothUuid& aAppUuid, diff --git a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h index 6970b1e733..52aca4442b 100644 --- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h +++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h @@ -67,6 +67,15 @@ public: StartLeScanInternal(const nsTArray& aServiceUuids, BluetoothReplyRunnable* aRunnable) override; + virtual void + StartAdvertisingInternal(const BluetoothUuid& aAppUuid, + const BluetoothGattAdvertisingData& aAdvData, + BluetoothReplyRunnable* aRunnable) override; + + virtual void + StopAdvertisingInternal(const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) override; + virtual nsresult SetProperty(BluetoothObjectType aType, const BluetoothNamedValue& aValue, @@ -353,6 +362,11 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable) override; + virtual void + GattServerRegisterInternal( + const BluetoothUuid& aAppUuid, + BluetoothReplyRunnable* aRunnable) override; + virtual void GattServerConnectPeripheralInternal( const BluetoothUuid& aAppUuid, diff --git a/dom/bluetooth/ipc/PBluetooth.ipdl b/dom/bluetooth/ipc/PBluetooth.ipdl index aaae8f534f..beb8a7f1fc 100644 --- a/dom/bluetooth/ipc/PBluetooth.ipdl +++ b/dom/bluetooth/ipc/PBluetooth.ipdl @@ -14,6 +14,8 @@ include "mozilla/dom/bluetooth/ipc/BluetoothMessageUtils.h"; using mozilla::dom::bluetooth::BluetoothAddress from "mozilla/dom/bluetooth/BluetoothCommon.h"; +using mozilla::dom::bluetooth::BluetoothGattAdvertisingData + from "mozilla/dom/bluetooth/BluetoothCommon.h"; using mozilla::dom::bluetooth::BluetoothObjectType from "mozilla/dom/bluetooth/BluetoothCommon.h"; using mozilla::dom::bluetooth::BluetoothPinCode @@ -70,6 +72,17 @@ struct StopLeScanRequest BluetoothUuid scanUuid; }; +struct StartAdvertisingRequest +{ + BluetoothUuid appUuid; + BluetoothGattAdvertisingData data; +}; + +struct StopAdvertisingRequest +{ + BluetoothUuid appUuid; +}; + struct PairRequest { BluetoothAddress address; @@ -348,6 +361,11 @@ struct GattClientWriteDescriptorValueRequest uint8_t[] value; }; +struct GattServerRegisterRequest +{ + BluetoothUuid appUuid; +}; + struct GattServerConnectPeripheralRequest { BluetoothUuid appUuid; @@ -444,6 +462,8 @@ union Request StopDiscoveryRequest; StartLeScanRequest; StopLeScanRequest; + StartAdvertisingRequest; + StopAdvertisingRequest; PairRequest; UnpairRequest; PinReplyRequest; @@ -491,6 +511,7 @@ union Request GattClientWriteCharacteristicValueRequest; GattClientReadDescriptorValueRequest; GattClientWriteDescriptorValueRequest; + GattServerRegisterRequest; GattServerConnectPeripheralRequest; GattServerDisconnectPeripheralRequest; UnregisterGattServerRequest; diff --git a/dom/webidl/BluetoothGattServer.webidl b/dom/webidl/BluetoothGattServer.webidl index 5dfe0e56b6..071bbdf9a7 100644 --- a/dom/webidl/BluetoothGattServer.webidl +++ b/dom/webidl/BluetoothGattServer.webidl @@ -4,6 +4,68 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ +dictionary BluetoothAdvertisingData +{ + /** + * Uuid value of Appearance characteristic of the GAP service which can be + * mapped to an icon or string that describes the physical representation of + * the device during the device discovery procedure. + */ + unsigned short appearance = 0; + + /** + * Whether to broadcast with device name or not. + */ + boolean includeDevName = false; + + /** + * Whether to broadcast with TX power or not. + */ + boolean includeTxPower = false; + + /** + * Company Identifier Code for manufacturer data. + * + * This ID will be combined with |manufacturerData| byte array specified + * below as the broadcasting manufacturer data. Please see Core Specification + * Supplement (CSS) v6 1.4 for more details. + */ + unsigned short manufacturerId = 0; + + /** + * Byte array of custom manufacturer specific data. + * + * These bytes will be appended to |manufacturerId| specified above as the + * broadcasting manufacturer data. Please see Core Specification Supplement + * (CSS) v6 1.4 for more details. + */ + ArrayBuffer? manufacturerData = null; + + /** + * 128-bit Service UUID for service data. + * + * This UUID will be combinded with |serviceData| specified below as the + * broadcasting service data. Please see Core Specification Supplement (CSS) + * v6 1.11 for more details. + */ + DOMString serviceUuid = ""; + + /** + * Data associated with |serviceUuid|. + * + * These bytes will be appended to |serviceUuid| specified above as the + * broadcasting manufacturer data. Please see Core Specification Supplement + * (CSS) v6 1.11 for more details. + */ + ArrayBuffer? serviceData = null; + + /** + * A list of Service or Service Class UUIDs. + * Please see Core Specification Supplement (CSS) v6 1.1 for more details. + */ + sequence serviceUuids = []; +}; + [CheckAnyPermissions="bluetooth"] interface BluetoothGattServer : EventTarget { @@ -28,6 +90,20 @@ interface BluetoothGattServer : EventTarget [NewObject] Promise disconnect(DOMString address); + /** + * Start or stop advertising data to nearby devices. + * + * Application may customize the advertising data by passing advData to + * |startAdvertising|. By performing |startAdvertising|, remote central + * devices can then discover and initiate a connection with our local device. + * A 'connectionstatechanged' event will be fired when a remote central + * device connects to the local device. + */ + [NewObject] + Promise startAdvertising(optional BluetoothAdvertisingData advData); + [NewObject] + Promise stopAdvertising(); + /** * Add a BLE service to the local GATT server. * diff --git a/dom/webidl/FontFace.webidl b/dom/webidl/FontFace.webidl index d4221a3973..136658cc7c 100644 --- a/dom/webidl/FontFace.webidl +++ b/dom/webidl/FontFace.webidl @@ -19,6 +19,7 @@ dictionary FontFaceDescriptors { DOMString unicodeRange = "U+0-10FFFF"; DOMString variant = "normal"; DOMString featureSettings = "normal"; + DOMString display = "auto"; }; enum FontFaceLoadStatus { "unloaded", "loading", "loaded", "error" }; @@ -37,6 +38,7 @@ interface FontFace { [SetterThrows] attribute DOMString unicodeRange; [SetterThrows] attribute DOMString variant; [SetterThrows] attribute DOMString featureSettings; + [SetterThrows, Pref="layout.css.font-display.enabled"] attribute DOMString display; readonly attribute FontFaceLoadStatus status; diff --git a/gfx/gl/GLTextureImage.cpp b/gfx/gl/GLTextureImage.cpp index 5663fb3dcd..b3dd425974 100644 --- a/gfx/gl/GLTextureImage.cpp +++ b/gfx/gl/GLTextureImage.cpp @@ -173,6 +173,7 @@ BasicTextureImage::EndUpdate() RefPtr updateData = updateSnapshot->GetDataSurface(); bool relative = FinishedSurfaceUpdate(); + bool needInit = mTextureState == Created; size_t uploadSize; mTextureFormat = UploadSurfaceToTexture(mGLContext, @@ -180,7 +181,7 @@ BasicTextureImage::EndUpdate() mUpdateRegion, mTexture, &uploadSize, - mTextureState == Created, + needInit, mUpdateOffset, relative); FinishedSurfaceUpload(); @@ -230,13 +231,14 @@ BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion } size_t uploadSize; + bool needInit = mTextureState == Created; mTextureFormat = UploadSurfaceToTexture(mGLContext, aSurf, region, mTexture, &uploadSize, - mTextureState == Created, + needInit, bounds.TopLeft() + IntPoint(aFrom.x, aFrom.y), false); if (uploadSize > 0) { diff --git a/gfx/gl/GLUploadHelpers.cpp b/gfx/gl/GLUploadHelpers.cpp index 0c52557b0d..9c8040dd95 100644 --- a/gfx/gl/GLUploadHelpers.cpp +++ b/gfx/gl/GLUploadHelpers.cpp @@ -434,12 +434,12 @@ UploadImageDataToTexture(GLContext* gl, const nsIntRegion& aDstRegion, GLuint& aTexture, size_t* aOutUploadSize, - bool aOverwrite, + bool aNeedInit, bool aPixelBuffer, GLenum aTextureUnit, GLenum aTextureTarget) { - bool textureInited = aOverwrite ? false : true; + bool textureInited = aNeedInit ? false : true; gl->MakeCurrent(); gl->fActiveTexture(aTextureUnit); @@ -612,7 +612,7 @@ UploadSurfaceToTexture(GLContext* gl, const nsIntRegion& aDstRegion, GLuint& aTexture, size_t* aOutUploadSize, - bool aOverwrite, + bool aNeedInit, const gfx::IntPoint& aSrcPoint, bool aPixelBuffer, GLenum aTextureUnit, @@ -624,7 +624,7 @@ UploadSurfaceToTexture(GLContext* gl, data += DataOffset(aSrcPoint, stride, format); return UploadImageDataToTexture(gl, data, stride, format, aDstRegion, aTexture, aOutUploadSize, - aOverwrite, aPixelBuffer, aTextureUnit, + aNeedInit, aPixelBuffer, aTextureUnit, aTextureTarget); } diff --git a/gfx/gl/GLUploadHelpers.h b/gfx/gl/GLUploadHelpers.h index 25a3348855..a641b45372 100644 --- a/gfx/gl/GLUploadHelpers.h +++ b/gfx/gl/GLUploadHelpers.h @@ -61,7 +61,7 @@ UploadImageDataToTexture(GLContext* gl, const nsIntRegion& aDstRegion, GLuint& aTexture, size_t* aOutUploadSize = nullptr, - bool aOverwrite = false, + bool aNeedInit = false, bool aPixelBuffer = false, GLenum aTextureUnit = LOCAL_GL_TEXTURE0, GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D); @@ -75,7 +75,7 @@ UploadSurfaceToTexture(GLContext* gl, const nsIntRegion& aDstRegion, GLuint& aTexture, size_t* aOutUploadSize = nullptr, - bool aOverwrite = false, + bool aNeedInit = false, const gfx::IntPoint& aSrcPoint = gfx::IntPoint(0, 0), bool aPixelBuffer = false, GLenum aTextureUnit = LOCAL_GL_TEXTURE0, diff --git a/gfx/gl/TextureImageEGL.cpp b/gfx/gl/TextureImageEGL.cpp index 31150f08b7..9e3da7765e 100644 --- a/gfx/gl/TextureImageEGL.cpp +++ b/gfx/gl/TextureImageEGL.cpp @@ -207,6 +207,7 @@ TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& region = aRegion; } + bool needInit = mTextureState == Created; size_t uploadSize = 0; mTextureFormat = UploadSurfaceToTexture(mGLContext, @@ -214,7 +215,7 @@ TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& region, mTexture, &uploadSize, - mTextureState == Created, + needInit, bounds.TopLeft() + gfx::IntPoint(aFrom.x, aFrom.y), false); if (uploadSize > 0) { diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index d8eb004969..b8fdedfb28 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -111,11 +111,13 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet, uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) : gfxFontEntry(NS_LITERAL_STRING("userfont")), mUserFontLoadState(STATUS_NOT_LOADED), mFontDataLoadingState(NOT_LOADING), mUnsupportedFormat(false), + mFontDisplay(aFontDisplay), mLoader(nullptr), mFontSet(aFontSet) { @@ -146,7 +148,8 @@ gfxUserFontEntry::Matches(const nsTArray& aFontFaceSrcList, uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { return mWeight == aWeight && mStretch == aStretch && @@ -154,6 +157,7 @@ gfxUserFontEntry::Matches(const nsTArray& aFontFaceSrcList, mFeatureSettings == aFeatureSettings && mLanguageOverride == aLanguageOverride && mSrcList == aFontFaceSrcList && + mFontDisplay == aFontDisplay && ((!aUnicodeRanges && !mCharacterMap) || (aUnicodeRanges && mCharacterMap && mCharacterMap->Equals(aUnicodeRanges))); } @@ -732,7 +736,8 @@ gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData, mLoader = nullptr; // download successful, make platform font using font data - if (NS_SUCCEEDED(aDownloadStatus)) { + if (NS_SUCCEEDED(aDownloadStatus) && + mFontDataLoadingState != LOADING_TIMED_OUT) { bool loaded = LoadPlatformFont(aFontData, aLength); aFontData = nullptr; @@ -744,7 +749,9 @@ gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData, } else { // download failed mFontSet->LogMessage(this, - "download failed", nsIScriptError::errorFlag, + (mFontDataLoadingState != LOADING_TIMED_OUT ? + "download failed" : "download timed out"), + nsIScriptError::errorFlag, aDownloadStatus); } @@ -752,8 +759,10 @@ gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData, moz_free((void*)aFontData); } - // error occurred, load next src - LoadNextSrc(); + // error occurred, load next src if load not yet timed out + if (mFontDataLoadingState != LOADING_TIMED_OUT) { + LoadNextSrc(); + } // We ignore the status returned by LoadNext(); // even if loading failed, we need to bump the font-set generation @@ -773,6 +782,7 @@ gfxUserFontEntry::GetUserFontSets(nsTArray& aResult) gfxUserFontSet::gfxUserFontSet() : mFontFamilies(4), mLocalRulesUsed(false), + mRebuildLocalRules(false), mDownloadCount(0), mDownloadSize(0) { @@ -800,7 +810,8 @@ gfxUserFontSet::FindOrCreateUserFontEntry( uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { RefPtr entry; @@ -815,13 +826,14 @@ gfxUserFontSet::FindOrCreateUserFontEntry( entry = FindExistingUserFontEntry(family, aFontFaceSrcList, aWeight, aStretch, aStyle, aFeatureSettings, aLanguageOverride, - aUnicodeRanges); + aUnicodeRanges, aFontDisplay); } if (!entry) { entry = CreateUserFontEntry(aFontFaceSrcList, aWeight, aStretch, aStyle, aFeatureSettings, - aLanguageOverride, aUnicodeRanges); + aLanguageOverride, aUnicodeRanges, + aFontDisplay); entry->mFamilyName = aFamilyName; } @@ -836,13 +848,14 @@ gfxUserFontSet::CreateUserFontEntry( uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { RefPtr userFontEntry = new gfxUserFontEntry(this, aFontFaceSrcList, aWeight, aStretch, aStyle, aFeatureSettings, - aLanguageOverride, aUnicodeRanges); + aLanguageOverride, aUnicodeRanges, aFontDisplay); return userFontEntry.forget(); } @@ -855,7 +868,8 @@ gfxUserFontSet::FindExistingUserFontEntry( uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { MOZ_ASSERT(aWeight != 0, "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead"); @@ -872,7 +886,7 @@ gfxUserFontSet::FindExistingUserFontEntry( if (!existingUserFontEntry->Matches(aFontFaceSrcList, aWeight, aStretch, aStyle, aFeatureSettings, aLanguageOverride, - aUnicodeRanges)) { + aUnicodeRanges, aFontDisplay)) { continue; } @@ -891,11 +905,12 @@ gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName, if (LOG_ENABLED()) { LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %d " - "stretch: %d", + "stretch: %d display: %d", this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry, (aUserFontEntry->IsItalic() ? "italic" : (aUserFontEntry->IsOblique() ? "oblique" : "normal")), - aUserFontEntry->Weight(), aUserFontEntry->Stretch())); + aUserFontEntry->Weight(), aUserFontEntry->Stretch(), + aUserFontEntry->GetFontDisplay())); } } @@ -942,6 +957,7 @@ void gfxUserFontSet::RebuildLocalRules() { if (mLocalRulesUsed) { + mRebuildLocalRules = true; DoRebuildUserFontSet(); } } diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 8403e306bd..12d1de4853 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -214,7 +214,8 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) = 0; + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) = 0; // creates a font face for the specified family, or returns an existing // matching entry on the family if there is one @@ -226,7 +227,8 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges); + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay); // add in a font face for which we have the gfxUserFontEntry already void AddUserFontEntry(const nsAString& aFamilyName, @@ -508,7 +510,8 @@ protected: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges); + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay); // creates a new gfxUserFontFamily in mFontFamilies, or returns an existing // family if there is one @@ -523,6 +526,9 @@ protected: // true when local names have been looked up, false otherwise bool mLocalRulesUsed; + // true when rules using local names need to be redone + bool mRebuildLocalRules; + // performance stats uint32_t mDownloadCount; uint64_t mDownloadSize; @@ -551,7 +557,8 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges); + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay); virtual ~gfxUserFontEntry(); @@ -562,7 +569,8 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges); + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay); virtual gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold); @@ -591,6 +599,8 @@ public: return mCharacterMap.get(); } + uint8_t GetFontDisplay() const { return mFontDisplay; } + // load the font - starts the loading of sources which continues until // a valid font resource is found or all sources fail void Load(); @@ -665,11 +675,13 @@ protected: // so keep hiding fallback font LOADING_SLOWLY, // timeout happened and we're not nearly done, // so use the fallback font + LOADING_TIMED_OUT, // font load took too long LOADING_FAILED // failed to load any source: use fallback }; FontDataLoadingState mFontDataLoadingState; bool mUnsupportedFormat; + uint8_t mFontDisplay; // timing of userfont fallback RefPtr mPlatformFontEntry; nsTArray mSrcList; diff --git a/hal/gonk/GonkSensorsHelpers.cpp b/hal/gonk/GonkSensorsHelpers.cpp new file mode 100644 index 0000000000..ccc940c7c0 --- /dev/null +++ b/hal/gonk/GonkSensorsHelpers.cpp @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 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 "GonkSensorsHelpers.h" + +namespace mozilla { +namespace hal { + +// +// Unpacking +// + +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, SensorsEvent& aOut) +{ + nsresult rv = UnpackPDU(aPDU, aOut.mType); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aOut.mTimestamp); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aOut.mStatus); + if (NS_FAILED(rv)) { + return rv; + } + + size_t i = 0; + + switch (aOut.mType) { + case SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + case SENSORS_TYPE_GYROSCOPE_UNCALIBRATED: + /* 6 data values */ + rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); + if (NS_FAILED(rv)) { + return rv; + } + /* fall through */ + case SENSORS_TYPE_ROTATION_VECTOR: + case SENSORS_TYPE_GAME_ROTATION_VECTOR: + case SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR: + /* 5 data values */ + rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); + if (NS_FAILED(rv)) { + return rv; + } + /* fall through */ + case SENSORS_TYPE_ACCELEROMETER: + case SENSORS_TYPE_GEOMAGNETIC_FIELD: + case SENSORS_TYPE_ORIENTATION: + case SENSORS_TYPE_GYROSCOPE: + case SENSORS_TYPE_GRAVITY: + case SENSORS_TYPE_LINEAR_ACCELERATION: + /* 3 data values */ + rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); + if (NS_FAILED(rv)) { + return rv; + } + /* fall through */ + case SENSORS_TYPE_LIGHT: + case SENSORS_TYPE_PRESSURE: + case SENSORS_TYPE_TEMPERATURE: + case SENSORS_TYPE_PROXIMITY: + case SENSORS_TYPE_RELATIVE_HUMIDITY: + case SENSORS_TYPE_AMBIENT_TEMPERATURE: + case SENSORS_TYPE_HEART_RATE: + case SENSORS_TYPE_TILT_DETECTOR: + case SENSORS_TYPE_WAKE_GESTURE: + case SENSORS_TYPE_GLANCE_GESTURE: + case SENSORS_TYPE_PICK_UP_GESTURE: + case SENSORS_TYPE_WRIST_TILT_GESTURE: + case SENSORS_TYPE_SIGNIFICANT_MOTION: + case SENSORS_TYPE_STEP_DETECTED: + /* 1 data value */ + rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); + if (NS_FAILED(rv)) { + return rv; + } + break; + case SENSORS_TYPE_STEP_COUNTER: + /* 1 data value */ + rv = UnpackPDU(aPDU, aOut.mData.mUint[0]); + if (NS_FAILED(rv)) { + return rv; + } + break; + default: + if (MOZ_HAL_IPC_UNPACK_WARN_IF(true, SensorsEvent)) { + return NS_ERROR_ILLEGAL_VALUE; + } + } + rv = UnpackPDU(aPDU, aOut.mDeliveryMode); + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; +} + +} // namespace hal +} // namespace mozilla diff --git a/hal/gonk/GonkSensorsHelpers.h b/hal/gonk/GonkSensorsHelpers.h new file mode 100644 index 0000000000..5218af53af --- /dev/null +++ b/hal/gonk/GonkSensorsHelpers.h @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 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 hal_gonk_GonkSensorsHelpers_h +#define hal_gonk_GonkSensorsHelpers_h + +#include +#include +#include "SensorsTypes.h" + +namespace mozilla { +namespace hal { + +using mozilla::ipc::DaemonSocketPDU; +using mozilla::ipc::DaemonSocketPDUHeader; +using mozilla::ipc::DaemonSocketPDUHelpers::Convert; +using mozilla::ipc::DaemonSocketPDUHelpers::PackPDU; +using mozilla::ipc::DaemonSocketPDUHelpers::UnpackPDU; + +using namespace mozilla::ipc::DaemonSocketPDUHelpers; + +// +// Conversion +// +// The functions below convert the input value to the output value's +// type and perform extension tests on the validity of the result. On +// success the output value will be returned in |aOut|. The functions +// return NS_OK on success, or an XPCOM error code otherwise. +// +// See the documentation of the HAL IPC framework for more information +// on conversion functions. +// + +nsresult +Convert(int32_t aIn, SensorsStatus& aOut) +{ + static const uint8_t sStatus[] = { + [0] = SENSORS_STATUS_NO_CONTACT, // '-1' + [1] = SENSORS_STATUS_UNRELIABLE, // '0' + [2] = SENSORS_STATUS_ACCURACY_LOW, // '1' + [3] = SENSORS_STATUS_ACCURACY_MEDIUM, // '2' + [4] = SENSORS_STATUS_ACCURACY_HIGH // '3' + }; + static const int8_t sOffset = -1; // '-1' is the lower bound of the status + + if (MOZ_HAL_IPC_CONVERT_WARN_IF(aIn < sOffset, int32_t, SensorsStatus) || + MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn >= (static_cast(MOZ_ARRAY_LENGTH(sStatus)) + sOffset), + int32_t, SensorsStatus)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(sStatus[aIn - sOffset]); + return NS_OK; +} + +nsresult +Convert(uint8_t aIn, SensorsDeliveryMode& aOut) +{ + static const uint8_t sMode[] = { + [0x00] = SENSORS_DELIVERY_MODE_BEST_EFFORT, + [0x01] = SENSORS_DELIVERY_MODE_IMMEDIATE + }; + if (MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn >= MOZ_ARRAY_LENGTH(sMode), uint8_t, SensorsDeliveryMode)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(sMode[aIn]); + return NS_OK; +} + +nsresult +Convert(uint8_t aIn, SensorsError& aOut) +{ + static const uint8_t sError[] = { + [0x00] = SENSORS_ERROR_NONE, + [0x01] = SENSORS_ERROR_FAIL, + [0x02] = SENSORS_ERROR_NOT_READY, + [0x03] = SENSORS_ERROR_NOMEM, + [0x04] = SENSORS_ERROR_BUSY, + [0x05] = SENSORS_ERROR_DONE, + [0x06] = SENSORS_ERROR_UNSUPPORTED, + [0x07] = SENSORS_ERROR_PARM_INVALID + }; + if (MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn >= MOZ_ARRAY_LENGTH(sError), uint8_t, SensorsError)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(sError[aIn]); + return NS_OK; +} + +nsresult +Convert(uint8_t aIn, SensorsTriggerMode& aOut) +{ + static const uint8_t sMode[] = { + [0x00] = SENSORS_TRIGGER_MODE_CONTINUOUS, + [0x01] = SENSORS_TRIGGER_MODE_ON_CHANGE, + [0x02] = SENSORS_TRIGGER_MODE_ONE_SHOT, + [0x03] = SENSORS_TRIGGER_MODE_SPECIAL + }; + if (MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn >= MOZ_ARRAY_LENGTH(sMode), uint8_t, SensorsTriggerMode)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(sMode[aIn]); + return NS_OK; +} + +nsresult +Convert(uint32_t aIn, SensorsType& aOut) +{ + static const uint8_t sType[] = { + [0x00] = 0, // invalid, required by gcc + [0x01] = SENSORS_TYPE_ACCELEROMETER, + [0x02] = SENSORS_TYPE_GEOMAGNETIC_FIELD, + [0x03] = SENSORS_TYPE_ORIENTATION, + [0x04] = SENSORS_TYPE_GYROSCOPE, + [0x05] = SENSORS_TYPE_LIGHT, + [0x06] = SENSORS_TYPE_PRESSURE, + [0x07] = SENSORS_TYPE_TEMPERATURE, + [0x08] = SENSORS_TYPE_PROXIMITY, + [0x09] = SENSORS_TYPE_GRAVITY, + [0x0a] = SENSORS_TYPE_LINEAR_ACCELERATION, + [0x0b] = SENSORS_TYPE_ROTATION_VECTOR, + [0x0c] = SENSORS_TYPE_RELATIVE_HUMIDITY, + [0x0d] = SENSORS_TYPE_AMBIENT_TEMPERATURE, + [0x0e] = SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED, + [0x0f] = SENSORS_TYPE_GAME_ROTATION_VECTOR, + [0x10] = SENSORS_TYPE_GYROSCOPE_UNCALIBRATED, + [0x11] = SENSORS_TYPE_SIGNIFICANT_MOTION, + [0x12] = SENSORS_TYPE_STEP_DETECTED, + [0x13] = SENSORS_TYPE_STEP_COUNTER, + [0x14] = SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR, + [0x15] = SENSORS_TYPE_HEART_RATE, + [0x16] = SENSORS_TYPE_TILT_DETECTOR, + [0x17] = SENSORS_TYPE_WAKE_GESTURE, + [0x18] = SENSORS_TYPE_GLANCE_GESTURE, + [0x19] = SENSORS_TYPE_PICK_UP_GESTURE, + [0x1a] = SENSORS_TYPE_WRIST_TILT_GESTURE + }; + if (MOZ_HAL_IPC_CONVERT_WARN_IF( + !aIn, uint32_t, SensorsType) || + MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn >= MOZ_ARRAY_LENGTH(sType), uint32_t, SensorsType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(sType[aIn]); + return NS_OK; +} + +nsresult +Convert(nsresult aIn, SensorsError& aOut) +{ + if (NS_SUCCEEDED(aIn)) { + aOut = SENSORS_ERROR_NONE; + } else if (aIn == NS_ERROR_OUT_OF_MEMORY) { + aOut = SENSORS_ERROR_NOMEM; + } else if (aIn == NS_ERROR_ILLEGAL_VALUE) { + aOut = SENSORS_ERROR_PARM_INVALID; + } else { + aOut = SENSORS_ERROR_FAIL; + } + return NS_OK; +} + +// +// Packing +// +// Pack functions store a value in PDU. See the documentation of the +// HAL IPC framework for more information. +// +// There are currently no sensor-specific pack functions necessary. If +// you add one, put it below. +// + +// +// Unpacking +// +// Unpack function retrieve a value from a PDU. The functions return +// NS_OK on success, or an XPCOM error code otherwise. On sucess, the +// returned value is stored in the second argument |aOut|. +// +// See the documentation of the HAL IPC framework for more information +// on unpack functions. +// + +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, SensorsDeliveryMode& aOut) +{ + return UnpackPDU(aPDU, UnpackConversion(aOut)); +} + +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, SensorsError& aOut) +{ + return UnpackPDU(aPDU, UnpackConversion(aOut)); +} + +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, SensorsEvent& aOut); + +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, SensorsStatus& aOut) +{ + return UnpackPDU(aPDU, UnpackConversion(aOut)); +} + +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, SensorsTriggerMode& aOut) +{ + return UnpackPDU(aPDU, UnpackConversion(aOut)); +} + +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, SensorsType& aOut) +{ + return UnpackPDU(aPDU, UnpackConversion(aOut)); +} + +} // namespace hal +} // namespace mozilla + +#endif // hal_gonk_GonkSensorsHelpers_h diff --git a/hal/gonk/SensorsTypes.h b/hal/gonk/SensorsTypes.h new file mode 100644 index 0000000000..35c852f5a8 --- /dev/null +++ b/hal/gonk/SensorsTypes.h @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 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 hal_gonk_SensorsTypes_h +#define hal_gonk_SensorsTypes_h + +namespace mozilla { +namespace hal { + +enum SensorsDeliveryMode { + SENSORS_DELIVERY_MODE_BEST_EFFORT, + SENSORS_DELIVERY_MODE_IMMEDIATE +}; + +enum SensorsError { + SENSORS_ERROR_NONE, + SENSORS_ERROR_FAIL, + SENSORS_ERROR_NOT_READY, + SENSORS_ERROR_NOMEM, + SENSORS_ERROR_BUSY, + SENSORS_ERROR_DONE, + SENSORS_ERROR_UNSUPPORTED, + SENSORS_ERROR_PARM_INVALID +}; + +enum SensorsStatus { + SENSORS_STATUS_NO_CONTACT, + SENSORS_STATUS_UNRELIABLE, + SENSORS_STATUS_ACCURACY_LOW, + SENSORS_STATUS_ACCURACY_MEDIUM, + SENSORS_STATUS_ACCURACY_HIGH +}; + +enum SensorsTriggerMode { + SENSORS_TRIGGER_MODE_CONTINUOUS, + SENSORS_TRIGGER_MODE_ON_CHANGE, + SENSORS_TRIGGER_MODE_ONE_SHOT, + SENSORS_TRIGGER_MODE_SPECIAL +}; + +enum SensorsType { + SENSORS_TYPE_ACCELEROMETER, + SENSORS_TYPE_GEOMAGNETIC_FIELD, + SENSORS_TYPE_ORIENTATION, + SENSORS_TYPE_GYROSCOPE, + SENSORS_TYPE_LIGHT, + SENSORS_TYPE_PRESSURE, + SENSORS_TYPE_TEMPERATURE, + SENSORS_TYPE_PROXIMITY, + SENSORS_TYPE_GRAVITY, + SENSORS_TYPE_LINEAR_ACCELERATION, + SENSORS_TYPE_ROTATION_VECTOR, + SENSORS_TYPE_RELATIVE_HUMIDITY, + SENSORS_TYPE_AMBIENT_TEMPERATURE, + SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED, + SENSORS_TYPE_GAME_ROTATION_VECTOR, + SENSORS_TYPE_GYROSCOPE_UNCALIBRATED, + SENSORS_TYPE_SIGNIFICANT_MOTION, + SENSORS_TYPE_STEP_DETECTED, + SENSORS_TYPE_STEP_COUNTER, + SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR, + SENSORS_TYPE_HEART_RATE, + SENSORS_TYPE_TILT_DETECTOR, + SENSORS_TYPE_WAKE_GESTURE, + SENSORS_TYPE_GLANCE_GESTURE, + SENSORS_TYPE_PICK_UP_GESTURE, + SENSORS_TYPE_WRIST_TILT_GESTURE, + SENSORS_NUM_TYPES +}; + +struct SensorsEvent { + SensorsType mType; + SensorsStatus mStatus; + SensorsDeliveryMode mDeliveryMode; + int64_t mTimestamp; + union { + float mFloat[6]; + uint64_t mUint[1]; + } mData; +}; + +/** + * |SensorsSensor| represents a device sensor; either single or composite. + */ +struct SensorsSensor { + SensorsSensor(int32_t aId, SensorsType aType, + float aRange, float aResolution, + float aPower, int32_t aMinPeriod, + int32_t aMaxPeriod, + SensorsTriggerMode aTriggerMode, + SensorsDeliveryMode aDeliveryMode) + : mId(aId) + , mType(aType) + , mRange(aRange) + , mResolution(aResolution) + , mPower(aPower) + , mMinPeriod(aMinPeriod) + , mMaxPeriod(aMaxPeriod) + , mTriggerMode(aTriggerMode) + , mDeliveryMode(aDeliveryMode) + { } + + int32_t mId; + SensorsType mType; + float mRange; + float mResolution; + float mPower; + int32_t mMinPeriod; + int32_t mMaxPeriod; + SensorsTriggerMode mTriggerMode; + SensorsDeliveryMode mDeliveryMode; +}; + +/** + * |SensorClass| represents the status of a specific sensor type. + */ +struct SensorsSensorClass { + SensorsSensorClass() + : mActivated(0) + , mMinValue(0) + , mMaxValue(0) + { } + + void UpdateFromSensor(const SensorsSensor& aSensor) + { + mMaxValue = std::max(aSensor.mRange, mMaxValue); + } + + uint32_t mActivated; + float mMinValue; + float mMaxValue; +}; + +} // namespace hal +} // namespace mozilla + +#endif // hal_gonk_SensorsTypes_h diff --git a/hal/moz.build b/hal/moz.build index 1c411b4bb0..2efa171493 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -48,6 +48,7 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': 'gonk/GonkDiskSpaceWatcher.cpp', 'gonk/GonkFMRadio.cpp', 'gonk/GonkSensor.cpp', + 'gonk/GonkSensorsHelpers.cpp', 'gonk/GonkSwitch.cpp', 'gonk/UeventPoller.cpp', 'linux/LinuxMemory.cpp', diff --git a/ipc/glue/ProtocolUtils.cpp b/ipc/glue/ProtocolUtils.cpp index 9951b74561..f6df3b0149 100644 --- a/ipc/glue/ProtocolUtils.cpp +++ b/ipc/glue/ProtocolUtils.cpp @@ -315,20 +315,18 @@ FatalError(const char* aProtocolName, const char* aMsg, formattedMessage.AppendLiteral("]: \""); formattedMessage.AppendASCII(aMsg); if (aIsParent) { - formattedMessage.AppendLiteral("\". Killing child side as a result."); +#ifdef MOZ_CRASHREPORTER + // We're going to crash the parent process because at this time + // there's no other really nice way of getting a minidump out of + // this process if we're off the main thread. + formattedMessage.AppendLiteral("\". Intentionally crashing."); NS_ERROR(formattedMessage.get()); - - if (aOtherPid != kInvalidProcessId && aOtherPid != base::GetCurrentProcId()) { - ScopedProcessHandle otherProcessHandle; - if (base::OpenProcessHandle(aOtherPid, &otherProcessHandle.rwget())) { - if (!base::KillProcess(otherProcessHandle, - base::PROCESS_END_KILLED_BY_USER, false)) { - NS_ERROR("May have failed to kill child!"); - } - } else { - NS_ERROR("Failed to open child process when attempting kill."); - } - } + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorProtocol"), + nsDependentCString(aProtocolName)); + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorMsg"), + nsDependentCString(aMsg)); +#endif + MOZ_CRASH("IPC FatalError in the parent process!"); } else { formattedMessage.AppendLiteral("\". abort()ing as a result."); NS_RUNTIMEABORT(formattedMessage.get()); diff --git a/ipc/hal/DaemonRunnables.h b/ipc/hal/DaemonRunnables.h index 03d6fa01a3..e067dd1411 100644 --- a/ipc/hal/DaemonRunnables.h +++ b/ipc/hal/DaemonRunnables.h @@ -713,6 +713,94 @@ private: Tin6 mArg6; }; +template +class DaemonNotificationRunnable8 final : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable8 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8), + const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8), + const InitOp& aInitOp) + { + RefPtr runnable = Create(aMethod, aInitOp); + if (!runnable) { + return; + } + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable))); + } + + NS_IMETHODIMP Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + if (!obj) { + NS_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4, + mArg5, mArg6, mArg7, mArg8); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable8( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult Init(const InitOp& aInitOp) + { + nsresult rv = aInitOp(mArg1, mArg2, mArg3, mArg4, + mArg5, mArg6, mArg7, mArg8); + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; + } + + Res (ObjectType::*mMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; + Tin4 mArg4; + Tin5 mArg5; + Tin6 mArg6; + Tin7 mArg7; + Tin8 mArg8; +}; + template = MAX_PAYLOAD_LENGTH) { + if (len >= PDU_MAX_PAYLOAD_LENGTH) { return NS_ERROR_ILLEGAL_VALUE; } uint16_t len16 = static_cast(len); - memcpy(GetData(OFF_LENGTH), &len16, sizeof(len16)); + memcpy(GetData(PDU_OFF_LENGTH), &len16, sizeof(len16)); return NS_OK; } @@ -177,9 +177,9 @@ DaemonSocketPDU::UpdateHeader() size_t DaemonSocketPDU::GetPayloadSize() const { - MOZ_ASSERT(GetSize() >= HEADER_SIZE); + MOZ_ASSERT(GetSize() >= PDU_HEADER_SIZE); - return GetSize() - HEADER_SIZE; + return GetSize() - PDU_HEADER_SIZE; } void diff --git a/ipc/hal/DaemonSocketPDU.h b/ipc/hal/DaemonSocketPDU.h index 2f0c9b152c..006b3ac3a2 100644 --- a/ipc/hal/DaemonSocketPDU.h +++ b/ipc/hal/DaemonSocketPDU.h @@ -39,12 +39,12 @@ class DaemonSocketPDU final : public UnixSocketIOBuffer { public: enum { - OFF_SERVICE = 0, - OFF_OPCODE = 1, - OFF_LENGTH = 2, - OFF_PAYLOAD = 4, - HEADER_SIZE = OFF_PAYLOAD, - MAX_PAYLOAD_LENGTH = 1 << 16 + PDU_OFF_SERVICE = 0, + PDU_OFF_OPCODE = 1, + PDU_OFF_LENGTH = 2, + PDU_OFF_PAYLOAD = 4, + PDU_HEADER_SIZE = PDU_OFF_PAYLOAD, + PDU_MAX_PAYLOAD_LENGTH = 1 << 16 }; DaemonSocketPDU(uint8_t aService, uint8_t aOpcode, uint16_t aPayloadSize); diff --git a/ipc/hal/DaemonSocketPDUHelpers.h b/ipc/hal/DaemonSocketPDUHelpers.h index f017a9269e..02f672f0ed 100644 --- a/ipc/hal/DaemonSocketPDUHelpers.h +++ b/ipc/hal/DaemonSocketPDUHelpers.h @@ -349,6 +349,42 @@ PackPDU(const PackReversed>& aIn, DaemonSocketPDU& aPDU) return NS_OK; } +/* |PackArray>| is a helper for packing data of each element in + * the reversed order. Pass an instance of this structure as the first argument + * to |PackPDU| to pack data of each array element in the reversed order. + * + * Unlike |PackReversed>| which packed array elements in the + * reversed order, here we use |PackReversed| to pack data of each element + * of |PackArray| in the reversed order. + */ +template +struct PackArray> +{ + PackArray(const U* aData, size_t aLength) + : mData(aData) + , mLength(aLength) + { } + + const U* mData; + size_t mLength; +}; + +/* This implementation of |PackPDU| packs data of each element in |PackArray| + * in the reversed order. (ex. reversed GATT UUID, see bug 1171866) + */ +template +inline nsresult +PackPDU(const PackArray>& aIn, DaemonSocketPDU& aPDU) +{ + for (size_t i = 0; i < aIn.mLength; ++i) { + nsresult rv = PackPDU(PackReversed(aIn.mData[i]), aPDU); + if (NS_FAILED(rv)) { + return rv; + } + } + return NS_OK; +} + template inline nsresult PackPDU(const T1& aIn1, const T2& aIn2, DaemonSocketPDU& aPDU) @@ -1106,6 +1142,136 @@ public: WarnAboutTrailingData(); return NS_OK; } + + template + nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4, + T5& aArg5, T6& aArg6, T7& aArg7) const + { + DaemonSocketPDU& pdu = GetPDU(); + + nsresult rv = UnpackPDU(pdu, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg2); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg3); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg4); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg5); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg6); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg7); + if (NS_FAILED(rv)) { + return rv; + } + WarnAboutTrailingData(); + return NS_OK; + } + + template + nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4, + T5& aArg5, T6& aArg6, T7& aArg7, T8& aArg8) const + { + DaemonSocketPDU& pdu = GetPDU(); + + nsresult rv = UnpackPDU(pdu, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg2); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg3); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg4); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg5); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg6); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg7); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg8); + if (NS_FAILED(rv)) { + return rv; + } + WarnAboutTrailingData(); + return NS_OK; + } + + template + nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4, + T5& aArg5, T6& aArg6, T7& aArg7, T8& aArg8, + T9& aArg9) const + { + DaemonSocketPDU& pdu = GetPDU(); + + nsresult rv = UnpackPDU(pdu, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg2); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg3); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg4); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg5); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg6); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg7); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg8); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(pdu, aArg9); + if (NS_FAILED(rv)) { + return rv; + } + WarnAboutTrailingData(); + return NS_OK; + } }; } // namespace DaemonSocketPDUHelpers diff --git a/js/src/jit-test/lib/jitopts.js b/js/src/jit-test/lib/jitopts.js index 587e56d44d..0d35a9e02c 100644 --- a/js/src/jit-test/lib/jitopts.js +++ b/js/src/jit-test/lib/jitopts.js @@ -9,6 +9,12 @@ function jitTogglesMatch(opts) { if (k.indexOf(".enable") > 0 && opts[k] != currentOpts[k]) return false; } + + // ARM64 does not yet have an Ion code generator, so return false if + // ion.enable is requested. + if (getBuildConfiguration()['arm64-simulator'] && opts['ion.enable']) + return false; + return true; } diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index 07f16bc688..01e0d4c1bc 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -219,7 +219,6 @@ class CodeGeneratorShared : public LElementVisitor inline Operand ToOperand(const LDefinition* def); protected: - #ifdef CHECK_OSIPOINT_REGISTERS void resetOsiPointRegs(LSafepoint* safepoint); bool shouldVerifyOsiPointRegs(LSafepoint* safepoint); diff --git a/layout/reftests/w3c-css/submitted/reftest.list b/layout/reftests/w3c-css/submitted/reftest.list index ae1f1b42ca..5740151d65 100644 --- a/layout/reftests/w3c-css/submitted/reftest.list +++ b/layout/reftests/w3c-css/submitted/reftest.list @@ -75,3 +75,6 @@ include values3/reftest.list # Variables Level 1 include variables/reftest.list + +# CSS will-change Level 1 +include will-change/reftest.list diff --git a/layout/reftests/w3c-css/submitted/will-change/green-square-100-by-100-ref.html b/layout/reftests/w3c-css/submitted/will-change/green-square-100-by-100-ref.html new file mode 100644 index 0000000000..d294b1ccfc --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/green-square-100-by-100-ref.html @@ -0,0 +1,12 @@ + + +CSS will-change reference + + + + +
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/reftest.list b/layout/reftests/w3c-css/submitted/will-change/reftest.list new file mode 100644 index 0000000000..06de58e725 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/reftest.list @@ -0,0 +1,12 @@ +== will-change-stacking-context-clip-path-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-filter-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-height-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-isolation-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-mask-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-mix-blend-mode-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-opacity-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-perspective-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-position-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-transform-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-transform-style-1.html green-square-100-by-100-ref.html +== will-change-stacking-context-z-index-1.html green-square-100-by-100-ref.html diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-clip-path-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-clip-path-1.html new file mode 100644 index 0000000000..817cdcf322 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-clip-path-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: clip-path' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-filter-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-filter-1.html new file mode 100644 index 0000000000..6241e5606c --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-filter-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: filter' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-height-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-height-1.html new file mode 100644 index 0000000000..025578236a --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-height-1.html @@ -0,0 +1,20 @@ + + +CSS will-change: 'will-change: height' does not create a stacking context + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-isolation-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-isolation-1.html new file mode 100644 index 0000000000..3935b7409a --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-isolation-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: isolation' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-mask-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-mask-1.html new file mode 100644 index 0000000000..69afd50df4 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-mask-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: mask' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-mix-blend-mode-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-mix-blend-mode-1.html new file mode 100644 index 0000000000..0dbfbe7fa9 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-mix-blend-mode-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: mix-blend-mode' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-opacity-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-opacity-1.html new file mode 100644 index 0000000000..9f0d345f17 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-opacity-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: opacity' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-perspective-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-perspective-1.html new file mode 100644 index 0000000000..b1180d2777 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-perspective-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: perspective' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-position-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-position-1.html new file mode 100644 index 0000000000..7c0e9b6949 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-position-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: position' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-transform-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-transform-1.html new file mode 100644 index 0000000000..e87b1c101b --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-transform-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: transform' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-transform-style-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-transform-style-1.html new file mode 100644 index 0000000000..08f3b2af64 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-transform-style-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: transform-style' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-z-index-1.html b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-z-index-1.html new file mode 100644 index 0000000000..b705e5a3ef --- /dev/null +++ b/layout/reftests/w3c-css/submitted/will-change/will-change-stacking-context-z-index-1.html @@ -0,0 +1,21 @@ + + +CSS will-change: 'will-change: z-index' creates a stacking context + + + + + + + + +
+
+
+
+ diff --git a/layout/style/FontFace.cpp b/layout/style/FontFace.cpp index 47b5b19265..3edbce8f53 100644 --- a/layout/style/FontFace.cpp +++ b/layout/style/FontFace.cpp @@ -355,6 +355,20 @@ FontFace::SetFeatureSettings(const nsAString& aValue, ErrorResult& aRv) SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv); } +void +FontFace::GetDisplay(nsString& aResult) +{ + mFontFaceSet->FlushUserFontSet(); + GetDesc(eCSSFontDesc_Display, eCSSProperty_UNKNOWN, aResult); +} + +void +FontFace::SetDisplay(const nsAString& aValue, ErrorResult& aRv) +{ + mFontFaceSet->FlushUserFontSet(); + SetDescriptor(eCSSFontDesc_Display, aValue, aRv); +} + FontFaceLoadStatus FontFace::Status() { @@ -548,7 +562,10 @@ FontFace::SetDescriptors(const nsAString& aFamily, mDescriptors->mUnicodeRange) || !ParseDescriptor(eCSSFontDesc_FontFeatureSettings, aDescriptors.mFeatureSettings, - mDescriptors->mFontFeatureSettings)) { + mDescriptors->mFontFeatureSettings) || + !ParseDescriptor(eCSSFontDesc_Display, + aDescriptors.mDisplay, + mDescriptors->mDisplay)) { // XXX Handle font-variant once we support it (bug 1055385). // If any of the descriptors failed to parse, none of them should be set @@ -584,6 +601,7 @@ FontFace::GetDesc(nsCSSFontDesc aDescID, nsString& aResult) const { MOZ_ASSERT(aDescID == eCSSFontDesc_UnicodeRange || + aDescID == eCSSFontDesc_Display || aPropID != eCSSProperty_UNKNOWN, "only pass eCSSProperty_UNKNOWN for eCSSFontDesc_UnicodeRange"); @@ -596,6 +614,8 @@ FontFace::GetDesc(nsCSSFontDesc aDescID, if (value.GetUnit() == eCSSUnit_Null) { if (aDescID == eCSSFontDesc_UnicodeRange) { aResult.AssignLiteral("U+0-10FFFF"); + } else if (aDescID == eCSSFontDesc_Display) { + aResult.AssignLiteral("auto"); } else if (aDescID != eCSSFontDesc_Family && aDescID != eCSSFontDesc_Src) { aResult.AssignLiteral("normal"); @@ -607,6 +627,10 @@ FontFace::GetDesc(nsCSSFontDesc aDescID, // Since there's no unicode-range property, we can't use // nsCSSValue::AppendToString to serialize this descriptor. nsStyleUtil::AppendUnicodeRange(value, aResult); + } else if (aDescID == eCSSFontDesc_Display) { + AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(value.GetIntValue(), + nsCSSProps::kFontDisplayKTable), + aResult); } else { value.AppendToString(aPropID, aResult, nsCSSValue::eNormalized); } diff --git a/layout/style/FontFace.h b/layout/style/FontFace.h index 41085dd564..11e2de50f6 100644 --- a/layout/style/FontFace.h +++ b/layout/style/FontFace.h @@ -47,10 +47,11 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) : gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch, aStyle, aFeatureSettings, aLanguageOverride, - aUnicodeRanges) {} + aUnicodeRanges, aFontDisplay) {} virtual void SetLoadState(UserFontLoadState aLoadState) override; virtual void GetUserFontSets(nsTArray& aResult) override; @@ -150,6 +151,8 @@ public: void SetVariant(const nsAString& aValue, mozilla::ErrorResult& aRv); void GetFeatureSettings(nsString& aResult); void SetFeatureSettings(const nsAString& aValue, mozilla::ErrorResult& aRv); + void GetDisplay(nsString& aResult); + void SetDisplay(const nsAString& aValue, mozilla::ErrorResult& aRv); mozilla::dom::FontFaceLoadStatus Status(); mozilla::dom::Promise* Load(mozilla::ErrorResult& aRv); diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index af3c18ab4d..ca1e02c625 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -789,14 +789,17 @@ FontFaceSet::UpdateRules(const nsTArray& aRules) CheckLoadingFinished(); } - // local rules have been rebuilt, so clear the flag - mUserFontSet->mLocalRulesUsed = false; + // if local rules needed to be rebuilt, they have been rebuilt at this point + if (mUserFontSet->mRebuildLocalRules) { + mUserFontSet->mLocalRulesUsed = false; + mUserFontSet->mRebuildLocalRules = false; + } if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) { - LOG(("userfonts (%p) userfont rules update (%s) rule count: %" PRIuSIZE, + LOG(("userfonts (%p) userfont rules update (%s) rule count: %d", mUserFontSet.get(), (modified ? "modified" : "not modified"), - mRuleFaces.Length())); + (int)(mRuleFaces.Length()))); } return modified; @@ -875,7 +878,8 @@ FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType, // if local rules were used, don't use the old font entry // for rules containing src local usage - if (mUserFontSet->mLocalRulesUsed) { + if (mUserFontSet->mLocalRulesUsed && + mUserFontSet->mRebuildLocalRules) { nsCSSValue val; aFontFace->GetDesc(eCSSFontDesc_Src, val); nsCSSUnit unit = val.GetUnit(); @@ -978,6 +982,7 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName, int32_t stretch = NS_STYLE_FONT_STRETCH_NORMAL; uint8_t italicStyle = NS_STYLE_FONT_STYLE_NORMAL; uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE; + uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO; // set up weight aFontFace->GetDesc(eCSSFontDesc_Weight, val); @@ -1018,6 +1023,16 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName, "@font-face style has unexpected unit"); } + // set up font display + aFontFace->GetDesc(eCSSFontDesc_Display, val); + unit = val.GetUnit(); + if (unit == eCSSUnit_Enumerated) { + fontDisplay = val.GetIntValue(); + } else { + NS_ASSERTION(unit == eCSSUnit_Null, + "@font-face style has unexpected unit"); + } + // set up font features nsTArray featureSettings; aFontFace->GetDesc(eCSSFontDesc_FontFeatureSettings, val); @@ -1163,7 +1178,7 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName, stretch, italicStyle, featureSettings, languageOverride, - unicodeRanges); + unicodeRanges, fontDisplay); return entry.forget(); } @@ -1807,11 +1822,13 @@ FontFaceSet::UserFontSet::CreateUserFontEntry( uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { RefPtr entry = new FontFace::Entry(this, aFontFaceSrcList, aWeight, aStretch, aStyle, - aFeatureSettings, aLanguageOverride, aUnicodeRanges); + aFeatureSettings, aLanguageOverride, aUnicodeRanges, + aFontDisplay); return entry.forget(); } diff --git a/layout/style/FontFaceSet.h b/layout/style/FontFaceSet.h index a18734368a..46a769bd7f 100644 --- a/layout/style/FontFaceSet.h +++ b/layout/style/FontFaceSet.h @@ -89,7 +89,8 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) override; + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) override; private: RefPtr mFontFaceSet; diff --git a/layout/style/nsCSSPropAliasList.h b/layout/style/nsCSSPropAliasList.h index fe079695ed..e03bac56c6 100644 --- a/layout/style/nsCSSPropAliasList.h +++ b/layout/style/nsCSSPropAliasList.h @@ -220,6 +220,10 @@ CSS_PROP_ALIAS(-webkit-animation-timing-function, WebkitAnimationTimingFunction, WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-filter, + filter, + WebkitFilter, + WEBKIT_PREFIX_PREF) CSS_PROP_ALIAS(-webkit-text-size-adjust, text_size_adjust, WebkitTextSizeAdjust, @@ -313,26 +317,6 @@ CSS_PROP_ALIAS(-webkit-border-image, border_image, WebkitBorderImage, WEBKIT_PREFIX_PREF) -CSS_PROP_ALIAS(-webkit-border-image-outset, - border_image_outset, - WebkitBorderImageOutset, - WEBKIT_PREFIX_PREF) -CSS_PROP_ALIAS(-webkit-border-image-repeat, - border_image_repeat, - WebkitBorderImageRepeat, - WEBKIT_PREFIX_PREF) -CSS_PROP_ALIAS(-webkit-border-image-slice, - border_image_slice, - WebkitBorderImageSlice, - WEBKIT_PREFIX_PREF) -CSS_PROP_ALIAS(-webkit-border-image-source, - border_image_source, - WebkitBorderImageSource, - WEBKIT_PREFIX_PREF) -CSS_PROP_ALIAS(-webkit-border-image-width, - border_image_width, - WebkitBorderImageWidth, - WEBKIT_PREFIX_PREF) CSS_PROP_ALIAS(-webkit-box-shadow, box_shadow, diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index e04b0c37a4..e45b503ff7 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -1589,8 +1589,8 @@ CSS_PROP_POSITION( AlignContent, CSS_PROPERTY_PARSE_FUNCTION, "", - 0, - nullptr, + VARIANT_HK, + kAutoCompletionAlignJustifyContent, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_POSITION( @@ -1599,8 +1599,8 @@ CSS_PROP_POSITION( AlignItems, CSS_PROPERTY_PARSE_FUNCTION, "", - 0, - nullptr, + VARIANT_HK, + kAutoCompletionAlignItems, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_POSITION( @@ -1609,8 +1609,8 @@ CSS_PROP_POSITION( AlignSelf, CSS_PROPERTY_PARSE_FUNCTION, "", - 0, - nullptr, + VARIANT_HK, + kAutoCompletionAlignJustifySelf, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_SHORTHAND( @@ -1720,8 +1720,8 @@ CSS_PROP_POSITION( JustifyContent, CSS_PROPERTY_PARSE_FUNCTION, "", - 0, - nullptr, + VARIANT_HK, + kAutoCompletionAlignJustifyContent, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_POSITION( @@ -1730,8 +1730,9 @@ CSS_PROP_POSITION( JustifyItems, CSS_PROPERTY_PARSE_FUNCTION, "", - 0, - nullptr, + VARIANT_HK, + // for auto-completion we use same values as justify-self: + kAutoCompletionAlignJustifySelf, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_POSITION( @@ -1740,8 +1741,8 @@ CSS_PROP_POSITION( JustifySelf, CSS_PROPERTY_PARSE_FUNCTION, "", - 0, - nullptr, + VARIANT_HK, + kAutoCompletionAlignJustifySelf, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_DISPLAY( @@ -2724,7 +2725,8 @@ CSS_PROP_DISPLAY( Opacity, CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_APPLIES_TO_PLACEHOLDER | - CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR, + CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR | + CSS_PROPERTY_CREATES_STACKING_CONTEXT, "", VARIANT_HN, nullptr, @@ -3959,8 +3961,7 @@ CSS_PROP_SVG( fill, fill, Fill, - CSS_PROPERTY_PARSE_FUNCTION | - CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED, + CSS_PROPERTY_PARSE_FUNCTION, "", 0, kContextPatternKTable, @@ -4217,8 +4218,7 @@ CSS_PROP_SVG( stroke, stroke, Stroke, - CSS_PROPERTY_PARSE_FUNCTION | - CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED, + CSS_PROPERTY_PARSE_FUNCTION, "", 0, kContextPatternKTable, diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 4826599059..89ad26ff9e 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -1383,6 +1383,63 @@ const KTableEntry nsCSSProps::kAlignContentPosition[] = { { eCSSKeyword_UNKNOWN, -1 } }; +// these are only used for auto-completion, not parsing: +const KTableEntry nsCSSProps::kAutoCompletionAlignJustifySelf[] = { + { eCSSKeyword_auto, NS_STYLE_ALIGN_AUTO }, + { eCSSKeyword_normal, NS_STYLE_ALIGN_NORMAL }, + { eCSSKeyword_stretch, NS_STYLE_ALIGN_STRETCH }, + { eCSSKeyword_baseline, NS_STYLE_ALIGN_BASELINE }, + { eCSSKeyword_last_baseline, NS_STYLE_ALIGN_LAST_BASELINE }, + { eCSSKeyword_start, NS_STYLE_ALIGN_START }, + { eCSSKeyword_end, NS_STYLE_ALIGN_END }, + { eCSSKeyword_flex_start, NS_STYLE_ALIGN_FLEX_START }, + { eCSSKeyword_flex_end, NS_STYLE_ALIGN_FLEX_END }, + { eCSSKeyword_center, NS_STYLE_ALIGN_CENTER }, + { eCSSKeyword_left, NS_STYLE_ALIGN_LEFT }, + { eCSSKeyword_right, NS_STYLE_ALIGN_RIGHT }, + { eCSSKeyword_self_start, NS_STYLE_ALIGN_SELF_START }, + { eCSSKeyword_self_end, NS_STYLE_ALIGN_SELF_END }, + { eCSSKeyword_UNKNOWN, -1 } +}; + +const KTableEntry nsCSSProps::kAutoCompletionAlignItems[] = { + // Intentionally no 'auto' here. + { eCSSKeyword_normal, NS_STYLE_ALIGN_NORMAL }, + { eCSSKeyword_stretch, NS_STYLE_ALIGN_STRETCH }, + { eCSSKeyword_baseline, NS_STYLE_ALIGN_BASELINE }, + { eCSSKeyword_last_baseline, NS_STYLE_ALIGN_LAST_BASELINE }, + { eCSSKeyword_start, NS_STYLE_ALIGN_START }, + { eCSSKeyword_end, NS_STYLE_ALIGN_END }, + { eCSSKeyword_flex_start, NS_STYLE_ALIGN_FLEX_START }, + { eCSSKeyword_flex_end, NS_STYLE_ALIGN_FLEX_END }, + { eCSSKeyword_center, NS_STYLE_ALIGN_CENTER }, + { eCSSKeyword_left, NS_STYLE_ALIGN_LEFT }, + { eCSSKeyword_right, NS_STYLE_ALIGN_RIGHT }, + { eCSSKeyword_self_start, NS_STYLE_ALIGN_SELF_START }, + { eCSSKeyword_self_end, NS_STYLE_ALIGN_SELF_END }, + { eCSSKeyword_UNKNOWN, -1 } +}; + +const KTableEntry nsCSSProps::kAutoCompletionAlignJustifyContent[] = { + // Intentionally no 'auto' here. + { eCSSKeyword_normal, NS_STYLE_ALIGN_NORMAL }, + { eCSSKeyword_baseline, NS_STYLE_ALIGN_BASELINE }, + { eCSSKeyword_last_baseline, NS_STYLE_ALIGN_LAST_BASELINE }, + { eCSSKeyword_stretch, NS_STYLE_ALIGN_STRETCH }, + { eCSSKeyword_space_between, NS_STYLE_ALIGN_SPACE_BETWEEN }, + { eCSSKeyword_space_around, NS_STYLE_ALIGN_SPACE_AROUND }, + { eCSSKeyword_space_evenly, NS_STYLE_ALIGN_SPACE_EVENLY }, + { eCSSKeyword_start, NS_STYLE_ALIGN_START }, + { eCSSKeyword_end, NS_STYLE_ALIGN_END }, + { eCSSKeyword_flex_start, NS_STYLE_ALIGN_FLEX_START }, + { eCSSKeyword_flex_end, NS_STYLE_ALIGN_FLEX_END }, + { eCSSKeyword_center, NS_STYLE_ALIGN_CENTER }, + { eCSSKeyword_left, NS_STYLE_ALIGN_LEFT }, + { eCSSKeyword_right, NS_STYLE_ALIGN_RIGHT }, + { eCSSKeyword_UNKNOWN, -1 } +}; +// + const KTableEntry nsCSSProps::kFlexDirectionKTable[] = { { eCSSKeyword_row, NS_STYLE_FLEX_DIRECTION_ROW }, { eCSSKeyword_row_reverse, NS_STYLE_FLEX_DIRECTION_ROW_REVERSE }, diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h index 742daa9cb6..3e8897cd8d 100644 --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -726,7 +726,7 @@ public: static KTableEntry kDisplayKTable[]; static const KTableEntry kElevationKTable[]; static const KTableEntry kEmptyCellsKTable[]; - // -- tables for the align-/justify-content/items/self properties -- + // -- tables for parsing the {align,justify}-{content,items,self} properties -- static const KTableEntry kAlignAllKeywords[]; static const KTableEntry kAlignOverflowPosition[]; // static const KTableEntry kAlignSelfPosition[]; // @@ -737,8 +737,10 @@ public: static const KTableEntry kAlignNormalBaseline[]; // 'normal/baseline/last-baseline' static const KTableEntry kAlignContentDistribution[]; // static const KTableEntry kAlignContentPosition[]; // - static const KTableEntry kAlignSelfKTable[]; - static const KTableEntry kJustifyContentKTable[]; + // -- tables for auto-completion of the {align,justify}-{content,items,self} properties -- + static const KTableEntry kAutoCompletionAlignJustifySelf[]; + static const KTableEntry kAutoCompletionAlignItems[]; + static const KTableEntry kAutoCompletionAlignJustifyContent[]; // ------------------------------------------------------------------ static const KTableEntry kFlexDirectionKTable[]; static const KTableEntry kFlexWrapKTable[]; diff --git a/layout/style/nsFontFaceLoader.cpp b/layout/style/nsFontFaceLoader.cpp index 2b8fb0698b..15c97d3055 100644 --- a/layout/style/nsFontFaceLoader.cpp +++ b/layout/style/nsFontFaceLoader.cpp @@ -31,6 +31,18 @@ using namespace mozilla::dom; #define LOG_ENABLED() MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), \ LogLevel::Debug) +static uint32_t +GetFallbackDelay() +{ + return Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000); +} + +static uint32_t +GetShortFallbackDelay() +{ + return Preferences::GetInt("gfx.downloadable_fonts.fallback_delay_short", 100); +} + nsFontFaceLoader::nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry, nsIURI* aFontURI, FontFaceSet* aFontFaceSet, @@ -60,8 +72,15 @@ nsFontFaceLoader::~nsFontFaceLoader() void nsFontFaceLoader::StartedLoading(nsIStreamLoader* aStreamLoader) { - int32_t loadTimeout = - Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000); + int32_t loadTimeout; + uint8_t fontDisplay = GetFontDisplay(); + if (fontDisplay == NS_FONT_DISPLAY_AUTO || + fontDisplay == NS_FONT_DISPLAY_BLOCK) { + loadTimeout = GetFallbackDelay(); + } else { + loadTimeout = GetShortFallbackDelay(); + } + if (loadTimeout > 0) { mLoadTimer = do_CreateInstance("@mozilla.org/timer;1"); if (mLoadTimer) { @@ -87,39 +106,72 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure) } gfxUserFontEntry* ufe = loader->mUserFontEntry.get(); - bool updateUserFontSet = true; + uint8_t fontDisplay = loader->GetFontDisplay(); - // If the entry is loading, check whether it's >75% done; if so, - // we allow another timeout period before showing a fallback font. - if (ufe->mFontDataLoadingState == gfxUserFontEntry::LOADING_STARTED) { - int64_t contentLength; - uint32_t numBytesRead; - if (NS_SUCCEEDED(loader->mChannel->GetContentLength(&contentLength)) && - contentLength > 0 && - contentLength < UINT32_MAX && - NS_SUCCEEDED(loader->mStreamLoader->GetNumBytesRead(&numBytesRead)) && - numBytesRead > 3 * (uint32_t(contentLength) >> 2)) - { - // More than 3/4 the data has been downloaded, so allow 50% extra - // time and hope the remainder will arrive before the additional - // time expires. - ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_ALMOST_DONE; - uint32_t delay; - loader->mLoadTimer->GetDelay(&delay); - loader->mLoadTimer->InitWithFuncCallback(LoadTimerCallback, - static_cast(loader), - delay >> 1, - nsITimer::TYPE_ONE_SHOT); - updateUserFontSet = false; - LOG(("userfonts (%p) 75%% done, resetting timer\n", loader)); + // Depending upon the value of the font-display descriptor for the font, + // their may be one or two timeouts associated with each font. The LOADING_SLOWLY + // state indicates that the fallback font is shown. The LOADING_TIMED_OUT + // state indicates that the fallback font is shown *and* the downloaded font + // resource will not replace the fallback font when the load completes. + + bool updateUserFontSet = true; + switch (fontDisplay) { + case NS_FONT_DISPLAY_AUTO: + case NS_FONT_DISPLAY_BLOCK: + // If the entry is loading, check whether it's >75% done; if so, + // we allow another timeout period before showing a fallback font. + if (ufe->mFontDataLoadingState == gfxUserFontEntry::LOADING_STARTED) { + int64_t contentLength; + uint32_t numBytesRead; + if (NS_SUCCEEDED(loader->mChannel->GetContentLength(&contentLength)) && + contentLength > 0 && + contentLength < UINT32_MAX && + NS_SUCCEEDED(loader->mStreamLoader->GetNumBytesRead(&numBytesRead)) && + numBytesRead > 3 * (uint32_t(contentLength) >> 2)) + { + // More than 3/4 the data has been downloaded, so allow 50% extra + // time and hope the remainder will arrive before the additional + // time expires. + ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_ALMOST_DONE; + uint32_t delay; + loader->mLoadTimer->GetDelay(&delay); + loader->mLoadTimer->InitWithFuncCallback(LoadTimerCallback, + static_cast(loader), + delay >> 1, + nsITimer::TYPE_ONE_SHOT); + updateUserFontSet = false; + LOG(("userfonts (%p) 75%% done, resetting timer\n", loader)); + } + } + if (updateUserFontSet) { + ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY; + } + break; + case NS_FONT_DISPLAY_SWAP: + ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY; + break; + case NS_FONT_DISPLAY_FALLBACK: { + if (ufe->mFontDataLoadingState == gfxUserFontEntry::LOADING_STARTED) { + ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY; + } else { + ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_TIMED_OUT; + updateUserFontSet = false; + } + break; } + case NS_FONT_DISPLAY_OPTIONAL: + ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_TIMED_OUT; + break; + + default: + NS_NOTREACHED("strange font-display value"); + break; } // If the font is not 75% loaded, or if we've already timed out once // before, we mark this entry as "loading slowly", so the fallback // font will be used in the meantime, and tell the context to refresh. if (updateUserFontSet) { - ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY; nsTArray fontSets; ufe->GetUserFontSets(fontSets); for (gfxUserFontSet* fontSet : fontSets) { @@ -127,8 +179,8 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure) if (ctx) { fontSet->IncrementGeneration(); ctx->UserFontSetUpdated(ufe); - LOG(("userfonts (%p) timeout reflow for pres context %p\n", - loader, ctx)); + LOG(("userfonts (%p) timeout reflow for pres context %p display %d\n", + loader, ctx, fontDisplay)); } } } @@ -155,6 +207,16 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader, uint32_t downloadTimeMS = uint32_t(downloadTime.ToMilliseconds()); Telemetry::Accumulate(Telemetry::WEBFONT_DOWNLOAD_TIME, downloadTimeMS); + if (GetFontDisplay() == NS_FONT_DISPLAY_FALLBACK) { + uint32_t loadTimeout = GetFallbackDelay(); + if (downloadTimeMS > loadTimeout && + (mUserFontEntry->mFontDataLoadingState == + gfxUserFontEntry::LOADING_SLOWLY)) { + mUserFontEntry->mFontDataLoadingState = + gfxUserFontEntry::LOADING_TIMED_OUT; + } + } + if (LOG_ENABLED()) { nsAutoCString fontURI; mFontURI->GetSpec(fontURI); @@ -271,3 +333,13 @@ nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal, return NS_OK; } + +uint8_t +nsFontFaceLoader::GetFontDisplay() +{ + uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO; + if (Preferences::GetBool("layout.css.font-display.enabled")) { + fontDisplay = mUserFontEntry->GetFontDisplay(); + } + return fontDisplay; +} diff --git a/layout/style/nsFontFaceLoader.h b/layout/style/nsFontFaceLoader.h index 117bf4850e..d9d607702c 100644 --- a/layout/style/nsFontFaceLoader.h +++ b/layout/style/nsFontFaceLoader.h @@ -50,6 +50,9 @@ public: protected: virtual ~nsFontFaceLoader(); + // helper method for determining the font-display value + uint8_t GetFontDisplay(); + private: RefPtr mUserFontEntry; nsCOMPtr mFontURI; diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index f3a84dde7f..95a1c1331c 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -2456,7 +2456,8 @@ struct nsStylePosition const nsStyleVisibility* aOldStyleVisibility) const; static nsChangeHint MaxDifference() { return NS_CombineHint(NS_STYLE_HINT_REFLOW, - nsChangeHint(nsChangeHint_RecomputePosition | + nsChangeHint(nsChangeHint_NeutralChange | + nsChangeHint_RecomputePosition | nsChangeHint_UpdateParentOverflow | nsChangeHint_UpdateComputedBSize)); } diff --git a/layout/style/test/descriptor_database.js b/layout/style/test/descriptor_database.js index d3531842de..da672d03b2 100644 --- a/layout/style/test/descriptor_database.js +++ b/layout/style/test/descriptor_database.js @@ -63,5 +63,10 @@ var gCSSFontFaceDescriptors = { domProp: null, values: [ "U+0-10FFFF", "U+3-7B3", "U+3??", "U+6A", "U+3????", "U+???", "U+302-302", "U+0-7,U+A-C", "U+100-17F,U+200-17F", "U+3??, U+500-513 ,U+612 , U+4????", "U+1FFF,U+200-27F" ], invalid_values: [ "U+1????-2????", "U+0-7,A-C", "U+100-17F,200-17F", "U+6A!important", "U+6A)" ] + }, + "font-display": { + domProp: null, + values: [ "auto", "block", "swap", "fallback", "optional" ], + invalid_values: [ "normal", "initial" ] } } diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index abc3d5ecdd..8e96f3f1d7 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -7006,6 +7006,13 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) { alias_for: "animation-timing-function", subproperties: [ "animation-timing-function" ], }; + gCSSProperties["-webkit-filter"] = { + domProp: "webkitFilter", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "filter", + subproperties: [ "filter" ], + }; gCSSProperties["-webkit-text-size-adjust"] = { domProp: "webkitTextSizeAdjust", inherited: true, @@ -7160,41 +7167,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) { alias_for: "border-image", subproperties: [ "border-image-source", "border-image-slice", "border-image-width", "border-image-outset", "border-image-repeat" ], }; - gCSSProperties["-webkit-border-image-outset"] = { - domProp: "webkitBorderImageOutset", - inherited: false, - type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "border-image-outset", - subproperties: [ "border-image-outset" ], - }; - gCSSProperties["-webkit-border-image-repeat"] = { - domProp: "webkitBorderImageRepeat", - inherited: false, - type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "border-image-repeat", - subproperties: [ "border-image-repeat" ], - }; - gCSSProperties["-webkit-border-image-slice"] = { - domProp: "webkitBorderImageSlice", - inherited: false, - type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "border-image-slice", - subproperties: [ "border-image-slice" ], - }; - gCSSProperties["-webkit-border-image-source"] = { - domProp: "webkitBorderImageSource", - inherited: false, - type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "border-image-source", - subproperties: [ "border-image-source" ], - }; - gCSSProperties["-webkit-border-image-width"] = { - domProp: "webkitBorderImageWidth", - inherited: false, - type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "border-image-width", - subproperties: [ "border-image-width" ], - }; gCSSProperties["-webkit-box-shadow"] = { domProp: "webkitBoxShadow", inherited: false, diff --git a/layout/style/test/test_descriptor_storage.html b/layout/style/test/test_descriptor_storage.html index c7504117c2..50017f642b 100644 --- a/layout/style/test/test_descriptor_storage.html +++ b/layout/style/test/test_descriptor_storage.html @@ -91,19 +91,27 @@ function test_descriptor(descriptor) // To avoid triggering the slow script dialog, we have to test one // descriptor at a time. SimpleTest.waitForExplicitFinish(); -var descs = []; -for (var desc in gCSSFontFaceDescriptors) - descs.push(desc); -descs = descs.reverse(); -function do_one() { - if (descs.length == 0) { - SimpleTest.finish(); - return; +function runTest() { + var descs = []; + for (var desc in gCSSFontFaceDescriptors) + descs.push(desc); + descs = descs.reverse(); + function do_one() { + if (descs.length == 0) { + SimpleTest.finish(); + return; + } + test_descriptor(descs.pop()); + SimpleTest.executeSoon(do_one); } - test_descriptor(descs.pop()); SimpleTest.executeSoon(do_one); } -SimpleTest.executeSoon(do_one); + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestLongerTimeout(5); + +SpecialPowers.pushPrefEnv({ set: [["layout.css.font-display.enabled", true]] }, + runTest); diff --git a/layout/style/test/test_font_loading_api.html b/layout/style/test/test_font_loading_api.html index 122d4e46d9..dcd9148b8e 100644 --- a/layout/style/test/test_font_loading_api.html +++ b/layout/style/test/test_font_loading_api.html @@ -19,7 +19,8 @@ var descriptorNames = { stretch: "font-stretch", unicodeRange: "unicode-range", variant: "font-variant", - featureSettings: "font-feature-settings" + featureSettings: "font-feature-settings", + display: "font-display" }; // Default values for the FontFace descriptor attributes other than family, as @@ -30,7 +31,8 @@ var defaultValues = { stretch: "normal", unicodeRange: "U+0-10FFFF", variant: "normal", - featureSettings: "normal" + featureSettings: "normal", + display: "auto" }; // Non-default values for the FontFace descriptor attributes other than family @@ -42,7 +44,8 @@ var nonDefaultValues = { stretch: ["Ultra-Condensed", "ultra-condensed"], unicodeRange: ["U+3??", "U+300-3FF"], variant: ["Small-Caps", "small-caps"], - featureSettings: ["'dlig' on", "\"dlig\""] + featureSettings: ["'dlig' on", "\"dlig\""], + display: ["Block", "block"] }; // Invalid values for the FontFace descriptor attributes other than family. @@ -52,7 +55,8 @@ var invalidValues = { stretch: "wider", unicodeRange: "U+1????-2????", variant: "inherit", - featureSettings: "dlig" + featureSettings: "dlig", + display: "normal" }; // Invalid font family names. @@ -159,8 +163,6 @@ function awaitRefresh() { } function runTest() { - SimpleTest.waitForExplicitFinish(); - // Document and window from inside the display:none iframe. var nframe = document.getElementById("n"); var ndocument = nframe.contentDocument; @@ -1859,11 +1861,16 @@ function runTest() { function start() { if (SpecialPowers.getBoolPref("layout.css.font-loading-api.enabled")) { - runTest(); + SpecialPowers.pushPrefEnv({ set: [["layout.css.font-display.enabled", true]] }, + runTest); } else { ok(true, "CSS Font Loading API is not enabled."); } } + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestLongerTimeout(5); + diff --git a/media/libstagefright/binding/Box.cpp b/media/libstagefright/binding/Box.cpp index 46a46b4e42..7621c6500f 100644 --- a/media/libstagefright/binding/Box.cpp +++ b/media/libstagefright/binding/Box.cpp @@ -13,6 +13,10 @@ using namespace mozilla; namespace mp4_demuxer { +// Limit reads to 32MiB max. +// static +const uint64_t Box::kMAX_BOX_READ = 32 * 1024 * 1024; + // Returns the offset from the start of the body of a box of type |aType| // to the start of its first child. static uint32_t @@ -149,8 +153,8 @@ Box::Read(nsTArray* aDest, const MediaByteRange& aRange) int64_t length; if (!mContext->mSource->Length(&length)) { // The HTTP server didn't give us a length to work with. - // Limit the read to 32MiB max. - length = std::min(aRange.mEnd - mChildOffset, uint64_t(32 * 1024 * 1024)); + // Limit the read to kMAX_BOX_READ max. + length = std::min(aRange.mEnd - mChildOffset, kMAX_BOX_READ); } else { length = aRange.mEnd - mChildOffset; } diff --git a/media/libstagefright/binding/Index.cpp b/media/libstagefright/binding/Index.cpp index e35cf902ac..595e6a781b 100644 --- a/media/libstagefright/binding/Index.cpp +++ b/media/libstagefright/binding/Index.cpp @@ -254,7 +254,7 @@ Index::Index(const nsTArray& aIndex, int64_t lastOffset = 0; for (size_t i = 0; i < aIndex.Length(); i++) { const Indice& indice = aIndex[i]; - if (indice.sync) { + if (indice.sync || mIsAudio) { haveSync = true; } if (!haveSync) { @@ -267,7 +267,7 @@ Index::Index(const nsTArray& aIndex, sample.mCompositionRange = Interval(indice.start_composition, indice.end_composition); sample.mDecodeTime = indice.start_decode; - sample.mSync = indice.sync; + sample.mSync = indice.sync || mIsAudio; // FIXME: Make this infallible after bug 968520 is done. MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample, fallible)); if (indice.start_offset < lastOffset) { diff --git a/media/libstagefright/binding/MP4Metadata.cpp b/media/libstagefright/binding/MP4Metadata.cpp index 9d526ada79..3112f0e7f6 100644 --- a/media/libstagefright/binding/MP4Metadata.cpp +++ b/media/libstagefright/binding/MP4Metadata.cpp @@ -112,7 +112,7 @@ MP4Metadata::~MP4Metadata() #ifdef MOZ_RUST_MP4PARSE // Helper to test the rust parser on a data source. -static bool try_rust(const UniquePtr& aRustState, RefPtr aSource, int32_t* aCount) +static bool try_rust(const UniquePtr& aRustState, RefPtr aSource) { static LazyLogModule sLog("MP4Metadata"); int64_t length; @@ -129,9 +129,7 @@ static bool try_rust(const UniquePtr& aRustSt MOZ_LOG(sLog, LogLevel::Warning, ("Error copying mp4 data")); return false; } - *aCount = mp4parse_read(aRustState.get(), buffer.data(), bytes_read); - MOZ_LOG(sLog, LogLevel::Info, ("rust parser found %d tracks", int(*aCount))); - return true; + return mp4parse_read(aRustState.get(), buffer.data(), bytes_read); } #endif @@ -139,12 +137,18 @@ uint32_t MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const { #ifdef MOZ_RUST_MP4PARSE + static LazyLogModule sLog("MP4Metadata"); // Try in rust first. mRustState.reset(mp4parse_new()); - int32_t rust_tracks = 0; - bool rust_mp4parse_success = try_rust(mRustState, mSource, &rust_tracks); + int32_t rust_mp4parse_success = try_rust(mRustState, mSource); Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_SUCCESS, - rust_mp4parse_success); + rust_mp4parse_success == 0); + if (rust_mp4parse_success < 0) { + Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_ERROR_CODE, + -rust_mp4parse_success); + } + uint32_t rust_tracks = mp4parse_get_track_count(mRustState.get()); + MOZ_LOG(sLog, LogLevel::Info, ("rust parser found %u tracks", rust_tracks)); #endif size_t tracks = mPrivate->mMetadataExtractor->countTracks(); uint32_t total = 0; @@ -176,7 +180,7 @@ MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const uint32_t rust_total = 0; const char* rust_track_type = nullptr; if (rust_mp4parse_success && rust_tracks > 0) { - for (int32_t i = 0; i < rust_tracks; ++i) { + for (uint32_t i = 0; i < rust_tracks; ++i) { mp4parse_track_info track_info; int32_t r = mp4parse_get_track_info(mRustState.get(), i, &track_info); switch (aType) { @@ -197,9 +201,20 @@ MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const } } } - static LazyLogModule sLog("MP4Metadata"); MOZ_LOG(sLog, LogLevel::Info, ("%s tracks found: stagefright=%u rust=%u", rust_track_type, total, rust_total)); + switch (aType) { + case mozilla::TrackInfo::kAudioTrack: + Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_AUDIO, + rust_total == total); + break; + case mozilla::TrackInfo::kVideoTrack: + Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_VIDEO, + rust_total == total); + break; + default: + break; + } #endif return total; } diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index a9737a8257..414aea1cb5 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -182,7 +182,9 @@ MoofParser::Metadata() MediaByteRange ftyp; MediaByteRange moov; ScanForMetadata(ftyp, moov); - if (!ftyp.Length() || !moov.Length()) { + if (!ftyp.Length() || !moov.Length() || + ftyp.Length() > Box::kMAX_BOX_READ || moov.Length() > Box::kMAX_BOX_READ) { + // No ftyp or moov, or trying to read bigger-that-readable box (32MB). return nullptr; } RefPtr metadata = new MediaByteBuffer(); diff --git a/media/libstagefright/binding/byteorder-mod.patch b/media/libstagefright/binding/byteorder-mod.patch new file mode 100644 index 0000000000..cce9208bbb --- /dev/null +++ b/media/libstagefright/binding/byteorder-mod.patch @@ -0,0 +1,37 @@ +diff --git a/media/libstagefright/binding/byteorder/mod.rs b/media/libstagefright/binding/byteorder/mod.rs +index 59ba692..9d2d1d5 100644 +--- a/media/libstagefright/binding/byteorder/mod.rs ++++ b/media/libstagefright/binding/byteorder/mod.rs +@@ -36,16 +36,16 @@ assert_eq!(wtr, vec![5, 2, 0, 3]); + ``` + */ + +-#![crate_name = "byteorder"] + #![doc(html_root_url = "http://burntsushi.net/rustdoc/byteorder")] + + #![deny(missing_docs)] + + use std::mem::transmute; + +-pub use new::{ReadBytesExt, WriteBytesExt, Error, Result}; ++pub use byteorder::new::{ReadBytesExt, WriteBytesExt, Error, Result}; + +-mod new; ++// Re-export new so gecko can build us as a mod intead of a crate. ++pub mod new; + + #[inline] + fn extend_sign(val: u64, nbytes: usize) -> i64 { +diff --git a/media/libstagefright/binding/byteorder/new.rs b/media/libstagefright/binding/byteorder/new.rs +index bbef0cd..a2e5393 100644 +--- a/media/libstagefright/binding/byteorder/new.rs ++++ b/media/libstagefright/binding/byteorder/new.rs +@@ -3,7 +3,7 @@ use std::fmt; + use std::io; + use std::result; + +-use ByteOrder; ++use byteorder::ByteOrder; + + /// A short-hand for `result::Result`. + pub type Result = result::Result; diff --git a/media/libstagefright/binding/include/mp4_demuxer/Box.h b/media/libstagefright/binding/include/mp4_demuxer/Box.h index e79b0130f8..bf87641690 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Box.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h @@ -51,6 +51,8 @@ public: bool Read(nsTArray* aDest); bool Read(nsTArray* aDest, const MediaByteRange& aRange); + static const uint64_t kMAX_BOX_READ; + private: bool Contains(MediaByteRange aRange) const; BoxContext* mContext; diff --git a/media/libstagefright/binding/mp4parse-mod.patch b/media/libstagefright/binding/mp4parse-mod.patch new file mode 100644 index 0000000000..ac5458cb86 --- /dev/null +++ b/media/libstagefright/binding/mp4parse-mod.patch @@ -0,0 +1,13 @@ +diff --git a/media/libstagefright/binding/MP4Metadata.rs b/media/libstagefright/binding/MP4Metadata.rs +index 2f1b873..d2ad827 100644 +--- a/media/libstagefright/binding/MP4Metadata.rs ++++ b/media/libstagefright/binding/MP4Metadata.rs +@@ -4,7 +4,7 @@ + // License, v. 2.0. If a copy of the MPL was not distributed with this + // file, You can obtain one at https://mozilla.org/MPL/2.0/. + +-extern crate byteorder; ++mod byteorder; // 'extern crate' upstream. + use byteorder::ReadBytesExt; + use std::error::Error as ErrorTrait; // For Err(e) => e.description(). + use std::io::{Read, BufRead, Take}; diff --git a/media/libstagefright/binding/update-rust.sh b/media/libstagefright/binding/update-rust.sh new file mode 100644 index 0000000000..aaae10c3c6 --- /dev/null +++ b/media/libstagefright/binding/update-rust.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Script to update mp4parse-rust sources to latest upstream + +# Default version. +VER=v0.1.3 + +# Accept version or commit from the command line. +if test -n "$1"; then + VER=$1 +fi + +echo "Fetching sources..." +rm -rf _upstream +git clone https://github.com/mozilla/mp4parse-rust _upstream/mp4parse +pushd _upstream/mp4parse +git checkout ${VER} +popd +cp _upstream/mp4parse/src/lib.rs MP4Metadata.rs +cp _upstream/mp4parse/src/capi.rs . + +# TODO: download deps from crates.io. + +git clone https://github.com/BurntSushi/byteorder _upstream/byteorder +pushd _upstream/byteorder +git checkout 0.3.13 +popd +cp _upstream/byteorder/src/lib.rs byteorder/mod.rs +cp _upstream/byteorder/src/new.rs byteorder/new.rs + +echo "Applying patches..." +patch -p4 < byteorder-mod.patch +patch -p4 < mp4parse-mod.patch + +echo "Cleaning up..." +rm -rf _upstream + +echo "Updated to ${VER}." diff --git a/media/mtransport/nr_socket_prsock.cpp b/media/mtransport/nr_socket_prsock.cpp index bd42a24dff..52b3f50510 100644 --- a/media/mtransport/nr_socket_prsock.cpp +++ b/media/mtransport/nr_socket_prsock.cpp @@ -89,6 +89,7 @@ nrappkit copyright: #include #include #include +#include #include "nspr.h" #include "prerror.h" @@ -110,6 +111,8 @@ nrappkit copyright: #include "nsTArray.h" #include "mozilla/dom/TCPSocketBinding.h" #include "nsITCPSocketCallback.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) // csi_platform.h deep in nrappkit defines LOG_INFO and LOG_WARNING @@ -164,6 +167,7 @@ extern "C" { } #include "nr_socket_prsock.h" #include "simpletokenbucket.h" +#include "test_nr_socket.h" // Implement the nsISupports ref counting namespace mozilla { @@ -355,6 +359,9 @@ void NrSocket::OnSocketReady(PRFileDesc *fd, int16_t outflags) { fire_callback(NR_ASYNC_WAIT_READ); if (outflags & PR_POLL_WRITE & poll_flags()) fire_callback(NR_ASYNC_WAIT_WRITE); + if (outflags & (PR_POLL_ERR | PR_POLL_NVAL | PR_POLL_HUP)) + // TODO: Bug 946423: how do we notify the upper layers about this? + close(); } void NrSocket::OnSocketDetached(PRFileDesc *fd) { @@ -489,7 +496,11 @@ int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr, ABORT(r); break; case AF_INET6: - ABORT(R_BAD_ARGS); + if ((r = nr_ip6_port_to_transport_addr((in6_addr *)&netaddr->inet6.ip.u8, + ntohs(netaddr->inet6.port), + protocol, addr))) + ABORT(r); + break; default: MOZ_ASSERT(false); ABORT(R_BAD_ARGS); @@ -905,6 +916,8 @@ int NrSocket::listen(int backlog) { assert(fd_); status = PR_Listen(fd_, backlog); if (status != PR_SUCCESS) { + r_log(LOG_GENERIC, LOG_CRIT, "%s: PR_GetError() == %d", + __FUNCTION__, PR_GetError()); ABORT(R_IO_ERROR); } @@ -1043,7 +1056,6 @@ NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerOpened() { // callback while UDP socket is connected NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerConnected() { return socket_->CallListenerConnected(); - return NS_OK; } // callback while UDP socket is closed @@ -1129,7 +1141,7 @@ NS_IMETHODIMP NrUdpSocketIpc::CallListenerReceivedData(const nsACString &host, return NS_OK; } -NS_IMETHODIMP NrUdpSocketIpc::SetAddress() { +nsresult NrUdpSocketIpc::SetAddress() { uint16_t port; if (NS_FAILED(socket_child_->GetLocalPort(&port))) { err_ = true; @@ -2051,24 +2063,26 @@ static nr_socket_vtbl nr_socket_local_vtbl={ nr_socket_local_accept }; -int nr_socket_local_create(void *obj, nr_transport_addr *addr, nr_socket **sockp) { - RefPtr sock; +/* static */ +int +NrSocketBase::CreateSocket(nr_transport_addr *addr, RefPtr *sock) +{ int r, _status; // create IPC bridge for content process if (XRE_IsParentProcess()) { - sock = new NrSocket(); + *sock = new NrSocket(); } else { switch (addr->protocol) { case IPPROTO_UDP: - sock = new NrUdpSocketIpc(); + *sock = new NrUdpSocketIpc(); break; case IPPROTO_TCP: #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) { nsCOMPtr main_thread; NS_GetMainThread(getter_AddRefs(main_thread)); - sock = new NrTcpSocketIpc(main_thread.get()); + *sock = new NrTcpSocketIpc(main_thread.get()); } #else ABORT(R_REJECTED); @@ -2077,10 +2091,27 @@ int nr_socket_local_create(void *obj, nr_transport_addr *addr, nr_socket **sockp } } - r = sock->create(addr); + r = (*sock)->create(addr); if (r) ABORT(r); + _status = 0; +abort: + if (_status) { + *sock = nullptr; + } + return _status; +} + +int nr_socket_local_create(void *obj, nr_transport_addr *addr, nr_socket **sockp) { + RefPtr sock; + int r, _status; + + r = NrSocketBase::CreateSocket(addr, &sock); + if (r) { + ABORT(r); + } + r = nr_socket_create_int(static_cast(sock), sock->vtbl(), sockp); if (r) diff --git a/media/mtransport/nr_socket_prsock.h b/media/mtransport/nr_socket_prsock.h index fa45c167ac..e256938213 100644 --- a/media/mtransport/nr_socket_prsock.h +++ b/media/mtransport/nr_socket_prsock.h @@ -96,6 +96,10 @@ public: } virtual ~NrSocketBase() {} + // Factory method; will create either an NrSocket, NrUdpSocketIpc, or + // NrTcpSocketIpc as appropriate. + static int CreateSocket(nr_transport_addr *addr, RefPtr *sock); + // the nr_socket APIs virtual int create(nr_transport_addr *addr) = 0; virtual int sendto(const void *msg, size_t len, @@ -132,9 +136,10 @@ public: return my_addr_; } -protected: void fire_callback(int how); +protected: + bool connect_invoked_; nr_transport_addr my_addr_; diff --git a/media/mtransport/nr_timer.cpp b/media/mtransport/nr_timer.cpp index 2172cddfd8..39606bb4ed 100644 --- a/media/mtransport/nr_timer.cpp +++ b/media/mtransport/nr_timer.cpp @@ -93,21 +93,24 @@ class nrappkitTimerCallback : public nrappkitCallback, NS_DECL_NSITIMERCALLBACK nrappkitTimerCallback(NR_async_cb cb, void *cb_arg, - const char *function, int line, - nsITimer *timer) + const char *function, int line) : nrappkitCallback(cb, cb_arg, function, line), - timer_(timer) {} + timer_(nullptr) {} + + void SetTimer(already_AddRefed&& timer) { + timer_ = timer; + } virtual void Cancel() override { AddRef(); // Cancelling the timer causes the callback it holds to // be released. AddRef() keeps us alive. timer_->Cancel(); - timer_->Release(); + timer_ = nullptr; Release(); // Will cause deletion of this object. } private: - nsITimer* timer_; + nsCOMPtr timer_; virtual ~nrappkitTimerCallback() {} }; @@ -120,7 +123,7 @@ NS_IMETHODIMP nrappkitTimerCallback::Notify(nsITimer *timer) { cb_(0, 0, cb_arg_); // Allow the timer to go away. - timer->Release(); + timer_ = nullptr; return NS_OK; } @@ -201,14 +204,15 @@ static int nr_async_timer_set_nonzero(int timeout, NR_async_cb cb, void *arg, } nrappkitTimerCallback* callback = - new nrappkitTimerCallback(cb, arg, func, l, timer); + new nrappkitTimerCallback(cb, arg, func, l); rv = timer->InitWithCallback(callback, timeout, nsITimer::TYPE_ONE_SHOT); if (NS_FAILED(rv)) { return R_FAILED; } - // We need an AddRef here to keep the timer alive, per the spec. - timer->AddRef(); + // Move the ownership of the timer to the callback object, which holds the + // timer alive per spec. + callback->SetTimer(timer.forget()); *handle = callback; diff --git a/media/mtransport/nricectx.cpp b/media/mtransport/nricectx.cpp index 9e990b1c5f..edc7c90873 100644 --- a/media/mtransport/nricectx.cpp +++ b/media/mtransport/nricectx.cpp @@ -95,6 +95,7 @@ extern "C" { #include "nr_socket_prsock.h" #include "nrinterfaceprioritizer.h" #include "rlogringbuffer.h" +#include "test_nr_socket.h" namespace mozilla { @@ -270,6 +271,25 @@ nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server *server) const { return NS_OK; } +NrIceCtx::NrIceCtx(const std::string& name, + bool offerer, + Policy policy) + : connection_state_(ICE_CTX_INIT), + gathering_state_(ICE_CTX_GATHER_INIT), + name_(name), + offerer_(offerer), + streams_(), + ctx_(nullptr), + peer_(nullptr), + ice_handler_vtbl_(nullptr), + ice_handler_(nullptr), + trickle_(true), + policy_(policy), + nat_ (nullptr) { + // XXX: offerer_ will be used eventually; placate clang in the meantime. + (void)offerer_; +} + // Handler callbacks int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream, int component_id, nr_ice_cand_pair **potentials, @@ -500,6 +520,42 @@ RefPtr NrIceCtx::Create(const std::string& name, } } + char* mapping_type = nullptr; + char* filtering_type = nullptr; + bool block_udp = false; + + nsresult rv; + nsCOMPtr pref_service = + do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr pref_branch; + rv = pref_service->GetBranch(nullptr, getter_AddRefs(pref_branch)); + if (NS_SUCCEEDED(rv)) { + rv = pref_branch->GetCharPref( + "media.peerconnection.nat_simulator.mapping_type", + &mapping_type); + rv = pref_branch->GetCharPref( + "media.peerconnection.nat_simulator.filtering_type", + &filtering_type); + rv = pref_branch->GetBoolPref( + "media.peerconnection.nat_simulator.block_udp", + &block_udp); + } + } + + MOZ_MTLOG(ML_DEBUG, "NAT filtering type: " << filtering_type); + MOZ_MTLOG(ML_DEBUG, "NAT mapping type: " << mapping_type); + + if (mapping_type && filtering_type) { + TestNat* test_nat = new TestNat; + test_nat->filtering_type_ = TestNat::ToNatBehavior(filtering_type); + test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type); + test_nat->block_udp_ = block_udp; + test_nat->enabled_ = true; + ctx->SetNat(test_nat); + } + // Create the handler objects ctx->ice_handler_vtbl_ = new nr_ice_handler_vtbl(); ctx->ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair; @@ -524,7 +580,6 @@ RefPtr NrIceCtx::Create(const std::string& name, return nullptr; } - nsresult rv; ctx->sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); if (!NS_SUCCEEDED(rv)) @@ -533,6 +588,17 @@ RefPtr NrIceCtx::Create(const std::string& name, return ctx; } +int NrIceCtx::SetNat(const RefPtr& aNat) { + nat_ = aNat; + nr_socket_factory *fac; + int r = nat_->create_socket_factory(&fac); + if (r) { + return r; + } + nr_ice_ctx_set_socket_factory(ctx_, fac); + return 0; +} + // ONLY USE THIS FOR TESTING. Will cause totally unpredictable and possibly very // bad effects if ICE is still live. void NrIceCtx::internal_DeinitializeGlobal() { diff --git a/media/mtransport/nricectx.h b/media/mtransport/nricectx.h index 081bc104e2..bdf9172141 100644 --- a/media/mtransport/nricectx.h +++ b/media/mtransport/nricectx.h @@ -191,6 +191,7 @@ class NrIceProxyServer { std::string alpn_; }; +class TestNat; class NrIceCtx { public: @@ -223,6 +224,8 @@ class NrIceCtx { bool hide_non_default = false, Policy policy = ICE_POLICY_ALL); + int SetNat(const RefPtr& aNat); + // Deinitialize all ICE global state. Used only for testing. static void internal_DeinitializeGlobal(); @@ -332,21 +335,7 @@ class NrIceCtx { private: NrIceCtx(const std::string& name, bool offerer, - Policy policy) - : connection_state_(ICE_CTX_INIT), - gathering_state_(ICE_CTX_GATHER_INIT), - name_(name), - offerer_(offerer), - streams_(), - ctx_(nullptr), - peer_(nullptr), - ice_handler_vtbl_(nullptr), - ice_handler_(nullptr), - trickle_(true), - policy_(policy) { - // XXX: offerer_ will be used eventually; placate clang in the meantime. - (void)offerer_; - } + Policy policy); virtual ~NrIceCtx(); @@ -390,6 +379,7 @@ class NrIceCtx { bool trickle_; nsCOMPtr sts_target_; // The thread to run on Policy policy_; + RefPtr nat_; }; diff --git a/media/mtransport/nricemediastream.cpp b/media/mtransport/nricemediastream.cpp index 36a677b7ee..31ab2bb5f5 100644 --- a/media/mtransport/nricemediastream.cpp +++ b/media/mtransport/nricemediastream.cpp @@ -265,6 +265,10 @@ nsresult NrIceMediaStream::GetActivePair(int component, nr_ice_candidate *local_int; nr_ice_candidate *remote_int; + if (!stream_) { + return NS_ERROR_NOT_AVAILABLE; + } + r = nr_ice_media_stream_get_active(ctx_->peer(), stream_, component, @@ -298,6 +302,14 @@ nsresult NrIceMediaStream::GetActivePair(int component, nsresult NrIceMediaStream::GetCandidatePairs(std::vector* out_pairs) const { MOZ_ASSERT(out_pairs); + if (!stream_) { + return NS_ERROR_NOT_AVAILABLE; + } + + // If we haven't at least started checking then there is nothing to report + if (ctx_->connection_state() == NrIceCtx::ICE_CTX_INIT) { + return NS_OK; + } // Get the check_list on the peer stream (this is where the check_list // actually lives, not in stream_) @@ -413,6 +425,10 @@ std::vector NrIceMediaStream::GetCandidates() const { int r; std::vector ret; + if (!stream_) { + return ret; + } + r = nr_ice_media_stream_get_attributes(stream_, &attrs, &attrct); if (r) { @@ -459,11 +475,24 @@ static nsresult GetCandidatesFromStream( nsresult NrIceMediaStream::GetLocalCandidates( std::vector* candidates) const { + if (!stream_) { + return NS_ERROR_NOT_AVAILABLE; + } + return GetCandidatesFromStream(stream_, candidates); } nsresult NrIceMediaStream::GetRemoteCandidates( std::vector* candidates) const { + if (!stream_) { + return NS_ERROR_NOT_AVAILABLE; + } + + // If we haven't at least started checking then there is nothing to report + if (ctx_->connection_state() == NrIceCtx::ICE_CTX_INIT) { + return NS_OK; + } + nr_ice_media_stream* peer_stream; int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream); if (r != 0) { diff --git a/media/mtransport/test/ice_unittest.cpp b/media/mtransport/test/ice_unittest.cpp index 38b77bb430..1c3adb7ba3 100644 --- a/media/mtransport/test/ice_unittest.cpp +++ b/media/mtransport/test/ice_unittest.cpp @@ -316,12 +316,9 @@ class IceTestPeer : public sigslot::has_slots<> { this, &IceTestPeer::ConnectionStateChange); - nr_socket_factory *fac; - int r = nat_->create_socket_factory(&fac); + int r = ice_ctx_->SetNat(nat_); + (void)r; MOZ_ASSERT(!r); - if (!r) { - nr_ice_ctx_set_socket_factory(ice_ctx_->ctx(), fac); - } } ~IceTestPeer() { @@ -2098,7 +2095,7 @@ TEST_F(IceGatherTest, TestFakeStunServerNoNatDefaultRouteOnly) { TEST_F(IceGatherTest, TestStunTcpServerTrickle) { UseFakeStunTcpServerWithResponse("192.0.3.1", 3333); - TestStunServer::GetInstance(AF_INET)->SetDelay(500); + TestStunTcpServer::GetInstance(AF_INET)->SetDelay(500); Gather(0); ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype ")); WaitForGather(); @@ -2917,11 +2914,11 @@ TEST_F(IceConnectTest, TestPollCandPairsBeforeConnect) { std::vector pairs; nsresult res = p1_->GetCandidatePairs(0, &pairs); // There should be no candidate pairs prior to calling Connect() - ASSERT_TRUE(NS_FAILED(res)); + ASSERT_EQ(NS_OK, res); ASSERT_EQ(0U, pairs.size()); res = p2_->GetCandidatePairs(0, &pairs); - ASSERT_TRUE(NS_FAILED(res)); + ASSERT_EQ(NS_OK, res); ASSERT_EQ(0U, pairs.size()); } diff --git a/media/mtransport/test/mtransport_test_utils.h b/media/mtransport/test/mtransport_test_utils.h index db1d68045d..6c96c6f1e1 100644 --- a/media/mtransport/test/mtransport_test_utils.h +++ b/media/mtransport/test/mtransport_test_utils.h @@ -25,6 +25,9 @@ #include "nsISocketTransportService.h" #include "nsDirectoryServiceUtils.h" #include "nsDirectoryServiceDefs.h" +#ifdef MOZ_CRASHREPORTER +#include "nsICrashReporter.h" +#endif #include "nsPISocketTransportService.h" #include "nsServiceManagerUtils.h" #if !defined(MOZILLA_XPCOMRT_API) @@ -63,6 +66,27 @@ class MtransportTestUtils { sts_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); MOZ_ASSERT(NS_SUCCEEDED(rv)); +#ifdef MOZ_CRASHREPORTER + char *crashreporter = PR_GetEnv("MOZ_CRASHREPORTER"); + if (crashreporter && !strcmp(crashreporter, "1")) { + //TODO: move this to an even-more-common location to use in all + // C++ unittests + crashreporter_ = do_GetService("@mozilla.org/toolkit/crash-reporter;1"); + if (crashreporter_) { + std::cerr << "Setting up crash reporting" << std::endl; + + nsCOMPtr dirsvc = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + nsCOMPtr cwd; + rv = dirsvc->Get(NS_OS_CURRENT_WORKING_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(cwd)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + crashreporter_->SetEnabled(true); + crashreporter_->SetMinidumpPath(cwd); + } + } +#endif } nsCOMPtr sts_target() { return sts_target_; } @@ -71,6 +95,9 @@ class MtransportTestUtils { ScopedXPCOM xpcom_; nsCOMPtr sts_target_; nsCOMPtr sts_; +#ifdef MOZ_CRASHREPORTER + nsCOMPtr crashreporter_; +#endif }; diff --git a/media/mtransport/test/multi_tcp_socket_unittest.cpp b/media/mtransport/test/multi_tcp_socket_unittest.cpp index 047a8ef54e..fff4291c58 100644 --- a/media/mtransport/test/multi_tcp_socket_unittest.cpp +++ b/media/mtransport/test/multi_tcp_socket_unittest.cpp @@ -148,6 +148,18 @@ class MultiTcpSocketTest : public ::testing::Test { NS_DISPATCH_SYNC); } + void Destroy_s(nr_socket *sock) { + int r = nr_socket_destroy(&sock); + ASSERT_EQ(0, r); + } + + void Destroy(nr_socket *sock) { + test_utils->sts_target()->Dispatch( + WrapRunnable( + this, &MultiTcpSocketTest::Destroy_s, sock), + NS_DISPATCH_SYNC); + } + void Connect_s(nr_socket *from, nr_socket *to) { nr_transport_addr addr_to; nr_transport_addr addr_from; @@ -287,6 +299,31 @@ class MultiTcpSocketTest : public ::testing::Test { NS_DISPATCH_SYNC); } + void RecvDataFailed_s(nr_socket *sent_to, size_t expected_len, int expected_err) { + SetReadable(false); + char received_data[expected_len+1]; + nr_transport_addr addr_to; + nr_transport_addr retaddr; + size_t retlen; + + int r=nr_socket_getaddr(sent_to, &addr_to); + ASSERT_EQ(0, r); + r=nr_socket_recvfrom(sent_to, received_data, expected_len+1, + &retlen, 0, &retaddr); + ASSERT_EQ(expected_err, r) << "Expecting receive failure " << expected_err + << " on " << addr_to.as_string; + } + + void RecvDataFailed(nr_socket *sent_to, size_t expected_len, + int expected_err) { + ASSERT_TRUE_WAIT(IsReadable(), 1000); + test_utils->sts_target()->Dispatch( + WrapRunnable( + this, &MultiTcpSocketTest::RecvDataFailed_s, sent_to, expected_len, + expected_err), + NS_DISPATCH_SYNC); + } + void TransferData(nr_socket *from, nr_socket *to, const char *data, size_t len) { SendData(from, to, data, len); @@ -331,6 +368,44 @@ TEST_F(MultiTcpSocketTest, TestTransmit) { TransferData(socks[1], socks[0], data, sizeof(data)); } +TEST_F(MultiTcpSocketTest, TestClosePassive) { + const char data[] = "TestClosePassive"; + socks[0] = Create(TCP_TYPE_ACTIVE); + socks[1] = Create(TCP_TYPE_PASSIVE); + Listen(socks[1]); + Connect(socks[0], socks[1]); + + TransferData(socks[0], socks[1], data, sizeof(data)); + TransferData(socks[1], socks[0], data, sizeof(data)); + + /* We have to destroy as only that calls PR_Close() */ + std::cerr << "Destructing socket" << std::endl; + Destroy(socks[1]); + + RecvDataFailed(socks[0], sizeof(data), R_EOD); + + socks[1] = nullptr; +} + +TEST_F(MultiTcpSocketTest, TestCloseActive) { + const char data[] = "TestCloseActive"; + socks[0] = Create(TCP_TYPE_ACTIVE); + socks[1] = Create(TCP_TYPE_PASSIVE); + Listen(socks[1]); + Connect(socks[0], socks[1]); + + TransferData(socks[0], socks[1], data, sizeof(data)); + TransferData(socks[1], socks[0], data, sizeof(data)); + + /* We have to destroy as only that calls PR_Close() */ + std::cerr << "Destructing socket" << std::endl; + Destroy(socks[0]); + + RecvDataFailed(socks[1], sizeof(data), R_EOD); + + socks[0] = nullptr; +} + TEST_F(MultiTcpSocketTest, TestTwoSendsBeforeReceives) { const char data1[] = "TestTwoSendsBeforeReceives"; const char data2[] = "2nd data"; diff --git a/media/mtransport/test/stunserver.cpp b/media/mtransport/test/stunserver.cpp index 67b150ed4f..c2f14d6700 100644 --- a/media/mtransport/test/stunserver.cpp +++ b/media/mtransport/test/stunserver.cpp @@ -608,6 +608,7 @@ void TestStunTcpServer::accept_cb(NR_SOCKET s, int how, void *cb_arg) { if(nr_socket_buffered_stun_create(newsock, 2048, TURN_TCP_FRAMING, &bufsock)) { MOZ_MTLOG(ML_ERROR, "Couldn't create connected tcp socket"); + nr_socket_destroy(&newsock); return; } @@ -615,11 +616,13 @@ void TestStunTcpServer::accept_cb(NR_SOCKET s, int how, void *cb_arg) { if(nr_socket_wrapped_create(bufsock, &wrapsock)) { MOZ_MTLOG(ML_ERROR, "Couldn't wrap connected tcp socket"); + nr_socket_destroy(&bufsock); return; } - if(nr_socket_getfd(bufsock, &fd)) { + if(nr_socket_getfd(wrapsock, &fd)) { MOZ_MTLOG(ML_ERROR, "Couldn't get fd from connected tcp socket"); + nr_socket_destroy(&wrapsock); return; } diff --git a/media/mtransport/test/test_nr_socket_unittest.cpp b/media/mtransport/test/test_nr_socket_unittest.cpp index 8a16712664..e70f90ea62 100644 --- a/media/mtransport/test/test_nr_socket_unittest.cpp +++ b/media/mtransport/test/test_nr_socket_unittest.cpp @@ -33,6 +33,8 @@ extern "C" { #include "gtest/gtest.h" #include "gtest_utils.h" +#define DATA_BUF_SIZE 1024 + namespace mozilla { class TestNrSocketTest : public ::testing::Test { @@ -62,12 +64,13 @@ class TestNrSocketTest : public ::testing::Test { } RefPtr CreateTestNrSocket_s(const char *ip_str, - TestNat *nat) { + int proto, + TestNat *nat) { // If no nat is supplied, we create a default NAT which is disabled. This // is how we simulate a non-natted socket. RefPtr sock(new TestNrSocket(nat ? nat : new TestNat)); nr_transport_addr address; - nr_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address); + nr_str_port_to_transport_addr(ip_str, 0, proto, &address); int r = sock->create(&address); if (r) { return nullptr; @@ -75,40 +78,47 @@ class TestNrSocketTest : public ::testing::Test { return sock; } - void CreatePublicAddrs(size_t count, const char *ip_str = "127.0.0.1") { + void CreatePublicAddrs(size_t count, + const char *ip_str = "127.0.0.1", + int proto = IPPROTO_UDP) { sts_->Dispatch( WrapRunnable(this, &TestNrSocketTest::CreatePublicAddrs_s, count, - ip_str), + ip_str, + proto), NS_DISPATCH_SYNC); } - void CreatePublicAddrs_s(size_t count, const char* ip_str) { + void CreatePublicAddrs_s(size_t count, const char* ip_str, int proto) { while (count--) { - auto sock = CreateTestNrSocket_s(ip_str, nullptr); + auto sock = CreateTestNrSocket_s(ip_str, proto, nullptr); ASSERT_TRUE(sock) << "Failed to create socket"; public_addrs_.push_back(sock); } } RefPtr CreatePrivateAddrs(size_t size, - const char* ip_str = "127.0.0.1") { + const char* ip_str = "127.0.0.1", + int proto = IPPROTO_UDP) { RefPtr result; sts_->Dispatch( WrapRunnableRet(&result, this, &TestNrSocketTest::CreatePrivateAddrs_s, size, - ip_str), + ip_str, + proto), NS_DISPATCH_SYNC); return result; } - RefPtr CreatePrivateAddrs_s(size_t count, const char* ip_str) { + RefPtr CreatePrivateAddrs_s(size_t count, + const char* ip_str, + int proto) { RefPtr nat(new TestNat); while (count--) { - auto sock = CreateTestNrSocket_s(ip_str, nat); + auto sock = CreateTestNrSocket_s(ip_str, proto, nat); if (!sock) { EXPECT_TRUE(false) << "Failed to create socket"; break; @@ -178,6 +188,63 @@ class TestNrSocketTest : public ::testing::Test { sender_external_address); } + bool CheckTcpConnectivity(TestNrSocket *from, TestNrSocket *to) { + NrSocketBase *accepted_sock; + if (!Connect(from, to, &accepted_sock)) { + std::cerr << "Connect failed" << std::endl; + return false; + } + + // write on |from|, recv on |accepted_sock| + if (!WaitForWriteable(from)) { + std::cerr << __LINE__ << "WaitForWriteable failed" << std::endl; + return false; + } + + int r; + sts_->Dispatch(WrapRunnableRet(&r, + this, + &TestNrSocketTest::SendDataTcp_s, + from), + NS_DISPATCH_SYNC); + if (r) { + std::cerr << "SendDataTcp_s (1) failed" << std::endl; + return false; + } + + sts_->Dispatch(WrapRunnableRet(&r, + this, + &TestNrSocketTest::RecvDataTcp_s, + accepted_sock), + NS_DISPATCH_SYNC); + if (r) { + std::cerr << "RecvDataTcp_s (1) failed" << std::endl; + return false; + } + + sts_->Dispatch(WrapRunnableRet(&r, + this, + &TestNrSocketTest::SendDataTcp_s, + accepted_sock), + NS_DISPATCH_SYNC); + if (r) { + std::cerr << "SendDataTcp_s (2) failed" << std::endl; + return false; + } + + sts_->Dispatch(WrapRunnableRet(&r, + this, + &TestNrSocketTest::RecvDataTcp_s, + from), + NS_DISPATCH_SYNC); + if (r) { + std::cerr << "RecvDataTcp_s (2) failed" << std::endl; + return false; + } + + return true; + } + int GetAddress(TestNrSocket *sock, nr_transport_addr_ *address) { MOZ_ASSERT(sock); MOZ_ASSERT(address); @@ -203,10 +270,16 @@ class TestNrSocketTest : public ::testing::Test { const_cast(&to)); } + int SendDataTcp_s(NrSocketBase *from) { + // It is up to caller to ensure that |from| is writeable. + const char buf[] = "foobajooba"; + size_t written; + return from->write(buf, sizeof(buf), &written); + } + int RecvData_s(TestNrSocket *to, nr_transport_addr *from) { // It is up to caller to ensure that |to| is readable - const size_t bufSize = 1024; - char buf[bufSize]; + char buf[DATA_BUF_SIZE]; size_t len; // Maybe check that data matches? int r = to->recvfrom(buf, sizeof(buf), &len, 0, from); @@ -216,6 +289,100 @@ class TestNrSocketTest : public ::testing::Test { return r; } + int RecvDataTcp_s(NrSocketBase *to) { + // It is up to caller to ensure that |to| is readable + char buf[DATA_BUF_SIZE]; + size_t len; + // Maybe check that data matches? + int r = to->read(buf, sizeof(buf), &len); + if (!r && (len == 0)) { + r = R_INTERNAL; + } + return r; + } + + int Listen_s(TestNrSocket *to) { + // listen on |to| + int r = to->listen(1); + if (r) { + return r; + } + return 0; + } + + int Connect_s(TestNrSocket *from, TestNrSocket *to) { + // connect on |from| + nr_transport_addr destination_address; + int r = to->getaddr(&destination_address); + if (r) { + return r; + } + + r = from->connect(&destination_address); + if (r) { + return r; + } + + return 0; + } + + int Accept_s(TestNrSocket *to, NrSocketBase **accepted_sock) { + nr_socket *sock; + nr_transport_addr source_address; + int r = to->accept(&source_address, &sock); + if (r) { + return r; + } + + *accepted_sock = reinterpret_cast(sock->obj); + return 0; + } + + bool Connect(TestNrSocket *from, + TestNrSocket *to, + NrSocketBase **accepted_sock) { + int r; + sts_->Dispatch(WrapRunnableRet(&r, + this, + &TestNrSocketTest::Listen_s, + to), + NS_DISPATCH_SYNC); + if (r) { + std::cerr << "Listen_s failed: " << r << std::endl; + return false; + } + + sts_->Dispatch(WrapRunnableRet(&r, + this, + &TestNrSocketTest::Connect_s, + from, + to), + NS_DISPATCH_SYNC); + if (r && r != R_WOULDBLOCK) { + std::cerr << "Connect_s failed: " << r << std::endl; + return false; + } + + if (!WaitForReadable(to)) { + std::cerr << "WaitForReadable failed" << std::endl; + return false; + } + + sts_->Dispatch(WrapRunnableRet(&r, + this, + &TestNrSocketTest::Accept_s, + to, + accepted_sock), + NS_DISPATCH_SYNC); + + if (r) { + std::cerr << "Accept_s failed: " << r << std::endl; + return false; + } + return true; + } + + bool WaitForSocketState(TestNrSocket *sock, int state) { MOZ_ASSERT(sock); sts_->Dispatch(WrapRunnable(this, @@ -225,7 +392,7 @@ class TestNrSocketTest : public ::testing::Test { NS_DISPATCH_SYNC); bool res; - WAIT_(wait_done_for_main_, 100, res); + WAIT_(wait_done_for_main_, 500, res); wait_done_for_main_ = false; if (!res) { @@ -641,8 +808,52 @@ TEST_F(TestNrSocketTest, FullConeTimeout) { sender_external_address)); } -// TODO(): We need TCP tests, but first we will need ICE TCP to land (this -// adds listen/accept support to NrSocket) +TEST_F(TestNrSocketTest, PublicConnectivityTcp) +{ + CreatePublicAddrs(2, "127.0.0.1", IPPROTO_TCP); + + ASSERT_TRUE(CheckTcpConnectivity(public_addrs_[0], public_addrs_[1])); +} + +TEST_F(TestNrSocketTest, PrivateConnectivityTcp) { + RefPtr nat(CreatePrivateAddrs(2, "127.0.0.1", IPPROTO_TCP)); + nat->filtering_type_ = TestNat::ENDPOINT_INDEPENDENT; + nat->mapping_type_ = TestNat::ENDPOINT_INDEPENDENT; + + ASSERT_TRUE(CheckTcpConnectivity(private_addrs_[0], private_addrs_[1])); +} + +TEST_F(TestNrSocketTest, PrivateToPublicConnectivityTcp) +{ + RefPtr nat(CreatePrivateAddrs(1, "127.0.0.1", IPPROTO_TCP)); + nat->filtering_type_ = TestNat::ENDPOINT_INDEPENDENT; + nat->mapping_type_ = TestNat::ENDPOINT_INDEPENDENT; + CreatePublicAddrs(1, "127.0.0.1", IPPROTO_TCP); + + ASSERT_TRUE(CheckTcpConnectivity(private_addrs_[0], public_addrs_[0])); +} + +TEST_F(TestNrSocketTest, NoConnectivityBetweenSubnetsTcp) +{ + RefPtr nat1(CreatePrivateAddrs(1, "127.0.0.1", IPPROTO_TCP)); + nat1->filtering_type_ = TestNat::ENDPOINT_INDEPENDENT; + nat1->mapping_type_ = TestNat::ENDPOINT_INDEPENDENT; + RefPtr nat2(CreatePrivateAddrs(1, "127.0.0.1", IPPROTO_TCP)); + nat2->filtering_type_ = TestNat::ENDPOINT_INDEPENDENT; + nat2->mapping_type_ = TestNat::ENDPOINT_INDEPENDENT; + + ASSERT_FALSE(CheckTcpConnectivity(private_addrs_[0], private_addrs_[1])); +} + +TEST_F(TestNrSocketTest, NoConnectivityPublicToPrivateTcp) +{ + RefPtr nat(CreatePrivateAddrs(1, "127.0.0.1", IPPROTO_TCP)); + nat->filtering_type_ = TestNat::ENDPOINT_INDEPENDENT; + nat->mapping_type_ = TestNat::ENDPOINT_INDEPENDENT; + CreatePublicAddrs(1, "127.0.0.1", IPPROTO_TCP); + + ASSERT_FALSE(CheckTcpConnectivity(public_addrs_[0], private_addrs_[0])); +} int main(int argc, char **argv) { diff --git a/media/mtransport/test_nr_socket.cpp b/media/mtransport/test_nr_socket.cpp index adbf1f4f6c..5dbffad1c9 100644 --- a/media/mtransport/test_nr_socket.cpp +++ b/media/mtransport/test_nr_socket.cpp @@ -137,6 +137,21 @@ static nr_socket_factory_vtbl test_nat_socket_factory_vtbl = { test_nat_socket_factory_destroy }; +/* static */ +TestNat::NatBehavior +TestNat::ToNatBehavior(const std::string& type) { + if (!type.compare("ENDPOINT_INDEPENDENT")) { + return TestNat::ENDPOINT_INDEPENDENT; + } else if (!type.compare("ADDRESS_DEPENDENT")) { + return TestNat::ADDRESS_DEPENDENT; + } else if (!type.compare("PORT_DEPENDENT")) { + return TestNat::PORT_DEPENDENT; + } + + MOZ_ASSERT(false, "Invalid NAT behavior"); + return TestNat::ENDPOINT_INDEPENDENT; +} + bool TestNat::has_port_mappings() const { for (TestNrSocket *sock : sockets_) { if (sock->has_port_mappings()) { @@ -192,7 +207,7 @@ TestNrSocket::~TestNrSocket() { nat_->erase_socket(this); } -RefPtr TestNrSocket::create_external_socket( +RefPtr TestNrSocket::create_external_socket( const nr_transport_addr &dest_addr) const { MOZ_ASSERT(nat_->enabled_); MOZ_ASSERT(!nat_->is_an_internal_tuple(dest_addr)); @@ -202,8 +217,9 @@ RefPtr TestNrSocket::create_external_socket( // Open the socket on an arbitrary port, on the same address. // TODO(bug 1170299): Remove const_cast when no longer necessary - if ((r = nr_transport_addr_copy(&nat_external_addr, - const_cast(&my_addr_)))) { + if ((r = nr_transport_addr_copy( + &nat_external_addr, + const_cast(&internal_socket_->my_addr())))) { r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in nr_transport_addr_copy: %d", __FUNCTION__, r); return nullptr; @@ -215,9 +231,10 @@ RefPtr TestNrSocket::create_external_socket( return nullptr; } - RefPtr external_socket = new NrSocket; + RefPtr external_socket; + r = NrSocketBase::CreateSocket(&nat_external_addr, &external_socket); - if ((r = external_socket->create(&nat_external_addr))) { + if (r) { r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in NrSocket::create: %d", __FUNCTION__, r); return nullptr; @@ -226,13 +243,49 @@ RefPtr TestNrSocket::create_external_socket( return external_socket; } +int TestNrSocket::create(nr_transport_addr *addr) { + return NrSocketBase::CreateSocket(addr, &internal_socket_); +} + +int TestNrSocket::getaddr(nr_transport_addr *addrp) { + return internal_socket_->getaddr(addrp); +} + +void TestNrSocket::close() { + // TODO: close port mappings too? + internal_socket_->close(); +} + +int TestNrSocket::listen(int backlog) { + MOZ_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP); + r_log(LOG_GENERIC, LOG_DEBUG, + "TestNrSocket %s listening", + internal_socket_->my_addr().as_string); + + return internal_socket_->listen(backlog); +} + +int TestNrSocket::accept(nr_transport_addr *addrp, nr_socket **sockp) { + MOZ_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP); + int r = internal_socket_->accept(addrp, sockp); + if (r) { + return r; + } + + if (nat_->enabled_ && !nat_->is_an_internal_tuple(*addrp)) { + nr_socket_destroy(sockp); + return R_IO_ERROR; + } + + return 0; +} + int TestNrSocket::sendto(const void *msg, size_t len, int flags, nr_transport_addr *to) { - MOZ_ASSERT(my_addr_.protocol != IPPROTO_TCP); - ASSERT_ON_THREAD(ststhread_); + MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP); if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) { - return NrSocket::sendto(msg, len, flags, to); + return internal_socket_->sendto(msg, len, flags, to); } destroy_stale_port_mappings(); @@ -251,7 +304,7 @@ int TestNrSocket::sendto(const void *msg, size_t len, // See if we have already made the external socket we need to use. PortMapping *similar_port_mapping = get_port_mapping(*to, nat_->mapping_type_); - RefPtr external_socket; + RefPtr external_socket; if (similar_port_mapping) { external_socket = similar_port_mapping->external_socket_; @@ -270,7 +323,7 @@ int TestNrSocket::sendto(const void *msg, size_t len, // Make sure the new port mapping is ready to receive traffic if the // TestNrSocket is already waiting. port_mapping->async_wait(NR_ASYNC_WAIT_READ, - port_mapping_readable_callback, + socket_readable_callback, this, (char*)__FUNCTION__, __LINE__); @@ -285,8 +338,7 @@ int TestNrSocket::sendto(const void *msg, size_t len, int TestNrSocket::recvfrom(void *buf, size_t maxlen, size_t *len, int flags, nr_transport_addr *from) { - MOZ_ASSERT(my_addr_.protocol != IPPROTO_TCP); - ASSERT_ON_THREAD(ststhread_); + MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP); int r; bool ingress_allowed = false; @@ -306,7 +358,7 @@ int TestNrSocket::recvfrom(void *buf, size_t maxlen, // If no external socket has data, see if there's any data that was sent // directly to the TestNrSocket, and eat it if it isn't supposed to get // through. - r = NrSocket::recvfrom(buf, maxlen, len, flags, from); + r = internal_socket_->recvfrom(buf, maxlen, len, flags, from); if (!r) { // We do not use allow_ingress() here because that only handles traffic // landing on an external port. @@ -315,7 +367,7 @@ int TestNrSocket::recvfrom(void *buf, size_t maxlen, if (!ingress_allowed) { r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: " "Not behind the same NAT", - my_addr_.as_string, + internal_socket_->my_addr().as_string, from->as_string); } } @@ -348,7 +400,7 @@ bool TestNrSocket::allow_ingress(const nr_transport_addr &from, if (!(*port_mapping_used)) { r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: " "Filtered", - my_addr_.as_string, + internal_socket_->my_addr().as_string, from.as_string); return false; } @@ -356,7 +408,7 @@ bool TestNrSocket::allow_ingress(const nr_transport_addr &from, if (is_port_mapping_stale(**port_mapping_used)) { r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: " "Stale port mapping", - my_addr_.as_string, + internal_socket_->my_addr().as_string, from.as_string); return false; } @@ -364,7 +416,7 @@ bool TestNrSocket::allow_ingress(const nr_transport_addr &from, if (!nat_->allow_hairpinning_ && nat_->is_my_external_tuple(from)) { r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: " "Hairpinning disallowed", - my_addr_.as_string, + internal_socket_->my_addr().as_string, from.as_string); return false; } @@ -373,7 +425,6 @@ bool TestNrSocket::allow_ingress(const nr_transport_addr &from, } int TestNrSocket::connect(nr_transport_addr *addr) { - ASSERT_ON_THREAD(ststhread_); if (connect_invoked_ || !port_mappings_.empty()) { MOZ_CRASH("TestNrSocket::connect() called more than once!"); @@ -386,17 +437,21 @@ int TestNrSocket::connect(nr_transport_addr *addr) { // we don't normally connect on UDP. || nat_->is_an_internal_tuple(*addr)) { // This will set connect_invoked_ - return NrSocket::connect(addr); + return internal_socket_->connect(addr); } - RefPtr external_socket(create_external_socket(*addr)); + RefPtr external_socket(create_external_socket(*addr)); if (!external_socket) { return R_INTERNAL; } PortMapping *port_mapping = create_port_mapping(*addr, external_socket); port_mappings_.push_back(port_mapping); - port_mapping->external_socket_->connect(addr); + int r = port_mapping->external_socket_->connect(addr); + if (r && r != R_WOULDBLOCK) { + return r; + } + port_mapping->last_used_ = PR_IntervalNow(); if (poll_flags() & PR_POLL_READ) { @@ -407,19 +462,22 @@ int TestNrSocket::connect(nr_transport_addr *addr) { __LINE__); } - return 0; + return r; } int TestNrSocket::write(const void *msg, size_t len, size_t *written) { - ASSERT_ON_THREAD(ststhread_); if (port_mappings_.empty()) { // The no-nat case, just pass call through. r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s writing", my_addr().as_string); - return NrSocket::write(msg, len, written); + return internal_socket_->write(msg, len, written); } else { + destroy_stale_port_mappings(); + if (port_mappings_.empty()) { + return -1; + } // This is TCP only MOZ_ASSERT(port_mappings_.size() == 1); r_log(LOG_GENERIC, LOG_INFO, @@ -432,10 +490,9 @@ int TestNrSocket::write(const void *msg, size_t len, size_t *written) { } int TestNrSocket::read(void *buf, size_t maxlen, size_t *len) { - ASSERT_ON_THREAD(ststhread_); if (port_mappings_.empty()) { - return NrSocket::read(buf, maxlen, len); + return internal_socket_->read(buf, maxlen, len); } else { MOZ_ASSERT(port_mappings_.size() == 1); return port_mappings_.front()->external_socket_->read(buf, maxlen, len); @@ -444,25 +501,45 @@ int TestNrSocket::read(void *buf, size_t maxlen, size_t *len) { int TestNrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg, char *function, int line) { - ASSERT_ON_THREAD(ststhread_); + r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s waiting for %s", + internal_socket_->my_addr().as_string, + how == NR_ASYNC_WAIT_READ ? "read" : "write"); - // Make sure we're waiting on the socket for the internal address - int r = NrSocket::async_wait(how, cb, cb_arg, function, line); + int r; - if (r) { - return r; + if (how == NR_ASYNC_WAIT_READ) { + NrSocketBase::async_wait(how, cb, cb_arg, function, line); + + // Make sure we're waiting on the socket for the internal address + r = internal_socket_->async_wait(how, + socket_readable_callback, + this, + function, + line); + } else { + // For write, just use the readiness of the internal socket, since we queue + // everything for the port mappings. + r = internal_socket_->async_wait(how, + cb, + cb_arg, + function, + line); } - r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s waiting for %s", - my_addr_.as_string, - how == NR_ASYNC_WAIT_READ ? "read" : "write"); + if (r) { + r_log(LOG_GENERIC, LOG_ERR, "TestNrSocket %s failed to async_wait for " + "internal socket: %d\n", + internal_socket_->my_addr().as_string, + r); + return r; + } if (is_tcp_connection_behind_nat()) { // Bypass all port-mapping related logic return 0; } - if (my_addr_.protocol == IPPROTO_TCP) { + if (internal_socket_->my_addr().protocol == IPPROTO_TCP) { // For a TCP connection through a simulated NAT, these signals are // just passed through. MOZ_ASSERT(port_mappings_.size() == 1); @@ -478,11 +555,15 @@ int TestNrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg, for (PortMapping *port_mapping : port_mappings_) { // Be ready to receive traffic on our port mappings r = port_mapping->async_wait(how, - port_mapping_readable_callback, + socket_readable_callback, this, function, line); if (r) { + r_log(LOG_GENERIC, LOG_ERR, "TestNrSocket %s failed to async_wait for " + "port mapping: %d\n", + internal_socket_->my_addr().as_string, + r); return r; } } @@ -498,18 +579,18 @@ void TestNrSocket::cancel_port_mapping_async_wait(int how) { } int TestNrSocket::cancel(int how) { - ASSERT_ON_THREAD(ststhread_); r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s stop waiting for %s", - my_addr_.as_string, + internal_socket_->my_addr().as_string, how == NR_ASYNC_WAIT_READ ? "read" : "write"); // Writable callbacks are decoupled except for the TCP case - if (how == NR_ASYNC_WAIT_READ || my_addr_.protocol == IPPROTO_TCP) { + if (how == NR_ASYNC_WAIT_READ || + internal_socket_->my_addr().protocol == IPPROTO_TCP) { cancel_port_mapping_async_wait(how); } - return NrSocket::cancel(how); + return internal_socket_->cancel(how); } bool TestNrSocket::has_port_mappings() const { @@ -548,7 +629,7 @@ void TestNrSocket::destroy_stale_port_mappings() { if (is_port_mapping_stale(**temp)) { r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s destroying port mapping %s -> %s", - my_addr_.as_string, + internal_socket_->my_addr().as_string, (*temp)->external_socket_->my_addr().as_string, (*temp)->remote_address_.as_string); @@ -557,34 +638,31 @@ void TestNrSocket::destroy_stale_port_mappings() { } } -void TestNrSocket::port_mapping_readable_callback(void *ext_sock_v, - int how, - void *test_sock_v) { +void TestNrSocket::socket_readable_callback(void *real_sock_v, + int how, + void *test_sock_v) { TestNrSocket *test_socket = static_cast(test_sock_v); - NrSocket *external_socket = static_cast(ext_sock_v); + NrSocket *real_socket = static_cast(real_sock_v); - test_socket->on_port_mapping_readable(external_socket); + test_socket->on_socket_readable(real_socket); } -void TestNrSocket::on_port_mapping_readable(NrSocket *external_socket) { - if (!readable_socket_) { - readable_socket_ = external_socket; +void TestNrSocket::on_socket_readable(NrSocketBase *real_socket) { + if (!readable_socket_ && (real_socket != internal_socket_)) { + readable_socket_ = real_socket; } - // None of our port mappings should be waiting for readable callbacks - // if nobody is waiting for readable callbacks from us. - MOZ_ASSERT(poll_flags() & PR_POLL_READ); - fire_readable_callback(); } void TestNrSocket::fire_readable_callback() { MOZ_ASSERT(poll_flags() & PR_POLL_READ); - // Stop listening on all mapped sockets; we will start listening again + // Stop listening on all real sockets; we will start listening again // if the app starts listening to us again. cancel_port_mapping_async_wait(NR_ASYNC_WAIT_READ); + internal_socket_->cancel(NR_ASYNC_WAIT_READ); r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s ready for read", - my_addr_.as_string); + internal_socket_->my_addr().as_string); fire_callback(NR_ASYNC_WAIT_READ); } @@ -592,13 +670,13 @@ void TestNrSocket::port_mapping_writeable_callback(void *ext_sock_v, int how, void *test_sock_v) { TestNrSocket *test_socket = static_cast(test_sock_v); - NrSocket *external_socket = static_cast(ext_sock_v); + NrSocketBase *external_socket = static_cast(ext_sock_v); test_socket->write_to_port_mapping(external_socket); } -void TestNrSocket::write_to_port_mapping(NrSocket *external_socket) { - MOZ_ASSERT(my_addr_.protocol != IPPROTO_TCP); +void TestNrSocket::write_to_port_mapping(NrSocketBase *external_socket) { + MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP); int r = 0; for (PortMapping *port_mapping : port_mappings_) { @@ -626,15 +704,16 @@ void TestNrSocket::port_mapping_tcp_passthrough_callback(void *ext_sock_v, TestNrSocket *test_socket = static_cast(test_sock_v); r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s firing %s callback", - test_socket->my_addr().as_string, + test_socket->internal_socket_->my_addr().as_string, how == NR_ASYNC_WAIT_READ ? "readable" : "writeable"); - test_socket->fire_callback(how); + test_socket->internal_socket_->fire_callback(how); } bool TestNrSocket::is_tcp_connection_behind_nat() const { - return my_addr_.protocol == IPPROTO_TCP && port_mappings_.empty(); + return internal_socket_->my_addr().protocol == IPPROTO_TCP && + port_mappings_.empty(); } TestNrSocket::PortMapping* TestNrSocket::get_port_mapping( @@ -665,9 +744,9 @@ TestNrSocket::PortMapping* TestNrSocket::get_port_mapping( TestNrSocket::PortMapping* TestNrSocket::create_port_mapping( const nr_transport_addr &remote_address, - const RefPtr &external_socket) const { + const RefPtr &external_socket) const { r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s creating port mapping %s -> %s", - my_addr_.as_string, + internal_socket_->my_addr().as_string, external_socket->my_addr().as_string, remote_address.as_string); @@ -676,7 +755,7 @@ TestNrSocket::PortMapping* TestNrSocket::create_port_mapping( TestNrSocket::PortMapping::PortMapping( const nr_transport_addr &remote_address, - const RefPtr &external_socket) : + const RefPtr &external_socket) : external_socket_(external_socket) { // TODO(bug 1170299): Remove const_cast when no longer necessary nr_transport_addr_copy(&remote_address_, diff --git a/media/mtransport/test_nr_socket.h b/media/mtransport/test_nr_socket.h index 48818a4bd7..c975812b70 100644 --- a/media/mtransport/test_nr_socket.h +++ b/media/mtransport/test_nr_socket.h @@ -83,6 +83,10 @@ nrappkit copyright: #ifndef test_nr_socket__ #define test_nr_socket__ +extern "C" { +#include "transport_addr.h" +} + #include "nr_socket_prsock.h" extern "C" { @@ -93,6 +97,7 @@ extern "C" { #include #include #include +#include #include "mozilla/UniquePtr.h" #include "prinrval.h" @@ -152,6 +157,8 @@ class TestNat { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNat); + static NatBehavior ToNatBehavior(const std::string& type); + bool enabled_; TestNat::NatBehavior filtering_type_; TestNat::NatBehavior mapping_type_; @@ -167,34 +174,45 @@ class TestNat { }; /** - * Subclass of NrSocket that can simulate things like being behind a NAT, packet - * loss, latency, packet rewriting, etc. Also exposes some stuff that assists in - * diagnostics. + * Subclass of NrSocketBase that can simulate things like being behind a NAT, + * packet loss, latency, packet rewriting, etc. Also exposes some stuff that + * assists in diagnostics. + * This is accomplished by wrapping an "internal" socket (that handles traffic + * behind the NAT), and a collection of "external" sockets (that handle traffic + * into/out of the NAT) */ -class TestNrSocket : public NrSocket { +class TestNrSocket : public NrSocketBase { public: explicit TestNrSocket(TestNat *nat); - virtual ~TestNrSocket(); - bool has_port_mappings() const; bool is_my_external_tuple(const nr_transport_addr &addr) const; - // Overrides of NrSocket + // Overrides of NrSocketBase + int create(nr_transport_addr *addr) override; int sendto(const void *msg, size_t len, int flags, nr_transport_addr *to) override; int recvfrom(void * buf, size_t maxlen, size_t *len, int flags, nr_transport_addr *from) override; + int getaddr(nr_transport_addr *addrp) override; + void close() override; int connect(nr_transport_addr *addr) override; int write(const void *msg, size_t len, size_t *written) override; int read(void *buf, size_t maxlen, size_t *len) override; + int listen(int backlog) override; + int accept(nr_transport_addr *addrp, nr_socket **sockp) override; int async_wait(int how, NR_async_cb cb, void *cb_arg, char *function, int line) override; int cancel(int how) override; + // Need override since this is virtual in NrSocketBase + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNrSocket, override) + private: + virtual ~TestNrSocket(); + class UdpPacket { public: UdpPacket(const void *msg, size_t len, const nr_transport_addr &addr) : @@ -215,7 +233,7 @@ class TestNrSocket : public NrSocket { class PortMapping { public: PortMapping(const nr_transport_addr &remote_address, - const RefPtr &external_socket); + const RefPtr &external_socket); int sendto(const void *msg, size_t len, const nr_transport_addr &to); int async_wait(int how, NR_async_cb cb, void *cb_arg, @@ -225,7 +243,7 @@ class TestNrSocket : public NrSocket { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PortMapping); PRIntervalTime last_used_; - RefPtr external_socket_; + RefPtr external_socket_; // For non-symmetric, most of the data here doesn't matter nr_transport_addr remote_address_; @@ -243,10 +261,10 @@ class TestNrSocket : public NrSocket { PortMapping **port_mapping_used) const; void destroy_stale_port_mappings(); - static void port_mapping_readable_callback(void *ext_sock_v, - int how, - void *test_sock_v); - void on_port_mapping_readable(NrSocket *external_socket); + static void socket_readable_callback(void *real_sock_v, + int how, + void *test_sock_v); + void on_socket_readable(NrSocketBase *external_or_internal_socket); void fire_readable_callback(); static void port_mapping_tcp_passthrough_callback(void *ext_sock_v, @@ -257,18 +275,21 @@ class TestNrSocket : public NrSocket { static void port_mapping_writeable_callback(void *ext_sock_v, int how, void *test_sock_v); - void write_to_port_mapping(NrSocket *external_socket); + void write_to_port_mapping(NrSocketBase *external_socket); bool is_tcp_connection_behind_nat() const; PortMapping* get_port_mapping(const nr_transport_addr &remote_addr, TestNat::NatBehavior filter) const; PortMapping* create_port_mapping( const nr_transport_addr &remote_addr, - const RefPtr &external_socket) const; - RefPtr create_external_socket( + const RefPtr &external_socket) const; + RefPtr create_external_socket( const nr_transport_addr &remote_addr) const; - RefPtr readable_socket_; + RefPtr readable_socket_; + // The socket for the "internal" address; used to talk to stuff behind the + // same nat. + RefPtr internal_socket_; RefPtr nat_; // Since our comparison logic is different depending on what kind of NAT // we simulate, and the STL does not make it very easy to switch out the diff --git a/media/mtransport/third_party/nICEr/src/ice/ice_component.c b/media/mtransport/third_party/nICEr/src/ice/ice_component.c index 2f80596870..9601fc259b 100644 --- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c +++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c @@ -490,6 +490,14 @@ static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_compon if (ctx->turn_servers[j].turn_server.transport != IPPROTO_TCP) continue; + if (ctx->turn_servers[j].turn_server.type == NR_ICE_STUN_SERVER_TYPE_ADDR && + nr_transport_addr_cmp(&ctx->turn_servers[j].turn_server.u.addr, + &addrs[i].addr, + NR_TRANSPORT_ADDR_CMP_MODE_VERSION)) { + r_log(LOG_ICE,LOG_INFO,"ICE(%s): Skipping TURN server because of IP version mis-match (%u - %u)",ctx->label,addrs[i].addr.ip_version,ctx->turn_servers[j].turn_server.u.addr.ip_version); + continue; + } + if (!ice_tcp_disabled) { /* Use TURN server to get srflx candidates */ if(r=nr_ice_candidate_create(ctx,component, diff --git a/media/mtransport/third_party/nICEr/src/ice/ice_socket.c b/media/mtransport/third_party/nICEr/src/ice/ice_socket.c index a52280c55b..f693d253fa 100644 --- a/media/mtransport/third_party/nICEr/src/ice/ice_socket.c +++ b/media/mtransport/third_party/nICEr/src/ice/ice_socket.c @@ -61,14 +61,15 @@ static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg) r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label); /* Re-arm first! */ - if (sock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP) + if (sock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP) { + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): rearming",sock->ctx->label); NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg); + } if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){ - if (r != R_WOULDBLOCK && (sock->type == NR_ICE_SOCKET_TYPE_STREAM_TURN)) { + if (r != R_WOULDBLOCK && (sock->type != NR_ICE_SOCKET_TYPE_DGRAM)) { /* Report this error upward. Bug 946423 */ - r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error %d on reliable socket. Abandoning.",sock->ctx->label, r); - NR_ASYNC_CANCEL(s, NR_ASYNC_WAIT_READ); + r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error %d on reliable socket(%p). Abandoning.",sock->ctx->label, r, s); } return; } diff --git a/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c b/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c index 5d9fc07131..c18da15f75 100644 --- a/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c +++ b/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c @@ -47,13 +47,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #define END_HEADERS CRLF CRLF +typedef enum { + PROXY_TUNNEL_NONE=0, + PROXY_TUNNEL_REQUESTED, + PROXY_TUNNEL_CONNECTED, + PROXY_TUNNEL_CLOSED, + PROXY_TUNNEL_FAILED +} nr_socket_proxy_tunnel_state; + typedef struct nr_socket_proxy_tunnel_ { nr_proxy_tunnel_config *config; nr_socket *inner; nr_transport_addr remote_addr; - int connect_requested; - int connect_answered; - int connect_failed; + nr_socket_proxy_tunnel_state state; char buffer[MAX_HTTP_CONNECT_BUFFER_SIZE]; size_t buffered_bytes; void *resolver_handle; @@ -143,7 +149,7 @@ static int send_http_connect(nr_socket_proxy_tunnel *sock) ABORT(R_IO_ERROR); } - sock->connect_requested = 1; + sock->state = PROXY_TUNNEL_REQUESTED; _status = 0; abort: @@ -173,6 +179,9 @@ static int parse_http_response(char *begin, char *end, unsigned int *status) // len should *never* be greater than nr_socket_proxy_tunnel::buffered_bytes. // Which in turn should never be greater nr_socket_proxy_tunnel::buffer size. assert(len <= MAX_HTTP_CONNECT_BUFFER_SIZE); + if (len > MAX_HTTP_CONNECT_BUFFER_SIZE) { + return R_BAD_DATA; + } memcpy(response, begin, len); response[len] = '\0'; @@ -249,6 +258,10 @@ static int nr_socket_proxy_tunnel_resolved_cb(void *obj, nr_transport_addr *prox else { r_log(LOG_GENERIC,LOG_WARNING,"Failed to resolve proxy %s", sock->config->proxy_host); + /* TODO: Mozilla bug 1241758: because of the callback the return value goes + * nowhere, so we can't mark the candidate as failed, so everything depends + * on the overall timeouts in this case. */ + sock->state = PROXY_TUNNEL_FAILED; ABORT(R_NOT_FOUND); } @@ -320,13 +333,20 @@ int nr_socket_proxy_tunnel_write(void *obj, const void *msg, size_t len, r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_write"); - if (!sock->connect_requested) { + if (sock->state >= PROXY_TUNNEL_CLOSED) { + return R_FAILED; + } + + if (sock->state == PROXY_TUNNEL_NONE) { if ((r=send_http_connect(sock))) { ABORT(r); } } - /* TODO (bug 1117984): we cannot assume it's safe to write until we receive a response. */ + if (sock->state != PROXY_TUNNEL_CONNECTED) { + return R_WOULDBLOCK; + } + if ((r=nr_socket_write(sock->inner, msg, len, written, 0))) { ABORT(r); } @@ -350,11 +370,11 @@ int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen, *len = 0; - if (sock->connect_failed) { + if (sock->state >= PROXY_TUNNEL_CLOSED) { return R_FAILED; } - if (sock->connect_answered) { + if (sock->state == PROXY_TUNNEL_CONNECTED) { return nr_socket_read(sock->inner, buf, maxlen, len, 0); } @@ -375,8 +395,6 @@ int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen, sock->buffered_bytes += bytes_read; if (http_term = find_http_terminator(sock->buffer, sock->buffered_bytes)) { - sock->connect_answered = 1; - if ((r = parse_http_response(sock->buffer, http_term, &http_status))) { ABORT(r); } @@ -388,6 +406,8 @@ int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen, ABORT(R_FAILED); } + sock->state = PROXY_TUNNEL_CONNECTED; + ptr = http_term + strlen(END_HEADERS); pending = sock->buffered_bytes - (ptr - sock->buffer); @@ -404,7 +424,7 @@ int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen, _status=0; abort: if (_status && _status != R_WOULDBLOCK) { - sock->connect_failed = 1; + sock->state = PROXY_TUNNEL_FAILED; } return(_status); } @@ -420,6 +440,8 @@ int nr_socket_proxy_tunnel_close(void *obj) sock->resolver_handle = 0; } + sock->state = PROXY_TUNNEL_CLOSED; + return nr_socket_close(sock->inner); } diff --git a/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c b/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c index 89effe9e32..926460d02e 100644 --- a/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c +++ b/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c @@ -250,7 +250,15 @@ abort: static void nr_socket_buffered_stun_failed(nr_socket_buffered_stun *sock) { + NR_SOCKET fd; + sock->read_state = NR_ICE_SOCKET_READ_FAILED; + + /* Cancel waiting on the socket */ + if (sock->inner && !nr_socket_getfd(sock->inner, &fd)) { + NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE); + NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ); + } } static int nr_socket_buffered_stun_recvfrom(void *obj,void * restrict buf, @@ -524,6 +532,10 @@ static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg) int r,_status; nr_p_buf *n1, *n2; + if (sock->read_state == NR_ICE_SOCKET_READ_FAILED) { + ABORT(R_FAILED); + } + /* Try to flush */ STAILQ_FOREACH_SAFE(n1, &sock->pending_writes, entry, n2) { size_t written = 0; diff --git a/media/mtransport/transportlayer.cpp b/media/mtransport/transportlayer.cpp index 2b2772e340..5f05b1d5de 100644 --- a/media/mtransport/transportlayer.cpp +++ b/media/mtransport/transportlayer.cpp @@ -49,19 +49,4 @@ void TransportLayer::SetState(State state, const char *file, unsigned line) { } } -nsresult TransportLayer::RunOnThread(nsIRunnable *event) { - if (target_) { - nsIThread *thr; - - DebugOnly rv = NS_GetCurrentThread(&thr); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - - if (target_ != thr) { - return target_->Dispatch(event, NS_DISPATCH_SYNC); - } - } - - return event->Run(); -} - } // close namespace diff --git a/media/mtransport/transportlayer.h b/media/mtransport/transportlayer.h index 85afad7fd9..fb40904c31 100644 --- a/media/mtransport/transportlayer.h +++ b/media/mtransport/transportlayer.h @@ -57,10 +57,6 @@ class TransportLayer : public sigslot::has_slots<> { // Downward interface TransportLayer *downward() { return downward_; } - // Dispatch a call onto our thread (or run on the same thread if - // thread is not set). This is always synchronous. - nsresult RunOnThread(nsIRunnable *event); - // Get the state State state() const { return state_; } // Must be implemented by derived classes diff --git a/media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in b/media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in deleted file mode 100644 index d5219102fe..0000000000 --- a/media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -include $(topsrcdir)/config/rules.mk - -INCLUDES += \ - -I$(topsrcdir)/media/omx-plugin/include/ics \ - $(NULL) diff --git a/media/omx-plugin/lib/ics/libvideoeditorplayer/moz.build b/media/omx-plugin/lib/ics/libvideoeditorplayer/moz.build index 09a43e0588..5604db5e64 100644 --- a/media/omx-plugin/lib/ics/libvideoeditorplayer/moz.build +++ b/media/omx-plugin/lib/ics/libvideoeditorplayer/moz.build @@ -15,3 +15,7 @@ SharedLibrary('videoeditorplayer') # Don't use STL wrappers; this isn't Gecko code DISABLE_STL_WRAPPING = True NO_VISIBILITY_FLAGS = True + +LOCAL_INCLUDES += [ + '/media/omx-plugin/include/ics', +] diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5faabc8653..59ce2b7fcc 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -690,6 +690,7 @@ pref("gfx.color_management.enablev4", false); pref("gfx.downloadable_fonts.enabled", true); pref("gfx.downloadable_fonts.fallback_delay", 3000); +pref("gfx.downloadable_fonts.fallback_delay_short", 100); // disable downloadable font cache so that behavior is consistently // the uncached load behavior across pages (useful for testing reflow problems) diff --git a/toolkit/components/alerts/AlertNotification.cpp b/toolkit/components/alerts/AlertNotification.cpp index ef443f714a..b72e5746ad 100644 --- a/toolkit/components/alerts/AlertNotification.cpp +++ b/toolkit/components/alerts/AlertNotification.cpp @@ -117,6 +117,16 @@ AlertNotification::GetPrincipal(nsIPrincipal** aPrincipal) return NS_OK; } +NS_IMETHODIMP +AlertNotification::GetURI(nsIURI** aURI) +{ + if (!nsAlertsUtils::IsActionablePrincipal(mPrincipal)) { + *aURI = nullptr; + return NS_OK; + } + return mPrincipal->GetURI(aURI); +} + NS_IMETHODIMP AlertNotification::GetInPrivateBrowsing(bool* aInPrivateBrowsing) { diff --git a/toolkit/components/alerts/nsAlertsService.cpp b/toolkit/components/alerts/nsAlertsService.cpp index d6765770ec..25cc5a3fc4 100644 --- a/toolkit/components/alerts/nsAlertsService.cpp +++ b/toolkit/components/alerts/nsAlertsService.cpp @@ -22,10 +22,122 @@ #endif // !MOZ_WIDGET_ANDROID +#ifdef MOZ_PLACES +#include "mozIAsyncFavicons.h" +#include "nsIFaviconService.h" +#endif // MOZ_PLACES + using namespace mozilla; using mozilla::dom::ContentChild; +namespace { + +#ifdef MOZ_PLACES + +class IconCallback final : public nsIFaviconDataCallback +{ +public: + NS_DECL_ISUPPORTS + + IconCallback(nsIAlertsService* aBackend, + nsIAlertNotification* aAlert, + nsIObserver* aAlertListener) + : mBackend(aBackend) + , mAlert(aAlert) + , mAlertListener(aAlertListener) + {} + + NS_IMETHOD + OnComplete(nsIURI *aIconURI, uint32_t aIconSize, const uint8_t *aIconData, + const nsACString &aMimeType) override + { + nsresult rv = NS_ERROR_FAILURE; + if (aIconSize > 0) { + nsCOMPtr alertsIconData(do_QueryInterface(mBackend)); + if (alertsIconData) { + rv = alertsIconData->ShowAlertWithIconData(mAlert, mAlertListener, + aIconSize, aIconData); + } + } else if (aIconURI) { + nsCOMPtr alertsIconURI(do_QueryInterface(mBackend)); + if (alertsIconURI) { + rv = alertsIconURI->ShowAlertWithIconURI(mAlert, mAlertListener, + aIconURI); + } + } + if (NS_FAILED(rv)) { + rv = mBackend->ShowAlert(mAlert, mAlertListener); + } + return rv; + } + +private: + virtual ~IconCallback() {} + + nsCOMPtr mBackend; + nsCOMPtr mAlert; + nsCOMPtr mAlertListener; +}; + +NS_IMPL_ISUPPORTS(IconCallback, nsIFaviconDataCallback) + +#endif // MOZ_PLACES + +#ifndef MOZ_WIDGET_ANDROID + +nsresult +ShowWithIconBackend(nsIAlertsService* aBackend, nsIAlertNotification* aAlert, + nsIObserver* aAlertListener) +{ +#ifdef MOZ_PLACES + nsCOMPtr uri; + nsresult rv = aAlert->GetURI(getter_AddRefs(uri)); + if (NS_FAILED(rv) || !uri) { + return NS_ERROR_FAILURE; + } + + // Ensure the backend supports favicons. + nsCOMPtr alertsIconData(do_QueryInterface(aBackend)); + nsCOMPtr alertsIconURI; + if (!alertsIconData) { + alertsIconURI = do_QueryInterface(aBackend); + } + if (!alertsIconData && !alertsIconURI) { + return NS_ERROR_NOT_IMPLEMENTED; + } + + nsCOMPtr favicons(do_GetService( + "@mozilla.org/browser/favicon-service;1")); + NS_ENSURE_TRUE(favicons, NS_ERROR_FAILURE); + + nsCOMPtr callback = + new IconCallback(aBackend, aAlert, aAlertListener); + if (alertsIconData) { + return favicons->GetFaviconDataForPage(uri, callback); + } + return favicons->GetFaviconURLForPage(uri, callback); +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif // !MOZ_PLACES +} + +nsresult +ShowWithBackend(nsIAlertsService* aBackend, nsIAlertNotification* aAlert, + nsIObserver* aAlertListener) +{ + nsresult rv = ShowWithIconBackend(aBackend, aAlert, aAlertListener); + if (NS_SUCCEEDED(rv)) { + return rv; + } + // If the backend doesn't support favicons, show the alert without one. + return aBackend->ShowAlert(aAlert, aAlertListener); +} + +#endif // MOZ_WIDGET_ANDROID + +} // anonymous namespace + NS_IMPL_ISUPPORTS(nsAlertsService, nsIAlertsService, nsIAlertsDoNotDisturb, nsIAlertsProgressListener) nsAlertsService::nsAlertsService() : @@ -66,7 +178,7 @@ bool nsAlertsService::ShouldShowAlert() return result; } -NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl, const nsAString & aAlertTitle, +NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl, const nsAString & aAlertTitle, const nsAString & aAlertText, bool aAlertTextClickable, const nsAString & aAlertCookie, nsIObserver * aAlertListener, @@ -135,7 +247,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlert(nsIAlertNotification * aAlert, #else // Check if there is an optional service that handles system-level notifications if (mBackend) { - rv = mBackend->ShowAlert(aAlert, aAlertListener); + rv = ShowWithBackend(mBackend, aAlert, aAlertListener); if (NS_SUCCEEDED(rv)) { return rv; } @@ -154,7 +266,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlert(nsIAlertNotification * aAlert, // Use XUL notifications as a fallback if above methods have failed. nsCOMPtr xulBackend(nsXULAlerts::GetInstance()); NS_ENSURE_TRUE(xulBackend, NS_ERROR_FAILURE); - return xulBackend->ShowAlert(aAlert, aAlertListener); + return ShowWithBackend(xulBackend, aAlert, aAlertListener); #endif // !MOZ_WIDGET_ANDROID } diff --git a/toolkit/components/alerts/nsIAlertsService.idl b/toolkit/components/alerts/nsIAlertsService.idl index f11848f566..d34061ff21 100644 --- a/toolkit/components/alerts/nsIAlertsService.idl +++ b/toolkit/components/alerts/nsIAlertsService.idl @@ -7,12 +7,13 @@ #include "nsIObserver.idl" interface nsIPrincipal; +interface nsIURI; %{C++ #define ALERT_NOTIFICATION_CONTRACTID "@mozilla.org/alert-notification;1" %} -[scriptable, uuid(9e87fc34-8dbb-4b14-a724-b27be6822ec8)] +[scriptable, uuid(1650a064-79d5-4eb6-8c9e-57dd6522b6ac)] interface nsIAlertNotification : nsISupports { /** Initializes an alert notification. */ @@ -85,6 +86,12 @@ interface nsIAlertNotification : nsISupports */ readonly attribute nsIPrincipal principal; + /** + * The URI of the page that created the alert. |null| if the alert is not + * actionable. + */ + readonly attribute nsIURI URI; + /** * Controls the image loading behavior. If true, the image URL will be loaded * in private browsing mode. @@ -224,3 +231,30 @@ interface nsIAlertsProgressListener : nsISupports void onCancel(in AString name); }; +[scriptable, uuid(fc6d7f0a-0cf6-4268-8c71-ab640842b9b1)] +interface nsIAlertsIconData : nsISupports +{ + /** + * Shows an alert with an icon. Web notifications use the favicon of the + * page that created the alert. If the favicon is not in the Places database, + * |iconSize| will be zero. + */ + void showAlertWithIconData(in nsIAlertNotification alert, + [optional] in nsIObserver alertListener, + [optional] in uint32_t iconSize, + [const, array, size_is(iconSize)] in uint8_t + iconData); +}; + +[scriptable, uuid(f3c82915-bf60-41ea-91ce-6c46b22e381a)] +interface nsIAlertsIconURI : nsISupports +{ + /** + * Shows an alert with an icon URI. Web notifications use |moz-anno:| + * URIs to reference favicons from Places. If the page doesn't have a + * favicon, |iconURI| will be |null|. + */ + void showAlertWithIconURI(in nsIAlertNotification alert, + [optional] in nsIObserver alertListener, + [optional] in nsIURI iconURI); +}; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 7b39fd3ab6..77aac217f2 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -5936,11 +5936,38 @@ "description": "The time (in milliseconds) that it took a 'reconfigure thread' request to go round trip." }, "MEDIA_RUST_MP4PARSE_SUCCESS": { + "alert_emails": ["giles@mozilla.com", "kinetik@flim.org"], "expires_in_version": "50", "kind": "boolean", + "bug_numbers": [1220885], "description": "(Bug 1220885) Whether the rust mp4 demuxer successfully parsed a stream segment.", "cpp_guard": "MOZ_RUST_MP4PARSE" }, + "MEDIA_RUST_MP4PARSE_ERROR_CODE": { + "alert_emails": ["giles@mozilla.com", "kinetik@flim.org"], + "expires_in_version": "50", + "kind": "enumerated", + "n_values": 32, + "bug_numbers": [1238420], + "description": "The error code reported when an MP4 parse attempt has failed.", + "cpp_guard": "MOZ_RUST_MP4PARSE" + }, + "MEDIA_RUST_MP4PARSE_TRACK_MATCH_AUDIO": { + "alert_emails": ["giles@mozilla.com", "kinetik@flim.org"], + "expires_in_version": "50", + "kind": "boolean", + "bug_numbers": [1231169], + "description": "Whether rust and stagefight mp4 parser audio track results match.", + "cpp_guard": "MOZ_RUST_MP4PARSE" + }, + "MEDIA_RUST_MP4PARSE_TRACK_MATCH_VIDEO": { + "alert_emails": ["giles@mozilla.com", "kinetik@flim.org"], + "expires_in_version": "50", + "kind": "boolean", + "bug_numbers": [1231169], + "description": "Whether rust and stagefight mp4 parser video track results match.", + "cpp_guard": "MOZ_RUST_MP4PARSE" + }, "MEDIA_WMF_DECODE_ERROR": { "expires_in_version": "50", "kind": "enumerated", diff --git a/widget/cocoa/OSXNotificationCenter.h b/widget/cocoa/OSXNotificationCenter.h index 3ae5df5b44..f56ddd2762 100644 --- a/widget/cocoa/OSXNotificationCenter.h +++ b/widget/cocoa/OSXNotificationCenter.h @@ -25,13 +25,15 @@ class OSXNotificationInfo; class OSXNotificationCenter : public nsIAlertsService, public imgINotificationObserver, - public nsITimerCallback + public nsITimerCallback, + public nsIAlertsIconData { public: NS_DECL_ISUPPORTS NS_DECL_NSIALERTSSERVICE NS_DECL_IMGINOTIFICATIONOBSERVER NS_DECL_NSITIMERCALLBACK + NS_DECL_NSIALERTSICONDATA OSXNotificationCenter(); diff --git a/widget/cocoa/OSXNotificationCenter.mm b/widget/cocoa/OSXNotificationCenter.mm index 98d63685c8..07ea00a728 100644 --- a/widget/cocoa/OSXNotificationCenter.mm +++ b/widget/cocoa/OSXNotificationCenter.mm @@ -220,7 +220,8 @@ OSXNotificationCenter::~OSXNotificationCenter() NS_OBJC_END_TRY_ABORT_BLOCK; } -NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, imgINotificationObserver, nsITimerCallback) +NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsITimerCallback, + imgINotificationObserver, nsIAlertsIconData) nsresult OSXNotificationCenter::Init() { @@ -257,6 +258,15 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const NS_IMETHODIMP OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert, nsIObserver* aAlertListener) +{ + return ShowAlertWithIconData(aAlert, aAlertListener, 0, nullptr); +} + +NS_IMETHODIMP +OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert, + nsIObserver* aAlertListener, + uint32_t aIconSize, + const uint8_t* aIconData) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; @@ -353,6 +363,18 @@ OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert, OSXNotificationInfo *osxni = new OSXNotificationInfo(alertName, aAlertListener, cookie); + // Show the favicon if supported on this version of OS X. + if (aIconSize > 0 && + [notification respondsToSelector:@selector(set_identityImage:)] && + [notification respondsToSelector:@selector(set_identityImageHasBorder:)]) { + + NSData *iconData = [NSData dataWithBytes:aIconData length:aIconSize]; + NSImage *icon = [[[NSImage alloc] initWithData:iconData] autorelease]; + + [(NSObject*)notification setValue:icon forKey:@"_identityImage"]; + [(NSObject*)notification setValue:@(NO) forKey:@"_identityImageHasBorder"]; + } + nsAutoString imageUrl; rv = aAlert->GetImageURL(imageUrl); NS_ENSURE_SUCCESS(rv, rv); diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index d41c1eb36c..b22932941b 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -2973,14 +2973,13 @@ RectTextureImage::EndUpdate(bool aKeepSurface) { MOZ_ASSERT(mInUpdate, "Ending update while not in update"); - bool overwriteTexture = false; + bool needInit = !mTexture; LayoutDeviceIntRegion updateRegion = mUpdateRegion; - if (!mTexture || (mTextureSize != mBufferSize)) { - overwriteTexture = true; + if (mTextureSize != mBufferSize) { mTextureSize = mBufferSize; } - if (overwriteTexture || !CanUploadSubtextures()) { + if (needInit || !CanUploadSubtextures()) { updateRegion = LayoutDeviceIntRect(LayoutDeviceIntPoint(0, 0), mTextureSize); } @@ -2994,7 +2993,7 @@ RectTextureImage::EndUpdate(bool aKeepSurface) UploadImageDataToTexture(mGLContext, data, stride, format, updateRegion.ToUnknownRegion(), mTexture, nullptr, - overwriteTexture, /* aPixelBuffer = */ false, + needInit, /* aPixelBuffer = */ false, LOCAL_GL_TEXTURE0, LOCAL_GL_TEXTURE_RECTANGLE_ARB); diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index 3ef5ca4461..447c5f37be 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -48,6 +48,12 @@ typedef struct NSEdgeInsets { CGFloat right; } NSEdgeInsets; +#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +// Not in 10.4 or 10.5. +@protocol NSAnimationDelegate +@end +#endif // 10.5 or earlier + #endif typedef struct _nsCocoaWindowList { diff --git a/widget/cocoa/nsPrintDialogX.mm b/widget/cocoa/nsPrintDialogX.mm index caac596503..a4ba0d7651 100644 --- a/widget/cocoa/nsPrintDialogX.mm +++ b/widget/cocoa/nsPrintDialogX.mm @@ -78,6 +78,11 @@ nsPrintDialogServiceX::Show(nsIDOMWindow *aParent, nsIPrintSettings *aSettings, [NSPrintOperation setCurrentOperation:printOperation]; NSPrintPanel* panel = [NSPrintPanel printPanel]; + [panel setOptions:NSPrintPanelShowsCopies + | NSPrintPanelShowsPageRange + | NSPrintPanelShowsPaperSize + | NSPrintPanelShowsOrientation + | NSPrintPanelShowsScaling ]; PrintPanelAccessoryController* viewController = [[PrintPanelAccessoryController alloc] initWithSettings:aSettings]; [panel addAccessoryController:viewController]; diff --git a/xpcom/threads/nsIEventTarget.idl b/xpcom/threads/nsIEventTarget.idl index c3e4d3c329..db71ac7bf6 100644 --- a/xpcom/threads/nsIEventTarget.idl +++ b/xpcom/threads/nsIEventTarget.idl @@ -56,9 +56,7 @@ interface nsIEventTarget : nsISupports * * @param event * The alreadyAddRefed<> event to dispatch. - * NOTE that the event will be leaked if it fails to dispatch. Also note - * that if "flags" includes DISPATCH_SYNC, it may return error from Run() - * after a successful dispatch. In that case, the event is not leaked. + * NOTE that the event will be leaked if it fails to dispatch. * @param flags * The flags modifying event dispatch. The flags are described in detail * below. diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 3c5f410889..39301973c1 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -618,9 +618,7 @@ nsThread::DispatchInternal(already_AddRefed&& aEvent, uint32_t aFla while (wrapper->IsPending()) { NS_ProcessNextEvent(thread, true); } - // NOTE that, unlike the behavior above, the event is not leaked by - // this place, while it is possible that the result is an error. - return wrapper->Result(); + return NS_OK; } NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags"); diff --git a/xpcom/threads/nsThreadSyncDispatch.h b/xpcom/threads/nsThreadSyncDispatch.h index 4462a38101..5e010f6d40 100644 --- a/xpcom/threads/nsThreadSyncDispatch.h +++ b/xpcom/threads/nsThreadSyncDispatch.h @@ -9,6 +9,7 @@ #include "nsThreadUtils.h" #include "LeakRefPtr.h" +#include "mozilla/DebugOnly.h" class nsThreadSyncDispatch : public nsRunnable { @@ -16,7 +17,6 @@ public: nsThreadSyncDispatch(nsIThread* aOrigin, already_AddRefed&& aTask) : mOrigin(aOrigin) , mSyncTask(mozilla::Move(aTask)) - , mResult(NS_ERROR_NOT_INITIALIZED) { } @@ -25,16 +25,13 @@ public: return !!mSyncTask; } - nsresult Result() - { - return mResult; - } - private: NS_IMETHOD Run() override { if (nsIRunnable* task = mSyncTask.get()) { - mResult = task->Run(); + mozilla::DebugOnly result = task->Run(); + MOZ_ASSERT(NS_SUCCEEDED(result), + "task in sync dispatch should not fail"); // We must release the task here to ensure that when the original // thread is unblocked, this task has been released. mSyncTask.release(); @@ -48,7 +45,6 @@ private: // The task is leaked by default when Run() is not called, because // otherwise we may release it in an incorrect thread. mozilla::LeakRefPtr mSyncTask; - nsresult mResult; }; #endif // nsThreadSyncDispatch_h_